llviewermessage.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:176k
- /**
- * @file llviewermessage.cpp
- * @brief Dumping ground for viewer-side message system callbacks.
- *
- * $LicenseInfo:firstyear=2002&license=viewergpl$
- *
- * Copyright (c) 2002-2010, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
- #include "llviewerprecompiledheaders.h"
- #include "llviewermessage.h"
- #include "llanimationstates.h"
- #include "llaudioengine.h"
- #include "llavataractions.h"
- #include "lscript_byteformat.h"
- #include "lleconomy.h"
- #include "lleventtimer.h"
- #include "llfloaterreg.h"
- #include "llfollowcamparams.h"
- #include "llregionhandle.h"
- #include "llsdserialize.h"
- #include "llteleportflags.h"
- #include "lltransactionflags.h"
- #include "llvfile.h"
- #include "llvfs.h"
- #include "llxfermanager.h"
- #include "mean_collision_data.h"
- #include "llagent.h"
- #include "llcallingcard.h"
- //#include "llfirstuse.h"
- #include "llfloaterbuycurrency.h"
- #include "llfloaterbuyland.h"
- #include "llfloaterland.h"
- #include "llfloaterregioninfo.h"
- #include "llfloaterlandholdings.h"
- #include "llfloaterpostcard.h"
- #include "llfloaterpreference.h"
- #include "llhudeffecttrail.h"
- #include "llhudmanager.h"
- #include "llinventoryobserver.h"
- #include "llinventorypanel.h"
- #include "llnearbychat.h"
- #include "llnotifications.h"
- #include "llnotificationsutil.h"
- #include "llpanelgrouplandmoney.h"
- #include "llpanelplaces.h"
- #include "llrecentpeople.h"
- #include "llscriptfloater.h"
- #include "llselectmgr.h"
- #include "llsidetray.h"
- #include "llstartup.h"
- #include "llsky.h"
- #include "llslurl.h"
- #include "llstatenums.h"
- #include "llstatusbar.h"
- #include "llimview.h"
- #include "llspeakers.h"
- #include "lltrans.h"
- #include "llviewerfoldertype.h"
- #include "lluri.h"
- #include "llviewergenericmessage.h"
- #include "llviewermenu.h"
- #include "llviewerobjectlist.h"
- #include "llviewerparcelmgr.h"
- #include "llviewerstats.h"
- #include "llviewertexteditor.h"
- #include "llviewerthrottle.h"
- #include "llviewerwindow.h"
- #include "llvlmanager.h"
- #include "llvoavatarself.h"
- #include "llvotextbubble.h"
- #include "llworld.h"
- #include "pipeline.h"
- #include "llfloaterworldmap.h"
- #include "llviewerdisplay.h"
- #include "llkeythrottle.h"
- #include "llgroupactions.h"
- #include "llagentui.h"
- #include "llpanelblockedlist.h"
- #include "llpanelplaceprofile.h"
- #include <boost/algorithm/string/split.hpp> //
- #if LL_WINDOWS // For Windows specific error handler
- #include "llwindebug.h" // For the invalid message handler
- #endif
- #include "llnotificationmanager.h" //
- //
- // Constants
- //
- const F32 BIRD_AUDIBLE_RADIUS = 32.0f;
- const F32 SIT_DISTANCE_FROM_TARGET = 0.25f;
- static const F32 LOGOUT_REPLY_TIME = 3.f; // Wait this long after LogoutReply before quitting.
- // Determine how quickly residents' scripts can issue question dialogs
- // Allow bursts of up to 5 dialogs in 10 seconds. 10*2=20 seconds recovery if throttle kicks in
- static const U32 LLREQUEST_PERMISSION_THROTTLE_LIMIT = 5; // requests
- static const F32 LLREQUEST_PERMISSION_THROTTLE_INTERVAL = 10.0f; // seconds
- extern BOOL gDebugClicks;
- // function prototypes
- bool check_offer_throttle(const std::string& from_name, bool check_only);
- //inventory offer throttle globals
- LLFrameTimer gThrottleTimer;
- const U32 OFFER_THROTTLE_MAX_COUNT=5; //number of items per time period
- const F32 OFFER_THROTTLE_TIME=10.f; //time period in seconds
- //script permissions
- const std::string SCRIPT_QUESTIONS[SCRIPT_PERMISSION_EOF] =
- {
- "ScriptTakeMoney",
- "ActOnControlInputs",
- "RemapControlInputs",
- "AnimateYourAvatar",
- "AttachToYourAvatar",
- "ReleaseOwnership",
- "LinkAndDelink",
- "AddAndRemoveJoints",
- "ChangePermissions",
- "TrackYourCamera",
- "ControlYourCamera"
- };
- const BOOL SCRIPT_QUESTION_IS_CAUTION[SCRIPT_PERMISSION_EOF] =
- {
- TRUE, // ScriptTakeMoney,
- FALSE, // ActOnControlInputs
- FALSE, // RemapControlInputs
- FALSE, // AnimateYourAvatar
- FALSE, // AttachToYourAvatar
- FALSE, // ReleaseOwnership,
- FALSE, // LinkAndDelink,
- FALSE, // AddAndRemoveJoints
- FALSE, // ChangePermissions
- FALSE, // TrackYourCamera,
- FALSE // ControlYourCamera
- };
- bool friendship_offer_callback(const LLSD& notification, const LLSD& response)
- {
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- LLMessageSystem* msg = gMessageSystem;
- const LLSD& payload = notification["payload"];
- // add friend to recent people list
- LLRecentPeople::instance().add(payload["from_id"]);
- switch(option)
- {
- case 0:
- {
- // accept
- LLAvatarTracker::formFriendship(payload["from_id"]);
- const LLUUID fid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD);
- // This will also trigger an onlinenotification if the user is online
- msg->newMessageFast(_PREHASH_AcceptFriendship);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->nextBlockFast(_PREHASH_TransactionBlock);
- msg->addUUIDFast(_PREHASH_TransactionID, payload["session_id"]);
- msg->nextBlockFast(_PREHASH_FolderData);
- msg->addUUIDFast(_PREHASH_FolderID, fid);
- msg->sendReliable(LLHost(payload["sender"].asString()));
- break;
- }
- case 1: // Decline
- case 2: // Send IM - decline and start IM session
- {
- // decline
- // We no longer notify other viewers, but we DO still send
- // the rejection to the simulator to delete the pending userop.
- msg->newMessageFast(_PREHASH_DeclineFriendship);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->nextBlockFast(_PREHASH_TransactionBlock);
- msg->addUUIDFast(_PREHASH_TransactionID, payload["session_id"]);
- msg->sendReliable(LLHost(payload["sender"].asString()));
- // start IM session
- if(2 == option)
- {
- LLAvatarActions::startIM(payload["from_id"].asUUID());
- }
- }
- default:
- // close button probably, possibly timed out
- break;
- }
- return false;
- }
- static LLNotificationFunctorRegistration friendship_offer_callback_reg("OfferFriendship", friendship_offer_callback);
- static LLNotificationFunctorRegistration friendship_offer_callback_reg_nm("OfferFriendshipNoMessage", friendship_offer_callback);
- //const char BUSY_AUTO_RESPONSE[] = "The Resident you messaged is in 'busy mode' which means they have "
- // "requested not to be disturbed. Your message will still be shown in their IM "
- // "panel for later viewing.";
- //
- // Functions
- //
- void give_money(const LLUUID& uuid, LLViewerRegion* region, S32 amount, BOOL is_group,
- S32 trx_type, const std::string& desc)
- {
- if(0 == amount || !region) return;
- amount = abs(amount);
- LL_INFOS("Messaging") << "give_money(" << uuid << "," << amount << ")"<< LL_ENDL;
- if(can_afford_transaction(amount))
- {
- // gStatusBar->debitBalance(amount);
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_MoneyTransferRequest);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->nextBlockFast(_PREHASH_MoneyData);
- msg->addUUIDFast(_PREHASH_SourceID, gAgent.getID() );
- msg->addUUIDFast(_PREHASH_DestID, uuid);
- msg->addU8Fast(_PREHASH_Flags, pack_transaction_flags(FALSE, is_group));
- msg->addS32Fast(_PREHASH_Amount, amount);
- msg->addU8Fast(_PREHASH_AggregatePermNextOwner, (U8)LLAggregatePermissions::AP_EMPTY);
- msg->addU8Fast(_PREHASH_AggregatePermInventory, (U8)LLAggregatePermissions::AP_EMPTY);
- msg->addS32Fast(_PREHASH_TransactionType, trx_type );
- msg->addStringFast(_PREHASH_Description, desc);
- msg->sendReliable(region->getHost());
- }
- else
- {
- LLFloaterBuyCurrency::buyCurrency("Giving", amount);
- }
- }
- void send_complete_agent_movement(const LLHost& sim_host)
- {
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_CompleteAgentMovement);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->addU32Fast(_PREHASH_CircuitCode, msg->mOurCircuitCode);
- msg->sendReliable(sim_host);
- }
- void process_logout_reply(LLMessageSystem* msg, void**)
- {
- // The server has told us it's ok to quit.
- LL_DEBUGS("Messaging") << "process_logout_reply" << LL_ENDL;
- LLUUID agent_id;
- msg->getUUID("AgentData", "AgentID", agent_id);
- LLUUID session_id;
- msg->getUUID("AgentData", "SessionID", session_id);
- if((agent_id != gAgent.getID()) || (session_id != gAgent.getSessionID()))
- {
- LL_WARNS("Messaging") << "Bogus Logout Reply" << LL_ENDL;
- }
- LLInventoryModel::update_map_t parents;
- S32 count = msg->getNumberOfBlocksFast( _PREHASH_InventoryData );
- for(S32 i = 0; i < count; ++i)
- {
- LLUUID item_id;
- msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id, i);
- if( (1 == count) && item_id.isNull() )
- {
- // Detect dummy item. Indicates an empty list.
- break;
- }
- // We do not need to track the asset ids, just account for an
- // updated inventory version.
- LL_INFOS("Messaging") << "process_logout_reply itemID=" << item_id << LL_ENDL;
- LLInventoryItem* item = gInventory.getItem( item_id );
- if( item )
- {
- parents[item->getParentUUID()] = 0;
- gInventory.addChangedMask(LLInventoryObserver::INTERNAL, item_id);
- }
- else
- {
- LL_INFOS("Messaging") << "process_logout_reply item not found: " << item_id << LL_ENDL;
- }
- }
- LLAppViewer::instance()->forceQuit();
- }
- void process_layer_data(LLMessageSystem *mesgsys, void **user_data)
- {
- LLViewerRegion *regionp = LLWorld::getInstance()->getRegion(mesgsys->getSender());
- if (!regionp || gNoRender)
- {
- return;
- }
- S32 size;
- S8 type;
- mesgsys->getS8Fast(_PREHASH_LayerID, _PREHASH_Type, type);
- size = mesgsys->getSizeFast(_PREHASH_LayerData, _PREHASH_Data);
- if (0 == size)
- {
- LL_WARNS("Messaging") << "Layer data has zero size." << LL_ENDL;
- return;
- }
- if (size < 0)
- {
- // getSizeFast() is probably trying to tell us about an error
- LL_WARNS("Messaging") << "getSizeFast() returned negative result: "
- << size
- << LL_ENDL;
- return;
- }
- U8 *datap = new U8[size];
- mesgsys->getBinaryDataFast(_PREHASH_LayerData, _PREHASH_Data, datap, size);
- LLVLData *vl_datap = new LLVLData(regionp, type, datap, size);
- if (mesgsys->getReceiveCompressedSize())
- {
- gVLManager.addLayerData(vl_datap, mesgsys->getReceiveCompressedSize());
- }
- else
- {
- gVLManager.addLayerData(vl_datap, mesgsys->getReceiveSize());
- }
- }
- // S32 exported_object_count = 0;
- // S32 exported_image_count = 0;
- // S32 current_object_count = 0;
- // S32 current_image_count = 0;
- // extern LLNotifyBox *gExporterNotify;
- // extern LLUUID gExporterRequestID;
- // extern std::string gExportDirectory;
- // extern LLUploadDialog *gExportDialog;
- // std::string gExportedFile;
- // std::map<LLUUID, std::string> gImageChecksums;
- // void export_complete()
- // {
- // LLUploadDialog::modalUploadFinished();
- // gExporterRequestID.setNull();
- // gExportDirectory = "";
- // LLFILE* fXML = LLFile::fopen(gExportedFile, "rb"); /* Flawfinder: ignore */
- // fseek(fXML, 0, SEEK_END);
- // long length = ftell(fXML);
- // fseek(fXML, 0, SEEK_SET);
- // U8 *buffer = new U8[length + 1];
- // size_t nread = fread(buffer, 1, length, fXML);
- // if (nread < (size_t) length)
- // {
- // LL_WARNS("Messaging") << "Short read" << LL_ENDL;
- // }
- // buffer[nread] = ' ';
- // fclose(fXML);
- // char *pos = (char *)buffer;
- // while ((pos = strstr(pos+1, "<sl:image ")) != 0)
- // {
- // char *pos_check = strstr(pos, "checksum="");
- // if (pos_check)
- // {
- // char *pos_uuid = strstr(pos_check, "">");
- // if (pos_uuid)
- // {
- // char image_uuid_str[UUID_STR_SIZE]; /* Flawfinder: ignore */
- // memcpy(image_uuid_str, pos_uuid+2, UUID_STR_SIZE-1); /* Flawfinder: ignore */
- // image_uuid_str[UUID_STR_SIZE-1] = 0;
-
- // LLUUID image_uuid(image_uuid_str);
- // LL_INFOS("Messaging") << "Found UUID: " << image_uuid << LL_ENDL;
- // std::map<LLUUID, std::string>::iterator itor = gImageChecksums.find(image_uuid);
- // if (itor != gImageChecksums.end())
- // {
- // LL_INFOS("Messaging") << "Replacing with checksum: " << itor->second << LL_ENDL;
- // if (!itor->second.empty())
- // {
- // memcpy(&pos_check[10], itor->second.c_str(), 32); /* Flawfinder: ignore */
- // }
- // }
- // }
- // }
- // }
- // LLFILE* fXMLOut = LLFile::fopen(gExportedFile, "wb"); /* Flawfinder: ignore */
- // if (fwrite(buffer, 1, length, fXMLOut) != length)
- // {
- // LL_WARNS("Messaging") << "Short write" << LL_ENDL;
- // }
- // fclose(fXMLOut);
- // delete [] buffer;
- // }
- // void exported_item_complete(const LLTSCode status, void *user_data)
- // {
- // //std::string *filename = (std::string *)user_data;
- // if (status < LLTS_OK)
- // {
- // LL_WARNS("Messaging") << "Export failed!" << LL_ENDL;
- // }
- // else
- // {
- // ++current_object_count;
- // if (current_image_count == exported_image_count && current_object_count == exported_object_count)
- // {
- // LL_INFOS("Messaging") << "*** Export complete ***" << LL_ENDL;
- // export_complete();
- // }
- // else
- // {
- // gExportDialog->setMessage(llformat("Exported %d/%d object files, %d/%d textures.", current_object_count, exported_object_count, current_image_count, exported_image_count));
- // }
- // }
- // }
- // struct exported_image_info
- // {
- // LLUUID image_id;
- // std::string filename;
- // U32 image_num;
- // };
- // void exported_j2c_complete(const LLTSCode status, void *user_data)
- // {
- // exported_image_info *info = (exported_image_info *)user_data;
- // LLUUID image_id = info->image_id;
- // U32 image_num = info->image_num;
- // std::string filename = info->filename;
- // delete info;
- // if (status < LLTS_OK)
- // {
- // LL_WARNS("Messaging") << "Image download failed!" << LL_ENDL;
- // }
- // else
- // {
- // LLFILE* fIn = LLFile::fopen(filename, "rb"); /* Flawfinder: ignore */
- // if (fIn)
- // {
- // LLPointer<LLImageJ2C> ImageUtility = new LLImageJ2C;
- // LLPointer<LLImageTGA> TargaUtility = new LLImageTGA;
- // fseek(fIn, 0, SEEK_END);
- // S32 length = ftell(fIn);
- // fseek(fIn, 0, SEEK_SET);
- // U8 *buffer = ImageUtility->allocateData(length);
- // if (fread(buffer, 1, length, fIn) != length)
- // {
- // LL_WARNS("Messaging") << "Short read" << LL_ENDL;
- // }
- // fclose(fIn);
- // LLFile::remove(filename);
- // // Convert to TGA
- // LLPointer<LLImageRaw> image = new LLImageRaw();
- // ImageUtility->updateData();
- // ImageUtility->decode(image, 100000.0f);
-
- // TargaUtility->encode(image);
- // U8 *data = TargaUtility->getData();
- // S32 data_size = TargaUtility->getDataSize();
- // std::string file_path = gDirUtilp->getDirName(filename);
-
- // std::string output_file = llformat("%s/image-%03d.tga", file_path.c_str(), image_num);//filename;
- // //S32 name_len = output_file.length();
- // //strcpy(&output_file[name_len-3], "tga");
- // LLFILE* fOut = LLFile::fopen(output_file, "wb"); /* Flawfinder: ignore */
- // char md5_hash_string[33]; /* Flawfinder: ignore */
- // strcpy(md5_hash_string, "00000000000000000000000000000000"); /* Flawfinder: ignore */
- // if (fOut)
- // {
- // if (fwrite(data, 1, data_size, fOut) != data_size)
- // {
- // LL_WARNS("Messaging") << "Short write" << LL_ENDL;
- // }
- // fseek(fOut, 0, SEEK_SET);
- // fclose(fOut);
- // fOut = LLFile::fopen(output_file, "rb"); /* Flawfinder: ignore */
- // LLMD5 my_md5_hash(fOut);
- // my_md5_hash.hex_digest(md5_hash_string);
- // }
- // gImageChecksums.insert(std::pair<LLUUID, std::string>(image_id, md5_hash_string));
- // }
- // }
- // ++current_image_count;
- // if (current_image_count == exported_image_count && current_object_count == exported_object_count)
- // {
- // LL_INFOS("Messaging") << "*** Export textures complete ***" << LL_ENDL;
- // export_complete();
- // }
- // else
- // {
- // gExportDialog->setMessage(llformat("Exported %d/%d object files, %d/%d textures.", current_object_count, exported_object_count, current_image_count, exported_image_count));
- // }
- //}
- void process_derez_ack(LLMessageSystem*, void**)
- {
- if(gViewerWindow) gViewerWindow->getWindow()->decBusyCount();
- }
- void process_places_reply(LLMessageSystem* msg, void** data)
- {
- LLUUID query_id;
- msg->getUUID("AgentData", "QueryID", query_id);
- if (query_id.isNull())
- {
- LLFloaterLandHoldings::processPlacesReply(msg, data);
- }
- else if(gAgent.isInGroup(query_id))
- {
- LLPanelGroupLandMoney::processPlacesReply(msg, data);
- }
- else
- {
- LL_WARNS("Messaging") << "Got invalid PlacesReply message" << LL_ENDL;
- }
- }
- void send_sound_trigger(const LLUUID& sound_id, F32 gain)
- {
- if (sound_id.isNull() || gAgent.getRegion() == NULL)
- {
- // disconnected agent or zero guids don't get sent (no sound)
- return;
- }
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_SoundTrigger);
- msg->nextBlockFast(_PREHASH_SoundData);
- msg->addUUIDFast(_PREHASH_SoundID, sound_id);
- // Client untrusted, ids set on sim
- msg->addUUIDFast(_PREHASH_OwnerID, LLUUID::null );
- msg->addUUIDFast(_PREHASH_ObjectID, LLUUID::null );
- msg->addUUIDFast(_PREHASH_ParentID, LLUUID::null );
- msg->addU64Fast(_PREHASH_Handle, gAgent.getRegion()->getHandle());
- LLVector3 position = gAgent.getPositionAgent();
- msg->addVector3Fast(_PREHASH_Position, position);
- msg->addF32Fast(_PREHASH_Gain, gain);
- gAgent.sendMessage();
- }
- bool join_group_response(const LLSD& notification, const LLSD& response)
- {
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- BOOL delete_context_data = TRUE;
- bool accept_invite = false;
- LLUUID group_id = notification["payload"]["group_id"].asUUID();
- LLUUID transaction_id = notification["payload"]["transaction_id"].asUUID();
- std::string name = notification["payload"]["name"].asString();
- std::string message = notification["payload"]["message"].asString();
- S32 fee = notification["payload"]["fee"].asInteger();
- if (option == 2 && !group_id.isNull())
- {
- LLGroupActions::show(group_id);
- LLSD args;
- args["MESSAGE"] = message;
- LLNotificationsUtil::add("JoinGroup", args, notification["payload"]);
- return false;
- }
- if(option == 0 && !group_id.isNull())
- {
- // check for promotion or demotion.
- S32 max_groups = MAX_AGENT_GROUPS;
- if(gAgent.isInGroup(group_id)) ++max_groups;
- if(gAgent.mGroups.count() < max_groups)
- {
- accept_invite = true;
- }
- else
- {
- delete_context_data = FALSE;
- LLSD args;
- args["NAME"] = name;
- LLNotificationsUtil::add("JoinedTooManyGroupsMember", args, notification["payload"]);
- }
- }
- if (accept_invite)
- {
- // If there is a fee to join this group, make
- // sure the user is sure they want to join.
- if (fee > 0)
- {
- delete_context_data = FALSE;
- LLSD args;
- args["COST"] = llformat("%d", fee);
- // Set the fee for next time to 0, so that we don't keep
- // asking about a fee.
- LLSD next_payload = notification["payload"];
- next_payload["fee"] = 0;
- LLNotificationsUtil::add("JoinGroupCanAfford",
- args,
- next_payload);
- }
- else
- {
- send_improved_im(group_id,
- std::string("name"),
- std::string("message"),
- IM_ONLINE,
- IM_GROUP_INVITATION_ACCEPT,
- transaction_id);
- }
- }
- else
- {
- send_improved_im(group_id,
- std::string("name"),
- std::string("message"),
- IM_ONLINE,
- IM_GROUP_INVITATION_DECLINE,
- transaction_id);
- }
- return false;
- }
- static LLNotificationFunctorRegistration jgr_1("JoinGroup", join_group_response);
- static LLNotificationFunctorRegistration jgr_2("JoinedTooManyGroupsMember", join_group_response);
- static LLNotificationFunctorRegistration jgr_3("JoinGroupCanAfford", join_group_response);
- //-----------------------------------------------------------------------------
- // Instant Message
- //-----------------------------------------------------------------------------
- class LLOpenAgentOffer : public LLInventoryFetchObserver
- {
- public:
- LLOpenAgentOffer(const std::string& from_name) : mFromName(from_name) {}
- /*virtual*/ void done()
- {
- open_inventory_offer(mComplete, mFromName);
- gInventory.removeObserver(this);
- delete this;
- }
- private:
- std::string mFromName;
- };
- //unlike the FetchObserver for AgentOffer, we only make one
- //instance of the AddedObserver for TaskOffers
- //and it never dies. We do this because we don't know the UUID of
- //task offers until they are accepted, so we don't wouldn't
- //know what to watch for, so instead we just watch for all additions.
- class LLOpenTaskOffer : public LLInventoryAddedObserver
- {
- protected:
- /*virtual*/ void done()
- {
- open_inventory_offer(mAdded, "");
- mAdded.clear();
- }
- };
- class LLOpenTaskGroupOffer : public LLInventoryAddedObserver
- {
- protected:
- /*virtual*/ void done()
- {
- open_inventory_offer(mAdded, "group_offer");
- mAdded.clear();
- gInventory.removeObserver(this);
- delete this;
- }
- };
- //one global instance to bind them
- LLOpenTaskOffer* gNewInventoryObserver=NULL;
- void start_new_inventory_observer()
- {
- if (!gNewInventoryObserver) //task offer observer
- {
- // Observer is deleted by gInventory
- gNewInventoryObserver = new LLOpenTaskOffer;
- gInventory.addObserver(gNewInventoryObserver);
- }
- }
- class LLDiscardAgentOffer : public LLInventoryFetchComboObserver
- {
- LOG_CLASS(LLDiscardAgentOffer);
- public:
- LLDiscardAgentOffer(const LLUUID& folder_id, const LLUUID& object_id) :
- mFolderID(folder_id),
- mObjectID(object_id) {}
- virtual ~LLDiscardAgentOffer() {}
- virtual void done()
- {
- LL_DEBUGS("Messaging") << "LLDiscardAgentOffer::done()" << LL_ENDL;
- const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
- bool notify = false;
- if(trash_id.notNull() && mObjectID.notNull())
- {
- LLInventoryModel::update_list_t update;
- LLInventoryModel::LLCategoryUpdate old_folder(mFolderID, -1);
- update.push_back(old_folder);
- LLInventoryModel::LLCategoryUpdate new_folder(trash_id, 1);
- update.push_back(new_folder);
- gInventory.accountForUpdate(update);
- gInventory.moveObject(mObjectID, trash_id);
- LLInventoryObject* obj = gInventory.getObject(mObjectID);
- if(obj)
- {
- // no need to restamp since this is already a freshly
- // stamped item.
- obj->updateParentOnServer(FALSE);
- notify = true;
- }
- }
- else
- {
- LL_WARNS("Messaging") << "DiscardAgentOffer unable to find: "
- << (trash_id.isNull() ? "trash " : "")
- << (mObjectID.isNull() ? "object" : "") << LL_ENDL;
- }
- gInventory.removeObserver(this);
- if(notify)
- {
- gInventory.notifyObservers();
- }
- delete this;
- }
- protected:
- LLUUID mFolderID;
- LLUUID mObjectID;
- };
- //Returns TRUE if we are OK, FALSE if we are throttled
- //Set check_only true if you want to know the throttle status
- //without registering a hit
- bool check_offer_throttle(const std::string& from_name, bool check_only)
- {
- static U32 throttle_count;
- static bool throttle_logged;
- LLChat chat;
- std::string log_message;
- if (!gSavedSettings.getBOOL("ShowNewInventory"))
- return false;
- if (check_only)
- {
- return gThrottleTimer.hasExpired();
- }
-
- if(gThrottleTimer.checkExpirationAndReset(OFFER_THROTTLE_TIME))
- {
- LL_DEBUGS("Messaging") << "Throttle Expired" << LL_ENDL;
- throttle_count=1;
- throttle_logged=false;
- return true;
- }
- else //has not expired
- {
- LL_DEBUGS("Messaging") << "Throttle Not Expired, Count: " << throttle_count << LL_ENDL;
- // When downloading the initial inventory we get a lot of new items
- // coming in and can't tell that from spam.
- if (LLStartUp::getStartupState() >= STATE_STARTED
- && throttle_count >= OFFER_THROTTLE_MAX_COUNT)
- {
- if (!throttle_logged)
- {
- // Use the name of the last item giver, who is probably the person
- // spamming you.
- std::ostringstream message;
- message << LLAppViewer::instance()->getSecondLifeTitle();
- if (!from_name.empty())
- {
- message << ": Items coming in too fast from " << from_name;
- }
- else
- {
- message << ": Items coming in too fast";
- }
- message << ", automatic preview disabled for "
- << OFFER_THROTTLE_TIME << " seconds.";
-
- //this is kinda important, so actually put it on screen
- std::string log_msg = message.str();
- LLSD args;
- args["MESSAGE"] = log_msg;
- LLNotificationsUtil::add("SystemMessage", args);
- throttle_logged=true;
- }
- return false;
- }
- else
- {
- throttle_count++;
- return true;
- }
- }
- }
-
- void open_inventory_offer(const std::vector<LLUUID>& items, const std::string& from_name)
- {
- for (std::vector<LLUUID>::const_iterator item_iter = items.begin();
- item_iter != items.end();
- ++item_iter)
- {
- const LLUUID& item_id = (*item_iter);
- if(!highlight_offered_item(item_id))
- {
- continue;
- }
- LLInventoryItem* item = gInventory.getItem(item_id);
- llassert(item);
- if (!item) {
- continue;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Special handling for various types.
- const LLAssetType::EType asset_type = item->getType();
- if (check_offer_throttle(from_name, false)) // If we are throttled, don't display
- {
- LL_DEBUGS("Messaging") << "Highlighting inventory item: " << item->getUUID() << LL_ENDL;
- // If we opened this ourselves, focus it
- const BOOL take_focus = from_name.empty() ? TAKE_FOCUS_YES : TAKE_FOCUS_NO;
- switch(asset_type)
- {
- case LLAssetType::AT_NOTECARD:
- {
- LLFloaterReg::showInstance("preview_notecard", LLSD(item_id), take_focus);
- break;
- }
- case LLAssetType::AT_LANDMARK:
- {
- LLInventoryCategory* parent_folder = gInventory.getCategory(item->getParentUUID());
- if ("inventory_handler" == from_name)
- {
- //we have to filter inventory_handler messages to avoid notification displaying
- LLSideTray::getInstance()->showPanel("panel_places",
- LLSD().with("type", "landmark").with("id", item->getUUID()));
- }
- else if("group_offer" == from_name)
- {
- // do not open inventory when we open group notice attachment because
- // we already opened landmark info panel
- // "group_offer" is passed by LLOpenTaskGroupOffer
- continue;
- }
- else if(from_name.empty())
- {
- // we receive a message from LLOpenTaskOffer, it mean that new landmark has been added.
- LLSD args;
- args["LANDMARK_NAME"] = item->getName();
- args["FOLDER_NAME"] = std::string(parent_folder ? parent_folder->getName() : "unknown");
- LLNotificationsUtil::add("LandmarkCreated", args);
- // Created landmark is passed to Places panel to allow its editing. In fact panel should be already displayed.
- // If the panel is closed we don't reopen it until created landmark is loaded.
- //TODO*:: dserduk(7/12/09) remove LLPanelPlaces dependency from here
- LLPanelPlaces *places_panel = dynamic_cast<LLPanelPlaces*>(LLSideTray::getInstance()->getPanel("panel_places"));
- if (places_panel)
- {
- // Landmark creation handling is moved to LLPanelPlaces::showAddedLandmarkInfo()
- // TODO* LLPanelPlaces dependency is going to be removed. See EXT-4347.
- //if("create_landmark" == places_panel->getPlaceInfoType() && !places_panel->getItem())
- //{
- // places_panel->setItem(item);
- //}
- //else
- // we are opening a group notice attachment
- if("create_landmark" != places_panel->getPlaceInfoType())
- {
- LLSD args;
- args["type"] = "landmark";
- args["id"] = item_id;
- LLSideTray::getInstance()->showPanel("panel_places", args);
- }
- }
- }
- }
- break;
- case LLAssetType::AT_TEXTURE:
- {
- LLFloaterReg::showInstance("preview_texture", LLSD(item_id), take_focus);
- break;
- }
- case LLAssetType::AT_ANIMATION:
- LLFloaterReg::showInstance("preview_anim", LLSD(item_id), take_focus);
- break;
- case LLAssetType::AT_SCRIPT:
- LLFloaterReg::showInstance("preview_script", LLSD(item_id), take_focus);
- break;
- case LLAssetType::AT_SOUND:
- LLFloaterReg::showInstance("preview_sound", LLSD(item_id), take_focus);
- break;
- default:
- break;
- }
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- // Highlight item if it's not in the trash, lost+found, or COF
- const BOOL auto_open = gSavedSettings.getBOOL("ShowInInventory") &&
- (asset_type != LLAssetType::AT_CALLINGCARD) &&
- (item->getInventoryType() != LLInventoryType::IT_ATTACHMENT) &&
- !from_name.empty();
- LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(auto_open);
- if(active_panel)
- {
- LL_DEBUGS("Messaging") << "Highlighting" << item_id << LL_ENDL;
- LLFocusableElement* focus_ctrl = gFocusMgr.getKeyboardFocus();
- active_panel->setSelection(item_id, TAKE_FOCUS_NO);
- gFocusMgr.setKeyboardFocus(focus_ctrl);
- }
- }
- }
- bool highlight_offered_item(const LLUUID& item_id)
- {
- LLInventoryItem* item = gInventory.getItem(item_id);
- if(!item)
- {
- LL_WARNS("Messaging") << "Unable to show inventory item: " << item_id << LL_ENDL;
- return false;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Don't highlight if it's in certain "quiet" folders which don't need UI
- // notification (e.g. trash, cof, lost-and-found).
- if(!gAgent.getAFK())
- {
- const LLViewerInventoryCategory *parent = gInventory.getFirstNondefaultParent(item_id);
- if (parent)
- {
- const LLFolderType::EType parent_type = parent->getPreferredType();
- if (LLViewerFolderType::lookupIsQuietType(parent_type))
- {
- return false;
- }
- }
- }
- return true;
- }
- void inventory_offer_mute_callback(const LLUUID& blocked_id,
- const std::string& first_name,
- const std::string& last_name,
- BOOL is_group, LLOfferInfo* offer = NULL)
- {
- std::string from_name;
- LLMute::EType type;
- if (is_group)
- {
- type = LLMute::GROUP;
- from_name = first_name;
- }
- else if(offer && offer->mFromObject)
- {
- //we have to block object by name because blocked_id is an id of owner
- type = LLMute::BY_NAME;
- from_name = offer->mFromName;
- }
- else
- {
- type = LLMute::AGENT;
- from_name = first_name + " " + last_name;
- }
- // id should be null for BY_NAME mute, see LLMuteList::add for details
- LLMute mute(type == LLMute::BY_NAME ? LLUUID::null : blocked_id, from_name, type);
- if (LLMuteList::getInstance()->add(mute))
- {
- LLPanelBlockedList::showPanelAndSelect(blocked_id);
- }
- // purge the message queue of any previously queued inventory offers from the same source.
- class OfferMatcher : public LLNotificationsUI::LLScreenChannel::Matcher
- {
- public:
- OfferMatcher(const LLUUID& to_block) : blocked_id(to_block) {}
- bool matches(const LLNotificationPtr notification) const
- {
- if(notification->getName() == "ObjectGiveItem"
- || notification->getName() == "ObjectGiveItemUnknownUser"
- || notification->getName() == "UserGiveItem")
- {
- return (notification->getPayload()["from_id"].asUUID() == blocked_id);
- }
- return FALSE;
- }
- private:
- const LLUUID& blocked_id;
- };
- LLNotificationsUI::LLChannelManager::getInstance()->killToastsFromChannel(LLUUID(
- gSavedSettings.getString("NotificationChannelUUID")), OfferMatcher(blocked_id));
- }
- LLOfferInfo::LLOfferInfo(const LLSD& sd)
- {
- mIM = (EInstantMessage)sd["im_type"].asInteger();
- mFromID = sd["from_id"].asUUID();
- mFromGroup = sd["from_group"].asBoolean();
- mFromObject = sd["from_object"].asBoolean();
- mTransactionID = sd["transaction_id"].asUUID();
- mFolderID = sd["folder_id"].asUUID();
- mObjectID = sd["object_id"].asUUID();
- mType = LLAssetType::lookup(sd["type"].asString().c_str());
- mFromName = sd["from_name"].asString();
- mDesc = sd["description"].asString();
- mHost = LLHost(sd["sender"].asString());
- }
- LLSD LLOfferInfo::asLLSD()
- {
- LLSD sd;
- sd["im_type"] = mIM;
- sd["from_id"] = mFromID;
- sd["from_group"] = mFromGroup;
- sd["from_object"] = mFromObject;
- sd["transaction_id"] = mTransactionID;
- sd["folder_id"] = mFolderID;
- sd["object_id"] = mObjectID;
- sd["type"] = LLAssetType::lookup(mType);
- sd["from_name"] = mFromName;
- sd["description"] = mDesc;
- sd["sender"] = mHost.getIPandPort();
- return sd;
- }
- void LLOfferInfo::send_auto_receive_response(void)
- {
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_ImprovedInstantMessage);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->nextBlockFast(_PREHASH_MessageBlock);
- msg->addBOOLFast(_PREHASH_FromGroup, FALSE);
- msg->addUUIDFast(_PREHASH_ToAgentID, mFromID);
- msg->addU8Fast(_PREHASH_Offline, IM_ONLINE);
- msg->addUUIDFast(_PREHASH_ID, mTransactionID);
- msg->addU32Fast(_PREHASH_Timestamp, NO_TIMESTAMP); // no timestamp necessary
- std::string name;
- LLAgentUI::buildFullname(name);
- msg->addStringFast(_PREHASH_FromAgentName, name);
- msg->addStringFast(_PREHASH_Message, "");
- msg->addU32Fast(_PREHASH_ParentEstateID, 0);
- msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null);
- msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent());
-
- // Auto Receive Message. The math for the dialog works, because the accept
- // for inventory_offered, task_inventory_offer or
- // group_notice_inventory is 1 greater than the offer integer value.
- // Generates IM_INVENTORY_ACCEPTED, IM_TASK_INVENTORY_ACCEPTED,
- // or IM_GROUP_NOTICE_INVENTORY_ACCEPTED
- msg->addU8Fast(_PREHASH_Dialog, (U8)(mIM + 1));
- msg->addBinaryDataFast(_PREHASH_BinaryBucket, &(mFolderID.mData),
- sizeof(mFolderID.mData));
- // send the message
- msg->sendReliable(mHost);
-
- if(IM_INVENTORY_OFFERED == mIM)
- {
- // add buddy to recent people list
- LLRecentPeople::instance().add(mFromID);
- }
- }
- bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& response)
- {
- LLChat chat;
- std::string log_message;
- S32 button = LLNotificationsUtil::getSelectedOption(notification, response);
-
- LLInventoryObserver* opener = NULL;
- LLViewerInventoryCategory* catp = NULL;
- catp = (LLViewerInventoryCategory*)gInventory.getCategory(mObjectID);
- LLViewerInventoryItem* itemp = NULL;
- if(!catp)
- {
- itemp = (LLViewerInventoryItem*)gInventory.getItem(mObjectID);
- }
-
- // For muting, we need to add the mute, then decline the offer.
- // This must be done here because:
- // * callback may be called immediately,
- // * adding the mute sends a message,
- // * we can't build two messages at once.
- if (2 == button) // Block
- {
- gCacheName->get(mFromID, mFromGroup, boost::bind(&inventory_offer_mute_callback,_1,_2,_3,_4,this));
- }
- std::string from_string; // Used in the pop-up.
- std::string chatHistory_string; // Used in chat history.
-
- // TODO: when task inventory offers can also be handled the new way, migrate the code that sets these strings here:
- from_string = chatHistory_string = mFromName;
-
- bool busy=FALSE;
-
- switch(button)
- {
- case IOR_SHOW:
- // we will want to open this item when it comes back.
- LL_DEBUGS("Messaging") << "Initializing an opener for tid: " << mTransactionID
- << LL_ENDL;
- switch (mIM)
- {
- case IM_INVENTORY_OFFERED:
- {
- // This is an offer from an agent. In this case, the back
- // end has already copied the items into your inventory,
- // so we can fetch it out of our inventory.
- LLInventoryFetchObserver::item_ref_t items;
- items.push_back(mObjectID);
- LLOpenAgentOffer* open_agent_offer = new LLOpenAgentOffer(from_string);
- open_agent_offer->fetchItems(items);
- if(catp || (itemp && itemp->isComplete()))
- {
- open_agent_offer->done();
- }
- else
- {
- opener = open_agent_offer;
- }
- }
- break;
- case IM_GROUP_NOTICE:
- opener = new LLOpenTaskGroupOffer;
- send_auto_receive_response();
- break;
- case IM_TASK_INVENTORY_OFFERED:
- case IM_GROUP_NOTICE_REQUESTED:
- // This is an offer from a task or group.
- // We don't use a new instance of an opener
- // We instead use the singular observer gOpenTaskOffer
- // Since it already exists, we don't need to actually do anything
- break;
- default:
- LL_WARNS("Messaging") << "inventory_offer_callback: unknown offer type" << LL_ENDL;
- break;
- }
- break;
- // end switch (mIM)
-
- case IOR_ACCEPT:
- //don't spam them if they are getting flooded
- if (check_offer_throttle(mFromName, true))
- {
- log_message = chatHistory_string + " " + LLTrans::getString("InvOfferGaveYou") + " " + mDesc + LLTrans::getString(".");
- LLSD args;
- args["MESSAGE"] = log_message;
- LLNotificationsUtil::add("SystemMessage", args);
- }
- break;
- case IOR_BUSY:
- //Busy falls through to decline. Says to make busy message.
- busy=TRUE;
- case IOR_MUTE:
- // MUTE falls through to decline
- case IOR_DECLINE:
- {
- log_message = LLTrans::getString("InvOfferYouDecline") + " " + mDesc + " " + LLTrans::getString("InvOfferFrom") + " " + mFromName +".";
- chat.mText = log_message;
- if( LLMuteList::getInstance()->isMuted(mFromID ) && ! LLMuteList::getInstance()->isLinden(mFromName) ) // muting for SL-42269
- {
- chat.mMuted = TRUE;
- }
- // *NOTE dzaporozhan
- // Disabled logging to old chat floater to fix crash in group notices - EXT-4149
- // LLFloaterChat::addChatHistory(chat);
-
- LLInventoryFetchComboObserver::folder_ref_t folders;
- LLInventoryFetchComboObserver::item_ref_t items;
- items.push_back(mObjectID);
- LLDiscardAgentOffer* discard_agent_offer;
- discard_agent_offer = new LLDiscardAgentOffer(mFolderID, mObjectID);
- discard_agent_offer->fetch(folders, items);
- if(catp || (itemp && itemp->isComplete()))
- {
- discard_agent_offer->done();
- }
- else
- {
- opener = discard_agent_offer;
- }
-
-
- if (busy && (!mFromGroup && !mFromObject))
- {
- busy_message(gMessageSystem, mFromID);
- }
- break;
- }
- default:
- // close button probably
- // The item has already been fetched and is in your inventory, we simply won't highlight it
- // OR delete it if the notification gets killed, since we don't want that to be a vector for
- // losing inventory offers.
- break;
- }
- if(opener)
- {
- gInventory.addObserver(opener);
- }
- delete this;
- return false;
- }
- bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const LLSD& response)
- {
- LLChat chat;
- std::string log_message;
- S32 button = LLNotification::getSelectedOption(notification, response);
-
- // For muting, we need to add the mute, then decline the offer.
- // This must be done here because:
- // * callback may be called immediately,
- // * adding the mute sends a message,
- // * we can't build two messages at once.
- if (2 == button)
- {
- gCacheName->get(mFromID, mFromGroup, boost::bind(&inventory_offer_mute_callback,_1,_2,_3,_4,this));
- }
-
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_ImprovedInstantMessage);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->nextBlockFast(_PREHASH_MessageBlock);
- msg->addBOOLFast(_PREHASH_FromGroup, FALSE);
- msg->addUUIDFast(_PREHASH_ToAgentID, mFromID);
- msg->addU8Fast(_PREHASH_Offline, IM_ONLINE);
- msg->addUUIDFast(_PREHASH_ID, mTransactionID);
- msg->addU32Fast(_PREHASH_Timestamp, NO_TIMESTAMP); // no timestamp necessary
- std::string name;
- LLAgentUI::buildFullname(name);
- msg->addStringFast(_PREHASH_FromAgentName, name);
- msg->addStringFast(_PREHASH_Message, "");
- msg->addU32Fast(_PREHASH_ParentEstateID, 0);
- msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null);
- msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent());
- LLInventoryObserver* opener = NULL;
-
- std::string from_string; // Used in the pop-up.
- std::string chatHistory_string; // Used in chat history.
- if (mFromObject == TRUE)
- {
- if (mFromGroup)
- {
- std::string group_name;
- if (gCacheName->getGroupName(mFromID, group_name))
- {
- from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+"'"
- + mFromName + LLTrans::getString("'") +" " + LLTrans::getString("InvOfferOwnedByGroup")
- + " "+ "'" + group_name + "'";
-
- chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByGroup")
- + " " + group_name + "'";
- }
- else
- {
- from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+"'"
- + mFromName +"'"+ " " + LLTrans::getString("InvOfferOwnedByUnknownGroup");
- chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByUnknownGroup");
- }
- }
- else
- {
- std::string first_name, last_name;
- if (gCacheName->getName(mFromID, first_name, last_name))
- {
- from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+ LLTrans::getString("'") + mFromName
- + LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedBy") + first_name + " " + last_name;
- chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedBy") + " " + first_name + " " + last_name;
- }
- else
- {
- from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+LLTrans::getString("'")
- + mFromName + LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedByUnknownUser");
- chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByUnknownUser");
- }
- }
- }
- else
- {
- from_string = chatHistory_string = mFromName;
- }
-
- bool busy=FALSE;
-
- switch(button)
- {
- case IOR_ACCEPT:
- // ACCEPT. The math for the dialog works, because the accept
- // for inventory_offered, task_inventory_offer or
- // group_notice_inventory is 1 greater than the offer integer value.
- // Generates IM_INVENTORY_ACCEPTED, IM_TASK_INVENTORY_ACCEPTED,
- // or IM_GROUP_NOTICE_INVENTORY_ACCEPTED
- msg->addU8Fast(_PREHASH_Dialog, (U8)(mIM + 1));
- msg->addBinaryDataFast(_PREHASH_BinaryBucket, &(mFolderID.mData),
- sizeof(mFolderID.mData));
- // send the message
- msg->sendReliable(mHost);
-
- //don't spam them if they are getting flooded
- if (check_offer_throttle(mFromName, true))
- {
- log_message = chatHistory_string + " " + LLTrans::getString("InvOfferGaveYou") + " " + mDesc + LLTrans::getString(".");
- LLSD args;
- args["MESSAGE"] = log_message;
- LLNotificationsUtil::add("SystemMessage", args);
- }
-
- // we will want to open this item when it comes back.
- LL_DEBUGS("Messaging") << "Initializing an opener for tid: " << mTransactionID
- << LL_ENDL;
- switch (mIM)
- {
- case IM_TASK_INVENTORY_OFFERED:
- case IM_GROUP_NOTICE:
- case IM_GROUP_NOTICE_REQUESTED:
- {
- // This is an offer from a task or group.
- // We don't use a new instance of an opener
- // We instead use the singular observer gOpenTaskOffer
- // Since it already exists, we don't need to actually do anything
- }
- break;
- default:
- LL_WARNS("Messaging") << "inventory_offer_callback: unknown offer type" << LL_ENDL;
- break;
- } // end switch (mIM)
- break;
-
- case IOR_BUSY:
- //Busy falls through to decline. Says to make busy message.
- busy=TRUE;
- case IOR_MUTE:
- // MUTE falls through to decline
- case IOR_DECLINE:
- // DECLINE. The math for the dialog works, because the decline
- // for inventory_offered, task_inventory_offer or
- // group_notice_inventory is 2 greater than the offer integer value.
- // Generates IM_INVENTORY_DECLINED, IM_TASK_INVENTORY_DECLINED,
- // or IM_GROUP_NOTICE_INVENTORY_DECLINED
- default:
- // close button probably (or any of the fall-throughs from above)
- msg->addU8Fast(_PREHASH_Dialog, (U8)(mIM + 2));
- msg->addBinaryDataFast(_PREHASH_BinaryBucket, EMPTY_BINARY_BUCKET, EMPTY_BINARY_BUCKET_SIZE);
- // send the message
- msg->sendReliable(mHost);
-
- log_message = LLTrans::getString("InvOfferYouDecline") + " " + mDesc + " " + LLTrans::getString("InvOfferFrom") + " " + mFromName +".";
- LLSD args;
- args["MESSAGE"] = log_message;
- LLNotificationsUtil::add("SystemMessage", args);
-
- if (busy && (!mFromGroup && !mFromObject))
- {
- busy_message(msg,mFromID);
- }
- break;
- }
-
- if(opener)
- {
- gInventory.addObserver(opener);
- }
- delete this;
- return false;
- }
- void inventory_offer_handler(LLOfferInfo* info)
- {
- //Until throttling is implmented, busy mode should reject inventory instead of silently
- //accepting it. SEE SL-39554
- if (gAgent.getBusy())
- {
- info->forceResponse(IOR_BUSY);
- return;
- }
-
- //If muted, don't even go through the messaging stuff. Just curtail the offer here.
- if (LLMuteList::getInstance()->isMuted(info->mFromID, info->mFromName))
- {
- info->forceResponse(IOR_MUTE);
- return;
- }
- // Avoid the Accept/Discard dialog if the user so desires. JC
- if (gSavedSettings.getBOOL("AutoAcceptNewInventory")
- && (info->mType == LLAssetType::AT_NOTECARD
- || info->mType == LLAssetType::AT_LANDMARK
- || info->mType == LLAssetType::AT_TEXTURE))
- {
- // For certain types, just accept the items into the inventory,
- // and possibly open them on receipt depending upon "ShowNewInventory".
- info->forceResponse(IOR_ACCEPT);
- return;
- }
- // Strip any SLURL from the message display. (DEV-2754)
- std::string msg = info->mDesc;
- int indx = msg.find(" ( http://slurl.com/secondlife/");
- if(indx == std::string::npos)
- {
- // try to find new slurl host
- indx = msg.find(" ( http://maps.secondlife.com/secondlife/");
- }
- if(indx >= 0)
- {
- LLStringUtil::truncate(msg, indx);
- }
- LLSD args;
- args["[OBJECTNAME]"] = msg;
- LLSD payload;
- // must protect against a NULL return from lookupHumanReadable()
- std::string typestr = ll_safe_string(LLAssetType::lookupHumanReadable(info->mType));
- if (!typestr.empty())
- {
- args["OBJECTTYPE"] = typestr;
- }
- else
- {
- LL_WARNS("Messaging") << "LLAssetType::lookupHumanReadable() returned NULL - probably bad asset type: " << info->mType << LL_ENDL;
- args["OBJECTTYPE"] = "";
- // This seems safest, rather than propagating bogosity
- LL_WARNS("Messaging") << "Forcing an inventory-decline for probably-bad asset type." << LL_ENDL;
- info->forceResponse(IOR_DECLINE);
- return;
- }
- // Name cache callbacks don't store userdata, so can't save
- // off the LLOfferInfo. Argh.
- BOOL name_found = FALSE;
- if (info->mFromGroup)
- {
- std::string group_name;
- if (gCacheName->getGroupName(info->mFromID, group_name))
- {
- args["FIRST"] = group_name;
- args["LAST"] = "";
- name_found = TRUE;
- }
- }
- else
- {
- std::string first_name, last_name;
- if (gCacheName->getName(info->mFromID, first_name, last_name))
- {
- args["FIRST"] = first_name;
- args["LAST"] = last_name;
- name_found = TRUE;
- }
- }
- // If mObjectID is null then generate the object_id based on msg to prevent
- // multiple creation of chiclets for same object.
- LLUUID object_id = info->mObjectID;
- if (object_id.isNull())
- object_id.generate(msg);
- payload["from_id"] = info->mFromID;
- // Needed by LLScriptFloaterManager to bind original notification with
- // faked for toast one.
- payload["object_id"] = object_id;
- // Flag indicating that this notification is faked for toast.
- payload["give_inventory_notification"] = FALSE;
- args["OBJECTFROMNAME"] = info->mFromName;
- args["NAME"] = info->mFromName;
- args["NAME_SLURL"] = LLSLURL::buildCommand("agent", info->mFromID, "about");
- std::string verb = "select?name=" + LLURI::escape(msg);
- args["ITEM_SLURL"] = LLSLURL::buildCommand("inventory", info->mObjectID, verb.c_str());
- LLNotification::Params p("ObjectGiveItem");
- // Object -> Agent Inventory Offer
- if (info->mFromObject)
- {
- // Inventory Slurls don't currently work for non agent transfers, so only display the object name.
- args["ITEM_SLURL"] = msg;
- // Note: sets inventory_task_offer_callback as the callback
- p.substitutions(args).payload(payload).functor.function(boost::bind(&LLOfferInfo::inventory_task_offer_callback, info, _1, _2));
- p.name = name_found ? "ObjectGiveItem" : "ObjectGiveItemUnknownUser";
- // Pop up inv offer chiclet and let the user accept (keep), or reject (and silently delete) the inventory.
- LLNotifications::instance().add(p);
- }
- else // Agent -> Agent Inventory Offer
- {
- // Note: sets inventory_offer_callback as the callback
- p.substitutions(args).payload(payload).functor.function(boost::bind(&LLOfferInfo::inventory_offer_callback, info, _1, _2));
- p.name = "UserGiveItem";
-
- // Prefetch the item into your local inventory.
- LLInventoryFetchObserver::item_ref_t items;
- items.push_back(info->mObjectID);
- LLInventoryFetchObserver* fetch_item = new LLInventoryFetchObserver();
- fetch_item->fetchItems(items);
- if(fetch_item->isEverythingComplete())
- {
- fetch_item->done();
- }
- else
- {
- gInventory.addObserver(fetch_item);
- }
-
- // In viewer 2 we're now auto receiving inventory offers and messaging as such (not sending reject messages).
- info->send_auto_receive_response();
- // Inform user that there is a script floater via toast system
- {
- payload["give_inventory_notification"] = TRUE;
- LLNotificationPtr notification = LLNotifications::instance().add(p.payload(payload));
- }
- }
- }
- bool lure_callback(const LLSD& notification, const LLSD& response)
- {
- S32 option = 0;
- if (response.isInteger())
- {
- option = response.asInteger();
- }
- else
- {
- option = LLNotificationsUtil::getSelectedOption(notification, response);
- }
-
- LLUUID from_id = notification["payload"]["from_id"].asUUID();
- LLUUID lure_id = notification["payload"]["lure_id"].asUUID();
- BOOL godlike = notification["payload"]["godlike"].asBoolean();
- switch(option)
- {
- case 0:
- {
- // accept
- gAgent.teleportViaLure(lure_id, godlike);
- }
- break;
- case 1:
- default:
- // decline
- send_simple_im(from_id,
- LLStringUtil::null,
- IM_LURE_DECLINED,
- lure_id);
- break;
- }
- return false;
- }
- static LLNotificationFunctorRegistration lure_callback_reg("TeleportOffered", lure_callback);
- bool goto_url_callback(const LLSD& notification, const LLSD& response)
- {
- std::string url = notification["payload"]["url"].asString();
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- if(1 == option)
- {
- LLWeb::loadURL(url);
- }
- return false;
- }
- static LLNotificationFunctorRegistration goto_url_callback_reg("GotoURL", goto_url_callback);
- bool inspect_remote_object_callback(const LLSD& notification, const LLSD& response)
- {
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- if (0 == option)
- {
- LLFloaterReg::showInstance("inspect_remote_object", notification["payload"]);
- }
- return false;
- }
- static LLNotificationFunctorRegistration inspect_remote_object_callback_reg("ServerObjectMessage", inspect_remote_object_callback);
- void process_improved_im(LLMessageSystem *msg, void **user_data)
- {
- if (gNoRender)
- {
- return;
- }
- LLUUID from_id;
- BOOL from_group;
- LLUUID to_id;
- U8 offline;
- U8 d = 0;
- LLUUID session_id;
- U32 timestamp;
- std::string name;
- std::string message;
- U32 parent_estate_id = 0;
- LLUUID region_id;
- LLVector3 position;
- U8 binary_bucket[MTUBYTES];
- S32 binary_bucket_size;
- LLChat chat;
- std::string buffer;
-
- // *TODO: Translate - need to fix the full name to first/last (maybe)
- msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, from_id);
- msg->getBOOLFast(_PREHASH_MessageBlock, _PREHASH_FromGroup, from_group);
- msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_ToAgentID, to_id);
- msg->getU8Fast( _PREHASH_MessageBlock, _PREHASH_Offline, offline);
- msg->getU8Fast( _PREHASH_MessageBlock, _PREHASH_Dialog, d);
- msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_ID, session_id);
- msg->getU32Fast( _PREHASH_MessageBlock, _PREHASH_Timestamp, timestamp);
- //msg->getData("MessageBlock", "Count", &count);
- msg->getStringFast(_PREHASH_MessageBlock, _PREHASH_FromAgentName, name);
- msg->getStringFast(_PREHASH_MessageBlock, _PREHASH_Message, message);
- msg->getU32Fast(_PREHASH_MessageBlock, _PREHASH_ParentEstateID, parent_estate_id);
- msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_RegionID, region_id);
- msg->getVector3Fast(_PREHASH_MessageBlock, _PREHASH_Position, position);
- msg->getBinaryDataFast( _PREHASH_MessageBlock, _PREHASH_BinaryBucket, binary_bucket, 0, 0, MTUBYTES);
- binary_bucket_size = msg->getSizeFast(_PREHASH_MessageBlock, _PREHASH_BinaryBucket);
- EInstantMessage dialog = (EInstantMessage)d;
- // make sure that we don't have an empty or all-whitespace name
- LLStringUtil::trim(name);
- if (name.empty())
- {
- name = LLTrans::getString("Unnamed");
- }
- BOOL is_busy = gAgent.getBusy();
- BOOL is_muted = LLMuteList::getInstance()->isMuted(from_id, name, LLMute::flagTextChat);
- BOOL is_linden = LLMuteList::getInstance()->isLinden(name);
- BOOL is_owned_by_me = FALSE;
- BOOL is_friend = (LLAvatarTracker::instance().getBuddyInfo(from_id) == NULL) ? false : true;
- BOOL accept_im_from_only_friend = gSavedSettings.getBOOL("VoiceCallsFriendsOnly");
-
- chat.mMuted = is_muted && !is_linden;
- chat.mFromID = from_id;
- chat.mFromName = name;
- chat.mSourceType = (from_id.isNull() || (name == std::string(SYSTEM_FROM))) ? CHAT_SOURCE_SYSTEM : CHAT_SOURCE_AGENT;
- LLViewerObject *source = gObjectList.findObject(session_id); //Session ID is probably the wrong thing.
- if (source)
- {
- is_owned_by_me = source->permYouOwner();
- }
- std::string separator_string(": ");
- LLSD args;
- switch(dialog)
- {
- case IM_CONSOLE_AND_CHAT_HISTORY:
- // These are used for system messages, hence don't need the name,
- // as it is always "Second Life".
- // *TODO: Translate
- args["MESSAGE"] = message;
- // Note: don't put the message in the IM history, even though was sent
- // via the IM mechanism.
- LLNotificationsUtil::add("SystemMessageTip",args);
- break;
- case IM_NOTHING_SPECIAL:
- // Don't show dialog, just do IM
- if (!gAgent.isGodlike()
- && gAgent.getRegion()->isPrelude()
- && to_id.isNull() )
- {
- // do nothing -- don't distract newbies in
- // Prelude with global IMs
- }
- else if (offline == IM_ONLINE && !is_linden && is_busy && name != SYSTEM_FROM)
- {
- // return a standard "busy" message, but only do it to online IM
- // (i.e. not other auto responses and not store-and-forward IM)
- if (!gIMMgr->hasSession(session_id))
- {
- // if there is not a panel for this conversation (i.e. it is a new IM conversation
- // initiated by the other party) then...
- std::string my_name;
- LLAgentUI::buildFullname(my_name);
- std::string response = gSavedPerAccountSettings.getString("BusyModeResponse2");
- pack_instant_message(
- gMessageSystem,
- gAgent.getID(),
- FALSE,
- gAgent.getSessionID(),
- from_id,
- my_name,
- response,
- IM_ONLINE,
- IM_BUSY_AUTO_RESPONSE,
- session_id);
- gAgent.sendReliableMessage();
- }
- // now store incoming IM in chat history
- buffer = message;
-
- LL_INFOS("Messaging") << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL;
- // add to IM panel, but do not bother the user
- gIMMgr->addMessage(
- session_id,
- from_id,
- name,
- buffer,
- LLStringUtil::null,
- dialog,
- parent_estate_id,
- region_id,
- position,
- true);
- }
- else if (from_id.isNull())
- {
- LLSD args;
- args["MESSAGE"] = message;
- LLNotificationsUtil::add("SystemMessage", args);
- }
- else if (to_id.isNull())
- {
- // Message to everyone from GOD
- args["NAME"] = name;
- args["MESSAGE"] = message;
- LLNotificationsUtil::add("GodMessage", args);
- // Treat like a system message and put in chat history.
- // Claim to be from a local agent so it doesn't go into
- // console.
- chat.mText = name + separator_string + message;
- LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat", LLSD());
- if(nearby_chat)
- {
- nearby_chat->addMessage(chat);
- }
- }
- else
- {
- // standard message, not from system
- std::string saved;
- if(offline == IM_OFFLINE)
- {
- saved = llformat("(Saved %s) ", formatted_time(timestamp).c_str());
- }
- buffer = saved + message;
- LL_INFOS("Messaging") << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL;
- bool mute_im = is_muted;
- if(accept_im_from_only_friend&&!is_friend)
- {
- mute_im = true;
- }
- if (!mute_im || is_linden)
- {
- gIMMgr->addMessage(
- session_id,
- from_id,
- name,
- buffer,
- LLStringUtil::null,
- dialog,
- parent_estate_id,
- region_id,
- position,
- true);
- }
- else
- {
- /*
- EXT-5099
- currently there is no way to store in history only...
- using LLNotificationsUtil::add will add message to Nearby Chat
- // muted user, so don't start an IM session, just record line in chat
- // history. Pretend the chat is from a local agent,
- // so it will go into the history but not be shown on screen.
- LLSD args;
- args["MESSAGE"] = buffer;
- LLNotificationsUtil::add("SystemMessageTip", args);
- */
- }
- }
- break;
- case IM_TYPING_START:
- {
- LLPointer<LLIMInfo> im_info = new LLIMInfo(gMessageSystem);
- gIMMgr->processIMTypingStart(im_info);
- }
- break;
- case IM_TYPING_STOP:
- {
- LLPointer<LLIMInfo> im_info = new LLIMInfo(gMessageSystem);
- gIMMgr->processIMTypingStop(im_info);
- }
- break;
- case IM_MESSAGEBOX:
- {
- // This is a block, modeless dialog.
- //*TODO: Translate
- args["MESSAGE"] = message;
- LLNotificationsUtil::add("SystemMessageTip", args);
- }
- break;
- case IM_GROUP_NOTICE:
- case IM_GROUP_NOTICE_REQUESTED:
- {
- LL_INFOS("Messaging") << "Received IM_GROUP_NOTICE message." << LL_ENDL;
- // Read the binary bucket for more information.
- struct notice_bucket_header_t
- {
- U8 has_inventory;
- U8 asset_type;
- LLUUID group_id;
- };
- struct notice_bucket_full_t
- {
- struct notice_bucket_header_t header;
- U8 item_name[DB_INV_ITEM_NAME_BUF_SIZE];
- }* notice_bin_bucket;
- // Make sure the binary bucket is big enough to hold the header
- // and a null terminated item name.
- if ( (binary_bucket_size < (S32)((sizeof(notice_bucket_header_t) + sizeof(U8))))
- || (binary_bucket[binary_bucket_size - 1] != ' ') )
- {
- LL_WARNS("Messaging") << "Malformed group notice binary bucket" << LL_ENDL;
- break;
- }
- notice_bin_bucket = (struct notice_bucket_full_t*) &binary_bucket[0];
- U8 has_inventory = notice_bin_bucket->header.has_inventory;
- U8 asset_type = notice_bin_bucket->header.asset_type;
- LLUUID group_id = notice_bin_bucket->header.group_id;
- std::string item_name = ll_safe_string((const char*) notice_bin_bucket->item_name);
- // If there is inventory, give the user the inventory offer.
- LLOfferInfo* info = NULL;
- if (has_inventory)
- {
- info = new LLOfferInfo();
-
- info->mIM = IM_GROUP_NOTICE;
- info->mFromID = from_id;
- info->mFromGroup = from_group;
- info->mTransactionID = session_id;
- info->mType = (LLAssetType::EType) asset_type;
- info->mFolderID = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(info->mType));
- std::string from_name;
- from_name += "A group member named ";
- from_name += name;
- info->mFromName = from_name;
- info->mDesc = item_name;
- info->mHost = msg->getSender();
- }
-
- std::string str(message);
- // Tokenize the string.
- // TODO: Support escaped tokens ("||" -> "|")
- typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
- boost::char_separator<char> sep("|","",boost::keep_empty_tokens);
- tokenizer tokens(str, sep);
- tokenizer::iterator iter = tokens.begin();
- std::string subj(*iter++);
- std::string mes(*iter++);
- // Send the notification down the new path.
- // For requested notices, we don't want to send the popups.
- if (dialog != IM_GROUP_NOTICE_REQUESTED)
- {
- LLSD payload;
- payload["subject"] = subj;
- payload["message"] = mes;
- payload["sender_name"] = name;
- payload["group_id"] = group_id;
- payload["inventory_name"] = item_name;
- payload["inventory_offer"] = info ? info->asLLSD() : LLSD();
- LLSD args;
- args["SUBJECT"] = subj;
- args["MESSAGE"] = mes;
- LLNotifications::instance().add(LLNotification::Params("GroupNotice").substitutions(args).payload(payload).time_stamp(timestamp));
- }
- // Also send down the old path for now.
- if (IM_GROUP_NOTICE_REQUESTED == dialog)
- {
-
- LLPanelGroup::showNotice(subj,mes,group_id,has_inventory,item_name,info);
- }
- else
- {
- delete info;
- }
- }
- break;
- case IM_GROUP_INVITATION:
- {
- //if (!is_linden && (is_busy || is_muted))
- if ((is_busy || is_muted))
- {
- LLMessageSystem *msg = gMessageSystem;
- busy_message(msg,from_id);
- }
- else
- {
- LL_INFOS("Messaging") << "Received IM_GROUP_INVITATION message." << LL_ENDL;
- // Read the binary bucket for more information.
- struct invite_bucket_t
- {
- S32 membership_fee;
- LLUUID role_id;
- }* invite_bucket;
- // Make sure the binary bucket is the correct size.
- if (binary_bucket_size != sizeof(invite_bucket_t))
- {
- LL_WARNS("Messaging") << "Malformed group invite binary bucket" << LL_ENDL;
- break;
- }
- invite_bucket = (struct invite_bucket_t*) &binary_bucket[0];
- S32 membership_fee = ntohl(invite_bucket->membership_fee);
- LLSD payload;
- payload["transaction_id"] = session_id;
- payload["group_id"] = from_id;
- payload["name"] = name;
- payload["message"] = message;
- payload["fee"] = membership_fee;
- LLSD args;
- args["MESSAGE"] = message;
- LLNotificationsUtil::add("JoinGroup", args, payload, join_group_response);
- }
- }
- break;
- case IM_INVENTORY_OFFERED:
- case IM_TASK_INVENTORY_OFFERED:
- // Someone has offered us some inventory.
- {
- LLOfferInfo* info = new LLOfferInfo;
- if (IM_INVENTORY_OFFERED == dialog)
- {
- struct offer_agent_bucket_t
- {
- S8 asset_type;
- LLUUID object_id;
- }* bucketp;
- if (sizeof(offer_agent_bucket_t) != binary_bucket_size)
- {
- LL_WARNS("Messaging") << "Malformed inventory offer from agent" << LL_ENDL;
- delete info;
- break;
- }
- bucketp = (struct offer_agent_bucket_t*) &binary_bucket[0];
- info->mType = (LLAssetType::EType) bucketp->asset_type;
- info->mObjectID = bucketp->object_id;
- }
- else
- {
- if (sizeof(S8) != binary_bucket_size)
- {
- LL_WARNS("Messaging") << "Malformed inventory offer from object" << LL_ENDL;
- delete info;
- break;
- }
- info->mType = (LLAssetType::EType) binary_bucket[0];
- info->mObjectID = LLUUID::null;
- }
- info->mIM = dialog;
- info->mFromID = from_id;
- info->mFromGroup = from_group;
- info->mTransactionID = session_id;
- info->mFolderID = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(info->mType));
- if (dialog == IM_TASK_INVENTORY_OFFERED)
- {
- info->mFromObject = TRUE;
- }
- else
- {
- info->mFromObject = FALSE;
- }
- info->mFromName = name;
- info->mDesc = message;
- info->mHost = msg->getSender();
- //if (((is_busy && !is_owned_by_me) || is_muted))
- if (is_muted)
- {
- // Prefetch the offered item so that it can be discarded by the appropriate observer. (EXT-4331)
- LLInventoryFetchObserver::item_ref_t items;
- items.push_back(info->mObjectID);
- LLInventoryFetchObserver* fetch_item = new LLInventoryFetchObserver();
- fetch_item->fetchItems(items);
- delete fetch_item;
- // Same as closing window
- info->forceResponse(IOR_DECLINE);
- }
- else
- {
- inventory_offer_handler(info);
- }
- }
- break;
- case IM_INVENTORY_ACCEPTED:
- {
- args["NAME"] = name;
- LLSD payload;
- payload["from_id"] = from_id;
- LLNotificationsUtil::add("InventoryAccepted", args, payload);
- break;
- }
- case IM_INVENTORY_DECLINED:
- {
- args["NAME"] = name;
- LLSD payload;
- payload["from_id"] = from_id;
- LLNotificationsUtil::add("InventoryDeclined", args, payload);
- break;
- }
- // TODO: _DEPRECATED suffix as part of vote removal - DEV-24856
- case IM_GROUP_VOTE:
- {
- LL_WARNS("Messaging") << "Received IM: IM_GROUP_VOTE_DEPRECATED" << LL_ENDL;
- }
- break;
- case IM_GROUP_ELECTION_DEPRECATED:
- {
- LL_WARNS("Messaging") << "Received IM: IM_GROUP_ELECTION_DEPRECATED" << LL_ENDL;
- }
- break;
-
- case IM_SESSION_SEND:
- {
- if (!is_linden && is_busy)
- {
- return;
- }
- // Only show messages if we have a session open (which
- // should happen after you get an "invitation"
- if ( !gIMMgr->hasSession(session_id) )
- {
- return;
- }
- // standard message, not from system
- std::string saved;
- if(offline == IM_OFFLINE)
- {
- saved = llformat("(Saved %s) ", formatted_time(timestamp).c_str());
- }
- buffer = saved + message;
- BOOL is_this_agent = FALSE;
- if(from_id == gAgentID)
- {
- is_this_agent = TRUE;
- }
- gIMMgr->addMessage(
- session_id,
- from_id,
- name,
- buffer,
- ll_safe_string((char*)binary_bucket),
- IM_SESSION_INVITE,
- parent_estate_id,
- region_id,
- position,
- true);
- }
- break;
- case IM_FROM_TASK:
- {
- if (is_busy && !is_owned_by_me)
- {
- return;
- }
- // Build a link to open the object IM info window.
- std::string location = ll_safe_string((char*)binary_bucket, binary_bucket_size-1);
- if (session_id.notNull())
- {
- chat.mFromID = session_id;
- }
- else
- {
- // This message originated on a region without the updated code for task id and slurl information.
- // We just need a unique ID for this object that isn't the owner ID.
- // If it is the owner ID it will overwrite the style that contains the link to that owner's profile.
- // This isn't ideal - it will make 1 style for all objects owned by the the same person/group.
- // This works because the only thing we can really do in this case is show the owner name and link to their profile.
- chat.mFromID = from_id ^ gAgent.getSessionID();
- }
- if(SYSTEM_FROM == name)
- {
- // System's UUID is NULL (fixes EXT-4766)
- chat.mFromID = from_id = LLUUID::null;
- }
- LLSD query_string;
- query_string["owner"] = from_id;
- query_string["slurl"] = location;
- query_string["name"] = name;
- if (from_group)
- {
- query_string["groupowned"] = "true";
- }
- std::ostringstream link;
- link << "secondlife:///app/objectim/" << session_id << LLURI::mapToQueryString(query_string);
- chat.mURL = link.str();
- chat.mText = message;
- chat.mSourceType = CHAT_SOURCE_OBJECT;
- // Note: lie to Nearby Chat, pretending that this is NOT an IM, because
- // IMs from obejcts don't open IM sessions.
- LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat", LLSD());
- if(nearby_chat)
- {
- LLSD args;
- args["owner_id"] = from_id;
- args["slurl"] = location;
- nearby_chat->addMessage(chat, true, args);
- }
- //Object IMs send with from name: 'Second Life' need to be displayed also in notification toasts (EXT-1590)
- if (SYSTEM_FROM != name) break;
-
- LLSD substitutions;
- substitutions["NAME"] = name;
- substitutions["MSG"] = message;
- LLSD payload;
- payload["object_id"] = session_id;
- payload["owner_id"] = from_id;
- payload["from_id"] = from_id;
- payload["slurl"] = location;
- payload["name"] = name;
- std::string session_name;
- gCacheName->getFullName(from_id, session_name);
- payload["SESSION_NAME"] = session_name;
- if (from_group)
- {
- payload["group_owned"] = "true";
- }
- LLNotificationsUtil::add("ServerObjectMessage", substitutions, payload);
- }
- break;
- case IM_FROM_TASK_AS_ALERT:
- if (is_busy && !is_owned_by_me)
- {
- return;
- }
- {
- // Construct a viewer alert for this message.
- args["NAME"] = name;
- args["MESSAGE"] = message;
- LLNotificationsUtil::add("ObjectMessage", args);
- }
- break;
- case IM_BUSY_AUTO_RESPONSE:
- if (is_muted)
- {
- LL_DEBUGS("Messaging") << "Ignoring busy response from " << from_id << LL_ENDL;
- return;
- }
- else
- {
- // TODO: after LLTrans hits release, get "busy response" into translatable file
- buffer = llformat("%s (%s): %s", name.c_str(), "busy response", message.c_str());
- gIMMgr->addMessage(session_id, from_id, name, buffer);
- }
- break;
-
- case IM_LURE_USER:
- {
- if (is_muted)
- {
- return;
- }
- else if (is_busy)
- {
- busy_message(msg,from_id);
- }
- else
- {
- LLSD args;
- // *TODO: Translate -> [FIRST] [LAST] (maybe)
- args["NAME"] = name;
- args["MESSAGE"] = message;
- LLSD payload;
- payload["from_id"] = from_id;
- payload["lure_id"] = session_id;
- payload["godlike"] = FALSE;
- LLNotificationsUtil::add("TeleportOffered", args, payload);
- }
- }
- break;
- case IM_GODLIKE_LURE_USER:
- {
- LLSD payload;
- payload["from_id"] = from_id;
- payload["lure_id"] = session_id;
- payload["godlike"] = TRUE;
- // do not show a message box, because you're about to be
- // teleported.
- LLNotifications::instance().forceResponse(LLNotification::Params("TeleportOffered").payload(payload), 0);
- }
- break;
- case IM_GOTO_URL:
- {
- LLSD args;
- // n.b. this is for URLs sent by the system, not for
- // URLs sent by scripts (i.e. llLoadURL)
- if (binary_bucket_size <= 0)
- {
- LL_WARNS("Messaging") << "bad binary_bucket_size: "
- << binary_bucket_size
- << " - aborting function." << LL_ENDL;
- return;
- }
- std::string url;
-
- url.assign((char*)binary_bucket, binary_bucket_size-1);
- args["MESSAGE"] = message;
- args["URL"] = url;
- LLSD payload;
- payload["url"] = url;
- LLNotificationsUtil::add("GotoURL", args, payload );
- }
- break;
- case IM_FRIENDSHIP_OFFERED:
- {
- LLSD payload;
- payload["from_id"] = from_id;
- payload["session_id"] = session_id;;
- payload["online"] = (offline == IM_ONLINE);
- payload["sender"] = msg->getSender().getIPandPort();
- if (is_busy)
- {
- busy_message(msg, from_id);
- LLNotifications::instance().forceResponse(LLNotification::Params("OfferFriendship").payload(payload), 1);
- }
- else if (is_muted)
- {
- LLNotifications::instance().forceResponse(LLNotification::Params("OfferFriendship").payload(payload), 1);
- }
- else
- {
- args["[NAME]"] = name;
- if(message.empty())
- {
- //support for frienship offers from clients before July 2008
- LLNotificationsUtil::add("OfferFriendshipNoMessage", args, payload);
- }
- else
- {
- args["[MESSAGE]"] = message;
- LLNotificationsUtil::add("OfferFriendship", args, payload);
- }
- }
- }
- break;
- case IM_FRIENDSHIP_ACCEPTED:
- {
- // In the case of an offline IM, the formFriendship() may be extraneous
- // as the database should already include the relationship. But it
- // doesn't hurt for dupes.
- LLAvatarTracker::formFriendship(from_id);
-
- std::vector<std::string> strings;
- strings.push_back(from_id.asString());
- send_generic_message("requestonlinenotification", strings);
-
- args["NAME"] = name;
- LLSD payload;
- payload["from_id"] = from_id;
- LLNotificationsUtil::add("FriendshipAccepted", args, payload);
- }
- break;
- case IM_FRIENDSHIP_DECLINED_DEPRECATED:
- default:
- LL_WARNS("Messaging") << "Instant message calling for unknown dialog "
- << (S32)dialog << LL_ENDL;
- break;
- }
- LLWindow* viewer_window = gViewerWindow->getWindow();
- if (viewer_window && viewer_window->getMinimized())
- {
- viewer_window->flashIcon(5.f);
- }
- }
- void busy_message (LLMessageSystem* msg, LLUUID from_id)
- {
- if (gAgent.getBusy())
- {
- std::string my_name;
- LLAgentUI::buildFullname(my_name);
- std::string response = gSavedPerAccountSettings.getString("BusyModeResponse2");
- pack_instant_message(
- gMessageSystem,
- gAgent.getID(),
- FALSE,
- gAgent.getSessionID(),
- from_id,
- my_name,
- response,
- IM_ONLINE,
- IM_BUSY_AUTO_RESPONSE);
- gAgent.sendReliableMessage();
- }
- }
- bool callingcard_offer_callback(const LLSD& notification, const LLSD& response)
- {
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- LLUUID fid;
- LLUUID from_id;
- LLMessageSystem* msg = gMessageSystem;
- switch(option)
- {
- case 0:
- // accept
- msg->newMessageFast(_PREHASH_AcceptCallingCard);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->nextBlockFast(_PREHASH_TransactionBlock);
- msg->addUUIDFast(_PREHASH_TransactionID, notification["payload"]["transaction_id"].asUUID());
- fid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD);
- msg->nextBlockFast(_PREHASH_FolderData);
- msg->addUUIDFast(_PREHASH_FolderID, fid);
- msg->sendReliable(LLHost(notification["payload"]["sender"].asString()));
- break;
- case 1:
- // decline
- msg->newMessageFast(_PREHASH_DeclineCallingCard);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->nextBlockFast(_PREHASH_TransactionBlock);
- msg->addUUIDFast(_PREHASH_TransactionID, notification["payload"]["transaction_id"].asUUID());
- msg->sendReliable(LLHost(notification["payload"]["sender"].asString()));
- busy_message(msg, notification["payload"]["source_id"].asUUID());
- break;
- default:
- // close button probably, possibly timed out
- break;
- }
- return false;
- }
- static LLNotificationFunctorRegistration callingcard_offer_cb_reg("OfferCallingCard", callingcard_offer_callback);
- void process_offer_callingcard(LLMessageSystem* msg, void**)
- {
- // someone has offered to form a friendship
- LL_DEBUGS("Messaging") << "callingcard offer" << LL_ENDL;
- LLUUID source_id;
- msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, source_id);
- LLUUID tid;
- msg->getUUIDFast(_PREHASH_AgentBlock, _PREHASH_TransactionID, tid);
- LLSD payload;
- payload["transaction_id"] = tid;
- payload["source_id"] = source_id;
- payload["sender"] = msg->getSender().getIPandPort();
- LLViewerObject* source = gObjectList.findObject(source_id);
- LLSD args;
- std::string source_name;
- if(source && source->isAvatar())
- {
- LLNameValue* nvfirst = source->getNVPair("FirstName");
- LLNameValue* nvlast = source->getNVPair("LastName");
- if (nvfirst && nvlast)
- {
- args["FIRST"] = nvfirst->getString();
- args["LAST"] = nvlast->getString();
- source_name = std::string(nvfirst->getString()) + " " + nvlast->getString();
- }
- }
- if(!source_name.empty())
- {
- if (gAgent.getBusy()
- || LLMuteList::getInstance()->isMuted(source_id, source_name, LLMute::flagTextChat))
- {
- // automatically decline offer
- LLNotifications::instance().forceResponse(LLNotification::Params("OfferCallingCard").payload(payload), 1);
- }
- else
- {
- LLNotificationsUtil::add("OfferCallingCard", args, payload);
- }
- }
- else
- {
- LL_WARNS("Messaging") << "Calling card offer from an unknown source." << LL_ENDL;
- }
- }
- void process_accept_callingcard(LLMessageSystem* msg, void**)
- {
- LLNotificationsUtil::add("CallingCardAccepted");
- }
- void process_decline_callingcard(LLMessageSystem* msg, void**)
- {
- LLNotificationsUtil::add("CallingCardDeclined");
- }
- void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
- {
- LLChat chat;
- std::string mesg;
- std::string from_name;
- U8 source_temp;
- U8 type_temp;
- U8 audible_temp;
- LLColor4 color(1.0f, 1.0f, 1.0f, 1.0f);
- LLUUID from_id;
- LLUUID owner_id;
- BOOL is_owned_by_me = FALSE;
- LLViewerObject* chatter;
- msg->getString("ChatData", "FromName", from_name);
- chat.mFromName = from_name;
-
- msg->getUUID("ChatData", "SourceID", from_id);
- chat.mFromID = from_id;
-
- // Object owner for objects
- msg->getUUID("ChatData", "OwnerID", owner_id);
- msg->getU8Fast(_PREHASH_ChatData, _PREHASH_SourceType, source_temp);
- chat.mSourceType = (EChatSourceType)source_temp;
- msg->getU8("ChatData", "ChatType", type_temp);
- chat.mChatType = (EChatType)type_temp;
- msg->getU8Fast(_PREHASH_ChatData, _PREHASH_Audible, audible_temp);
- chat.mAudible = (EChatAudible)audible_temp;
-
- chat.mTime = LLFrameTimer::getElapsedSeconds();
-
- BOOL is_busy = gAgent.getBusy();
- BOOL is_muted = FALSE;
- BOOL is_linden = FALSE;
- is_muted = LLMuteList::getInstance()->isMuted(
- from_id,
- from_name,
- LLMute::flagTextChat)
- || LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagTextChat);
- is_linden = chat.mSourceType != CHAT_SOURCE_OBJECT &&
- LLMuteList::getInstance()->isLinden(from_name);
- BOOL is_audible = (CHAT_AUDIBLE_FULLY == chat.mAudible);
- chatter = gObjectList.findObject(from_id);
- if (chatter)
- {
- chat.mPosAgent = chatter->getPositionAgent();
- // Make swirly things only for talking objects. (not script debug messages, though)
- if (chat.mSourceType == CHAT_SOURCE_OBJECT
- && chat.mChatType != CHAT_TYPE_DEBUG_MSG)
- {
- LLPointer<LLViewerPartSourceChat> psc = new LLViewerPartSourceChat(chatter->getPositionAgent());
- psc->setSourceObject(chatter);
- psc->setColor(color);
- //We set the particles to be owned by the object's owner,
- //just in case they should be muted by the mute list
- psc->setOwnerUUID(owner_id);
- LLViewerPartSim::getInstance()->addPartSource(psc);
- }
- // record last audible utterance
- if (is_audible
- && (is_linden || (!is_muted && !is_busy)))
- {
- if (chat.mChatType != CHAT_TYPE_START
- && chat.mChatType != CHAT_TYPE_STOP)
- {
- gAgent.heardChat(chat.mFromID);
- }
- }
- is_owned_by_me = chatter->permYouOwner();
- }
- if (is_audible)
- {
- BOOL visible_in_chat_bubble = FALSE;
- std::string verb;
- color.setVec(1.f,1.f,1.f,1.f);
- msg->getStringFast(_PREHASH_ChatData, _PREHASH_Message, mesg);
- BOOL ircstyle = FALSE;
- // Look for IRC-style emotes here so chatbubbles work
- std::string prefix = mesg.substr(0, 4);
- if (prefix == "/me " || prefix == "/me'")
- {
- ircstyle = TRUE;
- }
- chat.mText = mesg;
- // Look for the start of typing so we can put "..." in the bubbles.
- if (CHAT_TYPE_START == chat.mChatType)
- {
- LLLocalSpeakerMgr::getInstance()->setSpeakerTyping(from_id, TRUE);
- // Might not have the avatar constructed yet, eg on login.
- if (chatter && chatter->isAvatar())
- {
- ((LLVOAvatar*)chatter)->startTyping();
- }
- return;
- }
- else if (CHAT_TYPE_STOP == chat.mChatType)
- {
- LLLocalSpeakerMgr::getInstance()->setSpeakerTyping(from_id, FALSE);
- // Might not have the avatar constructed yet, eg on login.
- if (chatter && chatter->isAvatar())
- {
- ((LLVOAvatar*)chatter)->stopTyping();
- }
- return;
- }
- // Look for IRC-style emotes
- if (ircstyle)
- {
- // set CHAT_STYLE_IRC to avoid adding Avatar Name as author of message. See EXT-656
- chat.mChatStyle = CHAT_STYLE_IRC;
- // Do nothing, ircstyle is fixed above for chat bubbles
- }
- else
- {
- switch(chat.mChatType)
- {
- case CHAT_TYPE_WHISPER:
- verb = LLTrans::getString("whisper") + " ";
- break;
- case CHAT_TYPE_DEBUG_MSG:
- case CHAT_TYPE_OWNER:
- case CHAT_TYPE_NORMAL:
- verb = "";
- break;
- case CHAT_TYPE_SHOUT:
- verb = LLTrans::getString("shout") + " ";
- break;
- case CHAT_TYPE_START:
- case CHAT_TYPE_STOP:
- LL_WARNS("Messaging") << "Got chat type start/stop in main chat processing." << LL_ENDL;
- break;
- default:
- LL_WARNS("Messaging") << "Unknown type " << chat.mChatType << " in chat!" << LL_ENDL;
- verb = "";
- break;
- }
- chat.mText = "";
- chat.mText += verb;
- chat.mText += mesg;
- }
-
- // We have a real utterance now, so can stop showing "..." and proceed.
- if (chatter && chatter->isAvatar())
- {
- LLLocalSpeakerMgr::getInstance()->setSpeakerTyping(from_id, FALSE);
- ((LLVOAvatar*)chatter)->stopTyping();
-
- if (!is_muted && !is_busy)
- {
- visible_in_chat_bubble = gSavedSettings.getBOOL("UseChatBubbles");
- std::string formated_msg = "";
- LLViewerChat::formatChatMsg(chat, formated_msg);
- LLChat chat_bubble = chat;
- chat_bubble.mText = formated_msg;
- ((LLVOAvatar*)chatter)->addChat(chat_bubble);
- }
- }
-
- if (chatter)
- {
- chat.mPosAgent = chatter->getPositionAgent();
- }
- // truth table:
- // LINDEN BUSY MUTED OWNED_BY_YOU TASK DISPLAY STORE IN HISTORY
- // F F F F * Yes Yes
- // F F F T * Yes Yes
- // F F T F * No No
- // F F T T * No No
- // F T F F * No Yes
- // F T F T * Yes Yes
- // F T T F * No No
- // F T T T * No No
- // T * * * F Yes Yes
- chat.mMuted = is_muted && !is_linden;
- // pass owner_id to chat so that we can display the remote
- // object inspect for an object that is chatting with you
- LLSD args;
- args["type"] = LLNotificationsUI::NT_NEARBYCHAT;
- args["owner_id"] = owner_id;
- LLNotificationsUI::LLNotificationManager::instance().onChat(chat, args);
- }
- }
- // Simulator we're on is informing the viewer that the agent
- // is starting to teleport (perhaps to another sim, perhaps to the
- // same sim). If we initiated the teleport process by sending some kind
- // of TeleportRequest, then this info is redundant, but if the sim
- // initiated the teleport (via a script call, being killed, etc.)
- // then this info is news to us.
- void process_teleport_start(LLMessageSystem *msg, void**)
- {
- U32 teleport_flags = 0x0;
- msg->getU32("Info", "TeleportFlags", teleport_flags);
- if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL)
- {
- gViewerWindow->setProgressCancelButtonVisible(FALSE);
- }
- else
- {
- gViewerWindow->setProgressCancelButtonVisible(TRUE, LLTrans::getString("Cancel"));
- }
- // Freeze the UI and show progress bar
- // Note: could add data here to differentiate between normal teleport and death.
- if( gAgent.getTeleportState() == LLAgent::TELEPORT_NONE )
- {
- gTeleportDisplay = TRUE;
- gAgent.setTeleportState( LLAgent::TELEPORT_START );
- make_ui_sound("UISndTeleportOut");
-
- // Don't call LLFirstUse::useTeleport here because this could be
- // due to being killed, which would send you home, not to a Telehub
- }
- }
- void process_teleport_progress(LLMessageSystem* msg, void**)
- {
- LLUUID agent_id;
- msg->getUUID("AgentData", "AgentID", agent_id);
- if((gAgent.getID() != agent_id)
- || (gAgent.getTeleportState() == LLAgent::TELEPORT_NONE))
- {
- LL_WARNS("Messaging") << "Unexpected teleport progress message." << LL_ENDL;
- return;
- }
- U32 teleport_flags = 0x0;
- msg->getU32("Info", "TeleportFlags", teleport_flags);
- if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL)
- {
- gViewerWindow->setProgressCancelButtonVisible(FALSE);
- }
- else
- {
- gViewerWindow->setProgressCancelButtonVisible(TRUE, LLTrans::getString("Cancel"));
- }
- std::string buffer;
- msg->getString("Info", "Message", buffer);
- LL_DEBUGS("Messaging") << "teleport progress: " << buffer << LL_ENDL;
- //Sorta hacky...default to using simulator raw messages
- //if we don't find the coresponding mapping in our progress mappings
- std::string message = buffer;
- if (LLAgent::sTeleportProgressMessages.find(buffer) !=
- LLAgent::sTeleportProgressMessages.end() )
- {
- message = LLAgent::sTeleportProgressMessages[buffer];
- }
- gAgent.setTeleportMessage(LLAgent::sTeleportProgressMessages[message]);
- }
- class LLFetchInWelcomeArea : public LLInventoryFetchDescendentsObserver
- {
- public:
- LLFetchInWelcomeArea() {}
- virtual void done()
- {
- LLIsType is_landmark(LLAssetType::AT_LANDMARK);
- LLIsType is_card(LLAssetType::AT_CALLINGCARD);
- LLInventoryModel::cat_array_t card_cats;
- LLInventoryModel::item_array_t card_items;
- LLInventoryModel::cat_array_t land_cats;
- LLInventoryModel::item_array_t land_items;
- folder_ref_t::iterator it = mCompleteFolders.begin();
- folder_ref_t::iterator end = mCompleteFolders.end();
- for(; it != end; ++it)
- {
- gInventory.collectDescendentsIf(
- (*it),
- land_cats,
- land_items,
- LLInventoryModel::EXCLUDE_TRASH,
- is_landmark);
- gInventory.collectDescendentsIf(
- (*it),
- card_cats,
- card_items,
- LLInventoryModel::EXCLUDE_TRASH,
- is_card);
- }
- LLSD args;
- if ( land_items.count() > 0 )
- { // Show notification that they can now teleport to landmarks. Use a random landmark from the inventory
- S32 random_land = ll_rand( land_items.count() - 1 );
- args["NAME"] = land_items[random_land]->getName();
- LLNotificationsUtil::add("TeleportToLandmark",args);
- }
- if ( card_items.count() > 0 )
- { // Show notification that they can now contact people. Use a random calling card from the inventory
- S32 random_card = ll_rand( card_items.count() - 1 );
- args["NAME"] = card_items[random_card]->getName();
- LLNotificationsUtil::add("TeleportToPerson",args);
- }
- gInventory.removeObserver(this);
- delete this;
- }
- };
- class LLPostTeleportNotifiers : public LLEventTimer
- {
- public:
- LLPostTeleportNotifiers();
- virtual ~LLPostTeleportNotifiers();
- //function to be called at the supplied frequency
- virtual BOOL tick();
- };
- LLPostTeleportNotifiers::LLPostTeleportNotifiers() : LLEventTimer( 2.0 )
- {
- };
- LLPostTeleportNotifiers::~LLPostTeleportNotifiers()
- {
- }
- BOOL LLPostTeleportNotifiers::tick()
- {
- BOOL all_done = FALSE;
- if ( gAgent.getTeleportState() == LLAgent::TELEPORT_NONE )
- {
- // get callingcards and landmarks available to the user arriving.
- LLInventoryFetchDescendentsObserver::folder_ref_t folders;
- const LLUUID callingcard_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD);
- if(callingcard_id.notNull())
- folders.push_back(callingcard_id);
- const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK);
- if(folder_id.notNull())
- folders.push_back(folder_id);
- if(!folders.empty())
- {
- LLFetchInWelcomeArea* fetcher = new LLFetchInWelcomeArea;
- fetcher->fetchDescendents(folders);
- if(fetcher->isEverythingComplete())
- {
- fetcher->done();
- }
- else
- {
- gInventory.addObserver(fetcher);
- }
- }
- all_done = TRUE;
- }
- return all_done;
- }
- // Teleport notification from the simulator
- // We're going to pretend to be a new agent
- void process_teleport_finish(LLMessageSystem* msg, void**)
- {
- LL_DEBUGS("Messaging") << "Got teleport location message" << LL_ENDL;
- LLUUID agent_id;
- msg->getUUIDFast(_PREHASH_Info, _PREHASH_AgentID, agent_id);
- if (agent_id != gAgent.getID())
- {
- LL_WARNS("Messaging") << "Got teleport notification for wrong agent!" << LL_ENDL;
- return;
- }
- // Do teleport effect for where you're leaving
- // VEFFECT: TeleportStart
- LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE);
- effectp->setPositionGlobal(gAgent.getPositionGlobal());
- effectp->setColor(LLColor4U(gAgent.getEffectColor()));
- LLHUDManager::getInstance()->sendEffects();
- U32 location_id;
- U32 sim_ip;
- U16 sim_port;
- LLVector3 pos, look_at;
- U64 region_handle;
- msg->getU32Fast(_PREHASH_Info, _PREHASH_LocationID, location_id);
- msg->getIPAddrFast(_PREHASH_Info, _PREHASH_SimIP, sim_ip);
- msg->getIPPortFast(_PREHASH_Info, _PREHASH_SimPort, sim_port);
- //msg->getVector3Fast(_PREHASH_Info, _PREHASH_Position, pos);
- //msg->getVector3Fast(_PREHASH_Info, _PREHASH_LookAt, look_at);
- msg->getU64Fast(_PREHASH_Info, _PREHASH_RegionHandle, region_handle);
- U32 teleport_flags;
- msg->getU32Fast(_PREHASH_Info, _PREHASH_TeleportFlags, teleport_flags);
-
-
- std::string seedCap;
- msg->getStringFast(_PREHASH_Info, _PREHASH_SeedCapability, seedCap);
- // update home location if we are teleporting out of prelude - specific to teleporting to welcome area
- if((teleport_flags & TELEPORT_FLAGS_SET_HOME_TO_TARGET)
- && (!gAgent.isGodlike()))
- {
- gAgent.setHomePosRegion(region_handle, pos);
- // Create a timer that will send notices when teleporting is all finished. Since this is
- // based on the LLEventTimer class, it will be managed by that class and not orphaned or leaked.
- new LLPostTeleportNotifiers();
- }
- LLHost sim_host(sim_ip, sim_port);
- // Viewer trusts the simulator.
- gMessageSystem->enableCircuit(sim_host, TRUE);
- LLViewerRegion* regionp = LLWorld::getInstance()->addRegion(region_handle, sim_host);
- /*
- // send camera update to new region
- gAgent.updateCamera();
- // likewise make sure the camera is behind the avatar
- gAgent.resetView(TRUE);
- LLVector3 shift_vector = regionp->getPosRegionFromGlobal(gAgent.getRegion()->getOriginGlobal());
- gAgent.setRegion(regionp);
- gObjectList.shiftObjects(shift_vector);
- if (gAgent.getAvatarObject())
- {
- gAgent.getAvatarObject()->clearChatText();
- gAgent.slamLookAt(look_at);
- }
- gAgent.setPositionAgent(pos);
- gAssetStorage->setUpstream(sim);
- gCacheName->setUpstream(sim);
- */
- // now, use the circuit info to tell simulator about us!
- LL_INFOS("Messaging") << "process_teleport_finish() Enabling "
- << sim_host << " with code " << msg->mOurCircuitCode << LL_ENDL;
- msg->newMessageFast(_PREHASH_UseCircuitCode);
- msg->nextBlockFast(_PREHASH_CircuitCode);
- msg->addU32Fast(_PREHASH_Code, msg->getOurCircuitCode());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->addUUIDFast(_PREHASH_ID, gAgent.getID());
- msg->sendReliable(sim_host);
- send_complete_agent_movement(sim_host);
- gAgent.setTeleportState( LLAgent::TELEPORT_MOVING );
- gAgent.setTeleportMessage(LLAgent::sTeleportProgressMessages["contacting"]);
- regionp->setSeedCapability(seedCap);
- // Don't send camera updates to the new region until we're
- // actually there...
- // Now do teleport effect for where you're going.
- // VEFFECT: TeleportEnd
- effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE);
- effectp->setPositionGlobal(gAgent.getPositionGlobal());
- effectp->setColor(LLColor4U(gAgent.getEffectColor()));
- LLHUDManager::getInstance()->sendEffects();
- // gTeleportDisplay = TRUE;
- // gTeleportDisplayTimer.reset();
- // gViewerWindow->setShowProgress(TRUE);
- }
- // stuff we have to do every time we get an AvatarInitComplete from a sim
- /*
- void process_avatar_init_complete(LLMessageSystem* msg, void**)
- {
- LLVector3 agent_pos;
- msg->getVector3Fast(_PREHASH_AvatarData, _PREHASH_Position, agent_pos);
- agent_movement_complete(msg->getSender(), agent_pos);
- }
- */
- void process_agent_movement_complete(LLMessageSystem* msg, void**)
- {
- gAgentMovementCompleted = true;