llviewermessage.cpp

Go to the documentation of this file.
00001 
00032 #include "llviewerprecompiledheaders.h"
00033 
00034 #include "llviewermessage.h"
00035 
00036 #include <deque>
00037 
00038 #include "audioengine.h" 
00039 #include "indra_constants.h"
00040 #include "lscript_byteformat.h"
00041 #include "mean_collision_data.h"
00042 #include "llfloaterbump.h"
00043 #include "llassetstorage.h"
00044 #include "llcachename.h"
00045 #include "llchat.h"
00046 #include "lldbstrings.h"
00047 #include "lleconomy.h"
00048 #include "llfilepicker.h"
00049 #include "llfocusmgr.h"
00050 #include "llfollowcamparams.h"
00051 #include "llfloaterreleasemsg.h"
00052 #include "llinstantmessage.h"
00053 #include "llquantize.h"
00054 #include "llregionflags.h"
00055 #include "llregionhandle.h"
00056 #include "llsdserialize.h"
00057 #include "llstring.h"
00058 #include "llteleportflags.h"
00059 #include "lltracker.h"
00060 #include "lltransactionflags.h"
00061 #include "llxfermanager.h"
00062 #include "message.h"
00063 #include "sound_ids.h"
00064 #include "lltimer.h"
00065 #include "llmd5.h"
00066 
00067 #include "llagent.h"
00068 #include "llcallingcard.h"
00069 #include "llconsole.h"
00070 #include "llvieweraudio.h"
00071 #include "llviewercontrol.h"
00072 #include "lldrawpool.h"
00073 #include "llfirstuse.h"
00074 #include "llfloateractivespeakers.h"
00075 #include "llfloaterbuycurrency.h"
00076 #include "llfloaterbuyland.h"
00077 #include "llfloaterchat.h"
00078 #include "llfloatergroupinfo.h"
00079 #include "llfloaterimagepreview.h"
00080 #include "llfloaterland.h"
00081 #include "llfloaterregioninfo.h"
00082 #include "llfloaterlandholdings.h"
00083 #include "llfloatermap.h"
00084 #include "llurldispatcher.h"
00085 #include "llfloatermute.h"
00086 #include "llfloaterpostcard.h"
00087 #include "llfloaterpreference.h"
00088 #include "llfloaterreleasemsg.h"
00089 #include "llfollowcam.h"
00090 #include "llgroupnotify.h"
00091 #include "llhudeffect.h"
00092 #include "llhudeffecttrail.h"
00093 #include "llhudmanager.h"
00094 #include "llimpanel.h"
00095 #include "llinventorymodel.h"
00096 #include "llinventoryview.h"
00097 #include "llmenugl.h"
00098 #include "llmutelist.h"
00099 #include "llnetmap.h"
00100 #include "llnotify.h"
00101 #include "llpanelgrouplandmoney.h"
00102 #include "llselectmgr.h"
00103 #include "llstartup.h"
00104 #include "llsky.h"
00105 #include "llstatenums.h"
00106 #include "llstatusbar.h"
00107 #include "llimview.h"
00108 #include "lltool.h"
00109 #include "lltoolbar.h"
00110 #include "lltoolmgr.h"
00111 #include "llui.h"                       // for make_ui_sound
00112 #include "lluploaddialog.h"
00113 #include "llviewercamera.h"
00114 #include "llviewergenericmessage.h"
00115 #include "llviewerinventory.h"
00116 #include "llviewermenu.h"
00117 #include "llviewerobject.h"
00118 #include "llviewerobjectlist.h"
00119 #include "llviewerparcelmgr.h"
00120 #include "llviewerpartsource.h"
00121 #include "llviewerregion.h"
00122 #include "llviewerstats.h"
00123 #include "llviewertexteditor.h"
00124 #include "llviewerthrottle.h"
00125 #include "llviewerwindow.h"
00126 #include "llvlmanager.h"
00127 #include "llvoavatar.h"
00128 #include "llvotextbubble.h"
00129 #include "llweb.h"
00130 #include "llworld.h"
00131 #include "pipeline.h"
00132 #include "llappviewer.h"
00133 #include "llfloaterworldmap.h"
00134 #include "llkeythrottle.h"
00135 #include "llviewerdisplay.h"
00136 #include "llkeythrottle.h"
00137 
00138 #include <boost/tokenizer.hpp>
00139 
00140 #if LL_WINDOWS // For Windows specific error handler
00141 #include "llwindebug.h" // For the invalid message handler
00142 #endif
00143 
00144 //
00145 // Constants
00146 //
00147 const F32 BIRD_AUDIBLE_RADIUS = 32.0f;
00148 const F32 SIT_DISTANCE_FROM_TARGET = 0.25f;
00149 static const F32 LOGOUT_REPLY_TIME = 3.f;       // Wait this long after LogoutReply before quitting.
00150 
00151 // Determine how quickly residents' scripts can issue question dialogs
00152 // Allow bursts of up to 5 dialogs in 10 seconds. 10*2=20 seconds recovery if throttle kicks in
00153 static const U32 LLREQUEST_PERMISSION_THROTTLE_LIMIT    = 5;     // requests
00154 static const F32 LLREQUEST_PERMISSION_THROTTLE_INTERVAL = 10.0f; // seconds
00155 
00156 extern BOOL gDebugClicks;
00157 
00158 // function prototypes
00159 void open_offer(const std::vector<LLUUID>& items, const std::string& from_name);
00160 void friendship_offer_callback(S32 option, void* user_data);
00161 bool check_offer_throttle(const std::string& from_name, bool check_only);
00162 
00163 //inventory offer throttle globals
00164 LLFrameTimer gThrottleTimer;
00165 const U32 OFFER_THROTTLE_MAX_COUNT=5; //number of items per time period
00166 const F32 OFFER_THROTTLE_TIME=10.f; //time period in seconds
00167 
00168 //script permissions
00169 const LLString SCRIPT_QUESTIONS[SCRIPT_PERMISSION_EOF] = 
00170         { 
00171                 "ScriptTakeMoney",
00172                 "ActOnControlInputs",
00173                 "RemapControlInputs",
00174                 "AnimateYourAvatar",
00175                 "AttachToYourAvatar",
00176                 "ReleaseOwnership",
00177                 "LinkAndDelink",
00178                 "AddAndRemoveJoints",
00179                 "ChangePermissions",
00180                 "TrackYourCamera",
00181                 "ControlYourCamera"
00182         };
00183 
00184 struct LLFriendshipOffer
00185 {
00186         LLUUID mFromID;
00187         LLUUID mTransactionID;
00188         BOOL mOnline;
00189         LLHost mHost;
00190 };
00191 
00192 //const char BUSY_AUTO_RESPONSE[] =     "The Resident you messaged is in 'busy mode' which means they have "
00193 //                                                                      "requested not to be disturbed. Your message will still be shown in their IM "
00194 //                                                                      "panel for later viewing.";
00195 
00196 //
00197 // Functions
00198 //
00199 
00200 void give_money(const LLUUID& uuid, LLViewerRegion* region, S32 amount, BOOL is_group,
00201                                 S32 trx_type, const LLString& desc)
00202 {
00203         if(0 == amount) return;
00204         amount = abs(amount);
00205         LL_INFOS("Messaging") << "give_money(" << uuid << "," << amount << ")"<< LL_ENDL;
00206         if(can_afford_transaction(amount))
00207         {
00208 //              gStatusBar->debitBalance(amount);
00209                 LLMessageSystem* msg = gMessageSystem;
00210                 msg->newMessageFast(_PREHASH_MoneyTransferRequest);
00211                 msg->nextBlockFast(_PREHASH_AgentData);
00212                 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
00213         msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
00214                 msg->nextBlockFast(_PREHASH_MoneyData);
00215                 msg->addUUIDFast(_PREHASH_SourceID, gAgent.getID() );
00216                 msg->addUUIDFast(_PREHASH_DestID, uuid);
00217                 msg->addU8Fast(_PREHASH_Flags, pack_transaction_flags(FALSE, is_group));
00218                 msg->addS32Fast(_PREHASH_Amount, amount);
00219                 msg->addU8Fast(_PREHASH_AggregatePermNextOwner, (U8)LLAggregatePermissions::AP_EMPTY);
00220                 msg->addU8Fast(_PREHASH_AggregatePermInventory, (U8)LLAggregatePermissions::AP_EMPTY);
00221                 msg->addS32Fast(_PREHASH_TransactionType, trx_type );
00222                 msg->addStringFast(_PREHASH_Description, desc.c_str());
00223                 msg->sendReliable(region->getHost());
00224         }
00225         else
00226         {
00227                 LLFloaterBuyCurrency::buyCurrency("Giving", amount);
00228         }
00229 }
00230 
00231 void send_complete_agent_movement(const LLHost& sim_host)
00232 {
00233         LLMessageSystem* msg = gMessageSystem;
00234         msg->newMessageFast(_PREHASH_CompleteAgentMovement);
00235         msg->nextBlockFast(_PREHASH_AgentData);
00236         msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
00237         msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
00238         msg->addU32Fast(_PREHASH_CircuitCode, msg->mOurCircuitCode);
00239         msg->sendReliable(sim_host);
00240 }
00241 
00242 void process_logout_reply(LLMessageSystem* msg, void**)
00243 {
00244         // The server has told us it's ok to quit.
00245         LL_DEBUGS("Messaging") << "process_logout_reply" << LL_ENDL;
00246 
00247         LLUUID agent_id;
00248         msg->getUUID("AgentData", "AgentID", agent_id);
00249         LLUUID session_id;
00250         msg->getUUID("AgentData", "SessionID", session_id);
00251         if((agent_id != gAgent.getID()) || (session_id != gAgent.getSessionID()))
00252         {
00253                 LL_WARNS("Messaging") << "Bogus Logout Reply" << LL_ENDL;
00254         }
00255 
00256         LLInventoryModel::update_map_t parents;
00257         S32 count = msg->getNumberOfBlocksFast( _PREHASH_InventoryData );
00258         for(S32 i = 0; i < count; ++i)
00259         {
00260                 LLUUID item_id;
00261                 msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id, i);
00262 
00263                 if( (1 == count) && item_id.isNull() )
00264                 {
00265                         // Detect dummy item.  Indicates an empty list.
00266                         break;
00267                 }
00268 
00269                 // We do not need to track the asset ids, just account for an
00270                 // updated inventory version.
00271                 LL_INFOS("Messaging") << "process_logout_reply itemID=" << item_id << LL_ENDL;
00272                 LLInventoryItem* item = gInventory.getItem( item_id );
00273                 if( item )
00274                 {
00275                         parents[item->getParentUUID()] = 0;
00276                         gInventory.addChangedMask(LLInventoryObserver::INTERNAL, item_id);
00277                 }
00278                 else
00279                 {
00280                         LL_INFOS("Messaging") << "process_logout_reply item not found: " << item_id << LL_ENDL;
00281                 }
00282         }
00283     LLAppViewer::instance()->forceQuit();
00284 }
00285 
00286 void process_layer_data(LLMessageSystem *mesgsys, void **user_data)
00287 {
00288         LLViewerRegion *regionp = LLWorld::getInstance()->getRegion(mesgsys->getSender());
00289 
00290         if (!regionp || gNoRender)
00291         {
00292                 return;
00293         }
00294 
00295 
00296         S32 size;
00297         S8 type;
00298 
00299         mesgsys->getS8Fast(_PREHASH_LayerID, _PREHASH_Type, type);
00300         size = mesgsys->getSizeFast(_PREHASH_LayerData, _PREHASH_Data);
00301         if (0 == size)
00302         {
00303                 LL_WARNS("Messaging") << "Layer data has zero size." << LL_ENDL;
00304                 return;
00305         }
00306         if (size < 0)
00307         {
00308                 // getSizeFast() is probably trying to tell us about an error
00309                 LL_WARNS("Messaging") << "getSizeFast() returned negative result: "
00310                         << size
00311                         << LL_ENDL;
00312                 return;
00313         }
00314         U8 *datap = new U8[size];
00315         mesgsys->getBinaryDataFast(_PREHASH_LayerData, _PREHASH_Data, datap, size);
00316         LLVLData *vl_datap = new LLVLData(regionp, type, datap, size);
00317         if (mesgsys->getReceiveCompressedSize())
00318         {
00319                 gVLManager.addLayerData(vl_datap, mesgsys->getReceiveCompressedSize());
00320         }
00321         else
00322         {
00323                 gVLManager.addLayerData(vl_datap, mesgsys->getReceiveSize());
00324         }
00325 }
00326 
00327 S32 exported_object_count = 0;
00328 S32 exported_image_count = 0;
00329 S32 current_object_count = 0;
00330 S32 current_image_count = 0;
00331 
00332 extern LLNotifyBox *gExporterNotify;
00333 extern LLUUID gExporterRequestID;
00334 extern LLString gExportDirectory;
00335 
00336 extern LLUploadDialog *gExportDialog;
00337 
00338 LLString gExportedFile;
00339 
00340 std::map<LLUUID, LLString> gImageChecksums;
00341 
00342 void export_complete()
00343 {
00344                 LLUploadDialog::modalUploadFinished();
00345                 gExporterRequestID.setNull();
00346                 gExportDirectory = "";
00347 
00348                 LLFILE* fXML = LLFile::fopen(gExportedFile.c_str(), "rb");              /* Flawfinder: ignore */
00349                 fseek(fXML, 0, SEEK_END);
00350                 long length = ftell(fXML);
00351                 fseek(fXML, 0, SEEK_SET);
00352                 U8 *buffer = new U8[length + 1];
00353                 size_t nread = fread(buffer, 1, length, fXML);
00354                 if (nread < (size_t) length)
00355                 {
00356                         LL_WARNS("Messaging") << "Short read" << LL_ENDL;
00357                 }
00358                 buffer[nread] = '\0';
00359                 fclose(fXML);
00360 
00361                 char *pos = (char *)buffer;
00362                 while ((pos = strstr(pos+1, "<sl:image ")) != 0)
00363                 {
00364                         char *pos_check = strstr(pos, "checksum=\"");
00365 
00366                         if (pos_check)
00367                         {
00368                                 char *pos_uuid = strstr(pos_check, "\">");
00369 
00370                                 if (pos_uuid)
00371                                 {
00372                                         char image_uuid_str[UUID_STR_SIZE];             /* Flawfinder: ignore */
00373                                         memcpy(image_uuid_str, pos_uuid+2, UUID_STR_SIZE-1);            /* Flawfinder: ignore */
00374                                         image_uuid_str[UUID_STR_SIZE-1] = 0;
00375                                         
00376                                         LLUUID image_uuid(image_uuid_str);
00377 
00378                                         LL_INFOS("Messaging") << "Found UUID: " << image_uuid << LL_ENDL;
00379 
00380                                         std::map<LLUUID, LLString>::iterator itor = gImageChecksums.find(image_uuid);
00381                                         if (itor != gImageChecksums.end())
00382                                         {
00383                                                 LL_INFOS("Messaging") << "Replacing with checksum: " << itor->second << LL_ENDL;
00384                                                 if (itor->second.c_str() != NULL)
00385                                                         {
00386                                                                 memcpy(&pos_check[10], itor->second.c_str(), 32);               /* Flawfinder: ignore */
00387                                                         }
00388                                         }
00389                                 }
00390                         }
00391                 }
00392 
00393                 LLFILE* fXMLOut = LLFile::fopen(gExportedFile.c_str(), "wb");           /* Flawfinder: ignore */
00394                 if (fwrite(buffer, 1, length, fXMLOut) != length)
00395                 {
00396                         LL_WARNS("Messaging") << "Short write" << LL_ENDL;
00397                 }
00398                 fclose(fXMLOut);
00399 
00400                 delete [] buffer;
00401 }
00402 
00403 
00404 void exported_item_complete(const LLTSCode status, void *user_data)
00405 {
00406         //LLString *filename = (LLString *)user_data;
00407 
00408         if (status < LLTS_OK)
00409         {
00410                 LL_WARNS("Messaging") << "Export failed!" << LL_ENDL;
00411         }
00412         else
00413         {
00414                 ++current_object_count;
00415                 if (current_image_count == exported_image_count && current_object_count == exported_object_count)
00416                 {
00417                         LL_INFOS("Messaging") << "*** Export complete ***" << LL_ENDL;
00418 
00419                         export_complete();
00420                 }
00421                 else
00422                 {
00423                         gExportDialog->setMessage(llformat("Exported %d/%d object files, %d/%d textures.", current_object_count, exported_object_count, current_image_count, exported_image_count));
00424                 }
00425         }
00426 }
00427 
00428 struct exported_image_info
00429 {
00430         LLUUID image_id;
00431         LLString filename;
00432         U32 image_num;
00433 };
00434 
00435 void exported_j2c_complete(const LLTSCode status, void *user_data)
00436 {
00437         exported_image_info *info = (exported_image_info *)user_data;
00438         LLUUID image_id = info->image_id;
00439         U32 image_num = info->image_num;
00440         LLString filename = info->filename;
00441         delete info;
00442 
00443         if (status < LLTS_OK)
00444         {
00445                 LL_WARNS("Messaging") << "Image download failed!" << LL_ENDL;
00446         }
00447         else
00448         {
00449                 LLFILE* fIn = LLFile::fopen(filename.c_str(), "rb");            /* Flawfinder: ignore */
00450                 if (fIn) 
00451                 {
00452                         LLPointer<LLImageJ2C> ImageUtility = new LLImageJ2C;
00453                         LLPointer<LLImageTGA> TargaUtility = new LLImageTGA;
00454 
00455                         fseek(fIn, 0, SEEK_END);
00456                         S32 length = ftell(fIn);
00457                         fseek(fIn, 0, SEEK_SET);
00458                         U8 *buffer = ImageUtility->allocateData(length);
00459                         if (fread(buffer, 1, length, fIn) != length)
00460                         {
00461                                 LL_WARNS("Messaging") << "Short read" << LL_ENDL;
00462                         }
00463                         fclose(fIn);
00464                         LLFile::remove(filename.c_str());
00465 
00466                         // Convert to TGA
00467                         LLPointer<LLImageRaw> image = new LLImageRaw();
00468 
00469                         ImageUtility->updateData();
00470                         ImageUtility->decode(image, 100000.0f);
00471                         
00472                         TargaUtility->encode(image);
00473                         U8 *data = TargaUtility->getData();
00474                         S32 data_size = TargaUtility->getDataSize();
00475 
00476                         char *file_path = new char[filename.size()+1];
00477                         strcpy(file_path, filename.c_str());            /* Flawfinder: ignore */
00478                         char *end = strrchr(file_path, gDirUtilp->getDirDelimiter()[0]);
00479                         end[0] = 0;
00480                         LLString output_file = llformat("%s/image-%03d.tga", file_path, image_num);//filename;
00481                         delete [] file_path;
00482                         //S32 name_len = output_file.length();
00483                         //strcpy(&output_file[name_len-3], "tga");
00484                         LLFILE* fOut = LLFile::fopen(output_file.c_str(), "wb");                /* Flawfinder: ignore */
00485                         char md5_hash_string[33];               /* Flawfinder: ignore */
00486                         strcpy(md5_hash_string, "00000000000000000000000000000000");            /* Flawfinder: ignore */
00487                         if (fOut)
00488                         {
00489                                 if (fwrite(data, 1, data_size, fOut) != data_size)
00490                                 {
00491                                         LL_WARNS("Messaging") << "Short write" << LL_ENDL;
00492                                 }
00493                                 fseek(fOut, 0, SEEK_SET);
00494                                 fclose(fOut);
00495                                 fOut = LLFile::fopen(output_file.c_str(), "rb");                /* Flawfinder: ignore */
00496                                 LLMD5 my_md5_hash(fOut);
00497                                 my_md5_hash.hex_digest(md5_hash_string);
00498                         }
00499 
00500                         gImageChecksums.insert(std::pair<LLUUID, LLString>(image_id, md5_hash_string));
00501                 }
00502         }
00503 
00504         ++current_image_count;
00505         if (current_image_count == exported_image_count && current_object_count == exported_object_count)
00506         {
00507                 LL_INFOS("Messaging") << "*** Export textures complete ***" << LL_ENDL;
00508                         export_complete();
00509         }
00510         else
00511         {
00512                 gExportDialog->setMessage(llformat("Exported %d/%d object files, %d/%d textures.", current_object_count, exported_object_count, current_image_count, exported_image_count));
00513         }
00514 }
00515 
00516 void process_derez_ack(LLMessageSystem*, void**)
00517 {
00518         if(gViewerWindow) gViewerWindow->getWindow()->decBusyCount();
00519 }
00520 
00521 void process_places_reply(LLMessageSystem* msg, void** data)
00522 {
00523         LLUUID query_id;
00524 
00525         msg->getUUID("AgentData", "QueryID", query_id);
00526         if (query_id.isNull())
00527         {
00528                 LLFloaterLandHoldings::processPlacesReply(msg, data);
00529         }
00530         else if(gAgent.isInGroup(query_id))
00531         {
00532                 LLPanelGroupLandMoney::processPlacesReply(msg, data);
00533         }
00534         else
00535         {
00536                 LL_WARNS("Messaging") << "Got invalid PlacesReply message" << LL_ENDL;
00537         }
00538 }
00539 
00540 void send_sound_trigger(const LLUUID& sound_id, F32 gain)
00541 {
00542         if (sound_id.isNull())
00543         {
00544                 // zero guids don't get sent (no sound)
00545                 return;
00546         }
00547 
00548         LLMessageSystem* msg = gMessageSystem;
00549         msg->newMessageFast(_PREHASH_SoundTrigger);
00550         msg->nextBlockFast(_PREHASH_SoundData);
00551         msg->addUUIDFast(_PREHASH_SoundID, sound_id);
00552         // Client untrusted, ids set on sim
00553         msg->addUUIDFast(_PREHASH_OwnerID, LLUUID::null );
00554         msg->addUUIDFast(_PREHASH_ObjectID, LLUUID::null );
00555         msg->addUUIDFast(_PREHASH_ParentID, LLUUID::null );
00556 
00557         msg->addU64Fast(_PREHASH_Handle, gAgent.getRegion()->getHandle());
00558 
00559         LLVector3 position = gAgent.getPositionAgent();
00560         msg->addVector3Fast(_PREHASH_Position, position);
00561         msg->addF32Fast(_PREHASH_Gain, gain);
00562 
00563         gAgent.sendMessage();
00564 }
00565 
00566 struct LLJoinGroupData
00567 {
00568         LLUUID mGroupID;
00569         LLUUID mTransactionID;
00570         std::string mName;
00571         std::string mMessage;
00572         S32 mFee;
00573 };
00574 
00575 void join_group_callback(S32 option, void* user_data)
00576 {
00577         LLJoinGroupData* data = (LLJoinGroupData*)user_data;
00578         BOOL delete_context_data = TRUE;
00579         bool accept_invite = false;
00580 
00581         if (option == 2 && data && !data->mGroupID.isNull())
00582         {
00583                 LLFloaterGroupInfo::showFromUUID(data->mGroupID);
00584                 LLString::format_map_t args;
00585                 args["[MESSAGE]"] = data->mMessage;
00586                 LLNotifyBox::showXml("JoinGroup", args, &join_group_callback, data);
00587                 return;
00588         }
00589         if(option == 0 && data && !data->mGroupID.isNull())
00590         {
00591                 // check for promotion or demotion.
00592                 S32 max_groups = MAX_AGENT_GROUPS;
00593                 if(gAgent.isInGroup(data->mGroupID)) ++max_groups;
00594 
00595                 if(gAgent.mGroups.count() < max_groups)
00596                 {
00597                         accept_invite = true;
00598                 }
00599                 else
00600                 {
00601                         delete_context_data = FALSE;
00602                         LLString::format_map_t args;
00603                         args["[NAME]"] = data->mName;
00604                         args["[INVITE]"] = data->mMessage;
00605                         LLAlertDialog::showXml("JoinedTooManyGroupsMember", args, join_group_callback, (void*)data);
00606                 }
00607         }
00608 
00609         if (accept_invite)
00610         {
00611                 // If there is a fee to join this group, make
00612                 // sure the user is sure they want to join.
00613                 if (data->mFee > 0)
00614                 {
00615                         delete_context_data = FALSE;
00616                         LLString::format_map_t args;
00617                         args["[COST]"] = llformat("%d", data->mFee);
00618                         // Set the fee to 0, so that we don't keep
00619                         // asking about a fee.
00620                         data->mFee = 0;
00621                         gViewerWindow->alertXml("JoinGroupCanAfford",
00622                                                                         args,
00623                                                                         join_group_callback,
00624                                                                         (void*)data);
00625                 }
00626                 else
00627                 {
00628                         send_improved_im(data->mGroupID,
00629                                                         "name",
00630                                                         "message",
00631                                                         IM_ONLINE,
00632                                                         IM_GROUP_INVITATION_ACCEPT,
00633                                                         data->mTransactionID);
00634                 }
00635         }
00636         else if (data)
00637         {
00638                 send_improved_im(data->mGroupID,
00639                                                 "name",
00640                                                 "message",
00641                                                 IM_ONLINE,
00642                                                 IM_GROUP_INVITATION_DECLINE,
00643                                                 data->mTransactionID);
00644         }
00645 
00646         if(delete_context_data)
00647         {
00648                 delete data;
00649                 data = NULL;
00650         }
00651 }
00652 
00653 
00654 //-----------------------------------------------------------------------------
00655 // Instant Message
00656 //-----------------------------------------------------------------------------
00657 class LLOpenAgentOffer : public LLInventoryFetchObserver
00658 {
00659 public:
00660         LLOpenAgentOffer(const std::string& from_name) : mFromName(from_name) {}
00661         /*virtual*/ void done()
00662         {
00663                 open_offer(mComplete, mFromName);
00664                 gInventory.removeObserver(this);
00665                 delete this;
00666         }
00667 private:
00668         std::string mFromName;
00669 };
00670 
00671 //unlike the FetchObserver for AgentOffer, we only make one 
00672 //instance of the AddedObserver for TaskOffers
00673 //and it never dies.  We do this because we don't know the UUID of 
00674 //task offers until they are accepted, so we don't wouldn't 
00675 //know what to watch for, so instead we just watch for all additions. -Gigs
00676 class LLOpenTaskOffer : public LLInventoryAddedObserver
00677 {
00678 protected:
00679         /*virtual*/ void done()
00680         {
00681                 open_offer(mAdded, "");
00682                 mAdded.clear();
00683         }
00684  };
00685 
00686 //one global instance to bind them
00687 LLOpenTaskOffer* gNewInventoryObserver=NULL;
00688 
00689 void start_new_inventory_observer()
00690 {
00691         if (!gNewInventoryObserver) //task offer observer 
00692         {
00693                 // Observer is deleted by gInventory
00694                 gNewInventoryObserver = new LLOpenTaskOffer;
00695                 gInventory.addObserver(gNewInventoryObserver);
00696         }
00697 }
00698 
00699 class LLDiscardAgentOffer : public LLInventoryFetchComboObserver
00700 {
00701 public:
00702         LLDiscardAgentOffer(const LLUUID& folder_id, const LLUUID& object_id) :
00703                 mFolderID(folder_id),
00704                 mObjectID(object_id) {}
00705         virtual ~LLDiscardAgentOffer() {}
00706         virtual void done()
00707         {
00708                 LL_DEBUGS("Messaging") << "LLDiscardAgentOffer::done()" << LL_ENDL;
00709                 LLUUID trash_id;
00710                 trash_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_TRASH);
00711                 bool notify = false;
00712                 if(trash_id.notNull() && mObjectID.notNull())
00713                 {
00714                         LLInventoryModel::update_list_t update;
00715                         LLInventoryModel::LLCategoryUpdate old_folder(mFolderID, -1);
00716                         update.push_back(old_folder);
00717                         LLInventoryModel::LLCategoryUpdate new_folder(trash_id, 1);
00718                         update.push_back(new_folder);
00719                         gInventory.accountForUpdate(update);
00720                         gInventory.moveObject(mObjectID, trash_id);
00721                         LLInventoryObject* obj = gInventory.getObject(mObjectID);
00722                         if(obj)
00723                         {
00724                                 // no need to restamp since this is already a freshly
00725                                 // stamped item.
00726                                 obj->updateParentOnServer(FALSE);
00727                                 notify = true;
00728                         }
00729                 }
00730                 else
00731                 {
00732                         LL_WARNS("Messaging") << "DiscardAgentOffer unable to find: "
00733                                         << (trash_id.isNull() ? "trash " : "")
00734                                         << (mObjectID.isNull() ? "object" : "") << LL_ENDL;
00735                 }
00736                 gInventory.removeObserver(this);
00737                 if(notify)
00738                 {
00739                         gInventory.notifyObservers();
00740                 }
00741                 delete this;
00742         }
00743 protected:
00744         LLUUID mFolderID;
00745         LLUUID mObjectID;
00746 };
00747 
00748 
00749 //Returns TRUE if we are OK, FALSE if we are throttled
00750 //Set check_only true if you want to know the throttle status 
00751 //without registering a hit -Gigs
00752 bool check_offer_throttle(const std::string& from_name, bool check_only)
00753 {
00754         static U32 throttle_count;
00755         static bool throttle_logged;
00756         LLChat chat;
00757         LLString log_message;
00758 
00759         if (!gSavedSettings.getBOOL("ShowNewInventory"))
00760                 return false;
00761 
00762         if (check_only)
00763         {
00764                 return gThrottleTimer.hasExpired();
00765         }
00766         
00767         if(gThrottleTimer.checkExpirationAndReset(OFFER_THROTTLE_TIME))
00768         {
00769                 LL_DEBUGS("Messaging") << "Throttle Expired" << LL_ENDL;
00770                 throttle_count=1;
00771                 throttle_logged=false;
00772                 return true;
00773         }
00774         else //has not expired
00775         {
00776                 LL_DEBUGS("Messaging") << "Throttle Not Expired, Count: " << throttle_count << LL_ENDL;
00777                 // When downloading the initial inventory we get a lot of new items
00778                 // coming in and can't tell that from spam.  JC
00779                 if (LLStartUp::getStartupState() >= STATE_STARTED
00780                         && throttle_count >= OFFER_THROTTLE_MAX_COUNT)
00781                 {
00782                         if (!throttle_logged)
00783                         {
00784                                 // Use the name of the last item giver, who is probably the person
00785                                 // spamming you. JC
00786                                 std::ostringstream message;
00787                                 message << LLAppViewer::instance()->getSecondLifeTitle();
00788                                 if (!from_name.empty())
00789                                 {
00790                                         message << ": Items coming in too fast from " << from_name;
00791                                 }
00792                                 else
00793                                 {
00794                                         message << ": Items coming in too fast";
00795                                 }
00796                                 message << ", automatic preview disabled for "
00797                                         << OFFER_THROTTLE_TIME << " seconds.";
00798                                 chat.mText = message.str();
00799                                 //this is kinda important, so actually put it on screen
00800                                 LLFloaterChat::addChat(chat, FALSE, FALSE);
00801                                 throttle_logged=true;
00802                         }
00803                         return false;
00804                 }
00805                 else
00806                 {
00807                         throttle_count++;
00808                         return true;
00809                 }
00810         }
00811 }
00812  
00813 void open_offer(const std::vector<LLUUID>& items, const std::string& from_name)
00814 {
00815         std::vector<LLUUID>::const_iterator it = items.begin();
00816         std::vector<LLUUID>::const_iterator end = items.end();
00817         LLUUID trash_id(gInventory.findCategoryUUIDForType(LLAssetType::AT_TRASH));
00818         LLInventoryItem* item;
00819         for(; it != end; ++it)
00820         {
00821                 item = gInventory.getItem(*it);
00822                 if(!item)
00823                 {
00824                         LL_WARNS("Messaging") << "Unable to show inventory item: " << *it << LL_ENDL;
00825                         continue;
00826                 }
00827                 if(gInventory.isObjectDescendentOf(*it, trash_id))
00828                 {
00829                         continue;
00830                 }
00831                 //if we are throttled, don't display them - Gigs
00832                 if (check_offer_throttle(from_name, false))
00833                 {
00834                         // I'm not sure this is a good idea.  JC
00835                         bool show_keep_discard = item->getPermissions().getCreator() != gAgent.getID();
00836                         //bool show_keep_discard = true;
00837                         switch(item->getType())
00838                         {
00839                         case LLAssetType::AT_NOTECARD:
00840                                 open_notecard((LLViewerInventoryItem*)item, LLString("Note: ") + item->getName(), LLUUID::null, show_keep_discard, LLUUID::null, FALSE);
00841                                 break;
00842                         case LLAssetType::AT_LANDMARK:
00843                                 open_landmark((LLViewerInventoryItem*)item, LLString("Landmark: ") + item->getName(), show_keep_discard, LLUUID::null, FALSE);
00844                                 break;
00845                         case LLAssetType::AT_TEXTURE:
00846                                 open_texture(*it, LLString("Texture: ") + item->getName(), show_keep_discard, LLUUID::null, FALSE);
00847                                 break;
00848                         default:
00849                                 break;
00850                         }
00851                 }
00852                 //highlight item, if it's not in the trash or lost+found
00853                 
00854                 // Don't auto-open the inventory floater
00855                 LLInventoryView* view = LLInventoryView::getActiveInventory();
00856                 if(!view)
00857                 {
00858                         return;
00859                 }
00860 
00861                 //Trash Check
00862                 LLUUID trash_id;
00863                 trash_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_TRASH);
00864                 if(gInventory.isObjectDescendentOf(item->getUUID(), trash_id))
00865                 {
00866                         return;
00867                 }
00868                 LLUUID lost_and_found_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_LOST_AND_FOUND);
00869                 //BOOL inventory_has_focus = gFocusMgr.childHasKeyboardFocus(view);
00870                 BOOL user_is_away = gAwayTimer.getStarted();
00871 
00872                 // don't select lost and found items if the user is active
00873                 if (gInventory.isObjectDescendentOf(item->getUUID(), lost_and_found_id)
00874                         && !user_is_away)
00875                 {
00876                         return;
00877                 }
00878 
00879                 //Not sure about this check.  Could make it easy to miss incoming items. -Gigs
00880                 //don't dick with highlight while the user is working
00881                 //if(inventory_has_focus && !user_is_away)
00882                 //      break;
00883                 LL_DEBUGS("Messaging") << "Highlighting" << item->getUUID()  << LL_ENDL;
00884                 //highlight item
00885 
00886                 LLUICtrl* focus_ctrl = gFocusMgr.getKeyboardFocus();
00887                 view->getPanel()->setSelection(item->getUUID(), TAKE_FOCUS_NO);
00888                 gFocusMgr.setKeyboardFocus(focus_ctrl);
00889         }
00890 }
00891 
00892 void inventory_offer_mute_callback(const LLUUID& blocked_id,
00893                                                                    const char* first_name,
00894                                                                    const char* last_name,
00895                                                                    BOOL is_group,
00896                                                                    void* user_data)
00897 {
00898         LLString from_name;
00899         LLMute::EType type;
00900 
00901         if (is_group)
00902         {
00903                 type = LLMute::GROUP;
00904                 from_name = first_name;
00905         }
00906         else
00907         {
00908                 type = LLMute::AGENT;
00909                 from_name += first_name;
00910                 from_name += " ";
00911                 from_name += last_name;
00912         }
00913 
00914         LLMute mute(blocked_id, from_name, type);
00915         if (LLMuteList::getInstance()->add(mute))
00916         {
00917                 LLFloaterMute::showInstance();
00918                 LLFloaterMute::getInstance()->selectMute(blocked_id);
00919         }
00920 
00921         // purge the message queue of any previously queued inventory offers from the same source.
00922         class OfferMatcher : public LLNotifyBoxView::Matcher
00923         {
00924         public:
00925                 OfferMatcher(const LLUUID& to_block) : blocked_id(to_block) {}
00926                 BOOL matches(LLNotifyBox::notify_callback_t callback, void* cb_data) const
00927                 {
00928                         return callback == inventory_offer_callback && ((LLOfferInfo*)cb_data)->mFromID == blocked_id;
00929                 }
00930         private:
00931                 const LLUUID& blocked_id;
00932         };
00933         gNotifyBoxView->purgeMessagesMatching(OfferMatcher(blocked_id));
00934 }
00935 
00936 void inventory_offer_callback(S32 button, void* user_data)
00937  {
00938         LLChat chat;
00939         LLString log_message;
00940         LLOfferInfo* info = (LLOfferInfo*)user_data;
00941         if(!info) return;
00942 
00943         // For muting, we need to add the mute, then decline the offer.
00944         // This must be done here because:
00945         // * callback may be called immediately,
00946         // * adding the mute sends a message,
00947         // * we can't build two messages at once.  JC
00948         if (2 == button)
00949         {
00950                 gCacheName->get(info->mFromID, info->mFromGroup, inventory_offer_mute_callback, user_data);
00951         }
00952 
00953         LLMessageSystem* msg = gMessageSystem;
00954         msg->newMessageFast(_PREHASH_ImprovedInstantMessage);
00955         msg->nextBlockFast(_PREHASH_AgentData);
00956         msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
00957         msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
00958         msg->nextBlockFast(_PREHASH_MessageBlock);
00959         msg->addBOOLFast(_PREHASH_FromGroup, FALSE);
00960         msg->addUUIDFast(_PREHASH_ToAgentID, info->mFromID);
00961         msg->addU8Fast(_PREHASH_Offline, IM_ONLINE);
00962         msg->addUUIDFast(_PREHASH_ID, info->mTransactionID);
00963         msg->addU32Fast(_PREHASH_Timestamp, NO_TIMESTAMP); // no timestamp necessary
00964         std::string name;
00965         gAgent.buildFullname(name);
00966         msg->addStringFast(_PREHASH_FromAgentName, name);
00967         msg->addStringFast(_PREHASH_Message, ""); 
00968         msg->addU32Fast(_PREHASH_ParentEstateID, 0);
00969         msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null);
00970         msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent());
00971         LLInventoryObserver* opener = NULL;
00972         LLViewerInventoryCategory* catp = NULL;
00973         catp = (LLViewerInventoryCategory*)gInventory.getCategory(info->mObjectID);
00974         LLViewerInventoryItem* itemp = NULL;
00975         if(!catp)
00976         {
00977                 itemp = (LLViewerInventoryItem*)gInventory.getItem(info->mObjectID);
00978         }
00979 
00980         // *TODO:translate
00981         LLString from_string; // Used in the pop-up.
00982         LLString chatHistory_string;  // Used in chat history.
00983         if (info->mFromObject == TRUE)
00984         {
00985                 if (info->mFromGroup)
00986                 {
00987                         std::string group_name;
00988                         if (gCacheName->getGroupName(info->mFromID, group_name))
00989                         {
00990                                 from_string = LLString("An object named '") + info->mFromName + "' owned by the group '" + group_name + "'";
00991                                 chatHistory_string = info->mFromName + " owned by the group '" + group_name + "'";
00992                         }
00993                         else
00994                         {
00995                                 from_string = LLString("An object named '") + info->mFromName + "' owned by an unknown group";
00996                                 chatHistory_string = info->mFromName + " owned by an unknown group";
00997                         }
00998                 }
00999                 else
01000                 {
01001                         std::string first_name, last_name;
01002                         if (gCacheName->getName(info->mFromID, first_name, last_name))
01003                         {
01004                                 from_string = LLString("An object named '") + info->mFromName + "' owned by " + first_name + " " + last_name;
01005                                 chatHistory_string = info->mFromName + " owned by " + first_name + " " + last_name;
01006                         }
01007                         else
01008                         {
01009                                 from_string = LLString("An object named '") + info->mFromName + "' owned by an unknown user";
01010                                 chatHistory_string = info->mFromName + " owned by an unknown user";
01011                         }
01012                 }
01013         }
01014         else
01015         {
01016                 from_string = chatHistory_string = info->mFromName;
01017         }
01018         
01019         bool busy=FALSE;
01020         
01021         switch(button)
01022         {
01023         case IOR_ACCEPT:
01024                 // ACCEPT. The math for the dialog works, because the accept
01025                 // for inventory_offered, task_inventory_offer or
01026                 // group_notice_inventory is 1 greater than the offer integer value.
01027                 // Generates IM_INVENTORY_ACCEPTED, IM_TASK_INVENTORY_ACCEPTED, 
01028                 // or IM_GROUP_NOTICE_INVENTORY_ACCEPTED
01029                 msg->addU8Fast(_PREHASH_Dialog, (U8)(info->mIM + 1));
01030                 msg->addBinaryDataFast(_PREHASH_BinaryBucket, &(info->mFolderID.mData),
01031                                          sizeof(info->mFolderID.mData));
01032                 // send the message
01033                 msg->sendReliable(info->mHost);
01034 
01035                 //don't spam them if they are getting flooded
01036                 if (check_offer_throttle(info->mFromName, true))
01037                 {
01038                         log_message = chatHistory_string + " gave you " + info->mDesc + ".";
01039                         chat.mText = log_message;
01040                         LLFloaterChat::addChatHistory(chat);
01041                 }
01042 
01043                 // we will want to open this item when it comes back.
01044                 LL_DEBUGS("Messaging") << "Initializing an opener for tid: " << info->mTransactionID
01045                                  << LL_ENDL;
01046                 switch (info->mIM)
01047                 {
01048                 case IM_INVENTORY_OFFERED:
01049                 {
01050                         // This is an offer from an agent. In this case, the back
01051                         // end has already copied the items into your inventory,
01052                         // so we can fetch it out of our inventory.
01053                         LLInventoryFetchObserver::item_ref_t items;
01054                         items.push_back(info->mObjectID);
01055                         LLOpenAgentOffer* open_agent_offer = new LLOpenAgentOffer(from_string);
01056                         open_agent_offer->fetchItems(items);
01057                         if(catp || (itemp && itemp->isComplete()))
01058                         {
01059                                 open_agent_offer->done();
01060                         }
01061                         else
01062                         {
01063                                 opener = open_agent_offer;
01064                         }
01065                 }
01066                         break;
01067                 case IM_TASK_INVENTORY_OFFERED:
01068                 case IM_GROUP_NOTICE:
01069                 case IM_GROUP_NOTICE_REQUESTED:
01070                 {
01071                         // This is an offer from a task or group.
01072                         // We don't use a new instance of an opener
01073                         // We instead use the singular observer gOpenTaskOffer
01074                         // Since it already exists, we don't need to actually do anything
01075                 }
01076                 break;
01077                 default:
01078                         LL_WARNS("Messaging") << "inventory_offer_callback: unknown offer type" << LL_ENDL;
01079                         break;
01080                 }       // end switch (info->mIM)
01081                 break;
01082 
01083         case IOR_BUSY:
01084                 //Busy falls through to decline.  Says to make busy message.
01085                 busy=TRUE;
01086         case IOR_MUTE:
01087                 // MUTE falls through to decline
01088         case IOR_DECLINE:
01089                 // DECLINE. The math for the dialog works, because the decline
01090                 // for inventory_offered, task_inventory_offer or
01091                 // group_notice_inventory is 2 greater than the offer integer value.
01092                 // Generates IM_INVENTORY_DECLINED, IM_TASK_INVENTORY_DECLINED,
01093                 // or IM_GROUP_NOTICE_INVENTORY_DECLINED
01094         default:
01095                 // close button probably (or any of the fall-throughs from above)
01096                 msg->addU8Fast(_PREHASH_Dialog, (U8)(info->mIM + 2));
01097                 msg->addBinaryDataFast(_PREHASH_BinaryBucket, EMPTY_BINARY_BUCKET, EMPTY_BINARY_BUCKET_SIZE);
01098                 // send the message
01099                 msg->sendReliable(info->mHost);
01100 
01101                 log_message = "You decline " + info->mDesc + " from " + info->mFromName + ".";
01102                 chat.mText = log_message;
01103                 if( LLMuteList::getInstance()->isMuted(info->mFromID ) && ! LLMuteList::getInstance()->isLinden(info->mFromName) )  // muting for SL-42269
01104                 {
01105                         chat.mMuted = TRUE;
01106                 }
01107                 LLFloaterChat::addChatHistory(chat);
01108 
01109                 // If it's from an agent, we have to fetch the item to throw
01110                 // it away. If it's from a task or group, just denying the 
01111                 // request will suffice to discard the item.
01112                 if(IM_INVENTORY_OFFERED == info->mIM)
01113                 {
01114                         LLInventoryFetchComboObserver::folder_ref_t folders;
01115                         LLInventoryFetchComboObserver::item_ref_t items;
01116                         items.push_back(info->mObjectID);
01117                         LLDiscardAgentOffer* discard_agent_offer;
01118                         discard_agent_offer = new LLDiscardAgentOffer(info->mFolderID, info->mObjectID);
01119                         discard_agent_offer->fetch(folders, items);
01120                         if(catp || (itemp && itemp->isComplete()))
01121                         {
01122                                 discard_agent_offer->done();
01123                         }
01124                         else
01125                         {
01126                                 opener = discard_agent_offer;
01127                         }
01128                         
01129                 }
01130                 if (busy &&     (!info->mFromGroup && !info->mFromObject))
01131                 {
01132                         busy_message(msg,info->mFromID);
01133                 }
01134                 break;
01135         }
01136 
01137         if(opener)
01138         {
01139                 gInventory.addObserver(opener);
01140         }
01141 
01142         delete info;
01143         info = NULL;
01144 
01145         // Allow these to stack up, but once you deal with one, reset the
01146         // position.
01147         gFloaterView->resetStartingFloaterPosition();
01148 }
01149 
01150 
01151 void inventory_offer_handler(LLOfferInfo* info, BOOL from_task)
01152 {
01153         //Until throttling is implmented, busy mode should reject inventory instead of silently
01154         //accepting it.  SEE SL-39554
01155         if (gAgent.getBusy())
01156         {
01157                 inventory_offer_callback(IOR_BUSY, info);
01158                 return;
01159         }
01160         
01161         //If muted, don't even go through the messaging stuff.  Just curtail the offer here.
01162         if (LLMuteList::getInstance()->isMuted(info->mFromID, info->mFromName))
01163         {
01164                 inventory_offer_callback(IOR_MUTE, info);
01165                 return;
01166         }
01167 
01168         // Avoid the Accept/Discard dialog if the user so desires. JC
01169         if (gSavedSettings.getBOOL("AutoAcceptNewInventory")
01170                 && (info->mType == LLAssetType::AT_NOTECARD
01171                         || info->mType == LLAssetType::AT_LANDMARK
01172                         || info->mType == LLAssetType::AT_TEXTURE))
01173         {
01174                 // For certain types, just accept the items into the inventory,
01175                 // and possibly open them on receipt depending upon "ShowNewInventory".
01176                 inventory_offer_callback(IOR_ACCEPT, info);
01177                 return;
01178         }
01179 
01180         LLString::format_map_t args;
01181         args["[OBJECTNAME]"] = info->mDesc;
01182         // must protect against a NULL return from lookupHumanReadable()
01183         std::string typestr = ll_safe_string(LLAssetType::lookupHumanReadable(info->mType));
01184         if (!typestr.empty())
01185         {
01186                 args["[OBJECTTYPE]"] = typestr;
01187         }
01188         else
01189         {
01190                 LL_WARNS("Messaging") << "LLAssetType::lookupHumanReadable() returned NULL - probably bad asset type: " << info->mType << LL_ENDL;
01191                 args["[OBJECTTYPE]"] = "";
01192 
01193                 // This seems safest, rather than propagating bogosity
01194                 LL_WARNS("Messaging") << "Forcing an inventory-decline for probably-bad asset type." << LL_ENDL;
01195                 inventory_offer_callback(IOR_DECLINE, info);
01196                 return;
01197         }
01198 
01199         // Name cache callbacks don't store userdata, so can't save
01200         // off the LLOfferInfo.  Argh.  JC
01201         BOOL name_found = FALSE;
01202         if (info->mFromGroup)
01203         {
01204                 std::string group_name;
01205                 if (gCacheName->getGroupName(info->mFromID, group_name))
01206                 {
01207                         args["[FIRST]"] = group_name;
01208                         args["[LAST]"] = "";
01209                         name_found = TRUE;
01210                 }
01211         }
01212         else
01213         {
01214                 std::string first_name, last_name;
01215                 if (gCacheName->getName(info->mFromID, first_name, last_name))
01216                 {
01217                         args["[FIRST]"] = first_name;
01218                         args["[LAST]"] = last_name;
01219                         name_found = TRUE;
01220                 }
01221         }
01222         if (from_task)
01223         {
01224                 args["[OBJECTFROMNAME]"] = info->mFromName;
01225                 LLNotifyBox::showXml(name_found ? "ObjectGiveItem" : "ObjectGiveItemUnknownUser",
01226                                                         args, &inventory_offer_callback, (void*)info);
01227         }
01228         else
01229         {
01230                 // *TODO:translate -> [FIRST] [LAST]
01231                 args["[NAME]"] = info->mFromName;
01232                 LLNotifyBox::showXml("UserGiveItem", args,
01233                                                         &inventory_offer_callback, (void*)info);
01234         }
01235 }
01236 
01237 
01238 void group_vote_callback(S32 option, void *userdata)
01239 {
01240         LLUUID *group_id = (LLUUID *)userdata;
01241         if (!group_id) return;
01242 
01243         switch(option)
01244         {
01245         case 0:
01246                 // Vote Now
01247                 // Open up the voting tab
01248                 LLFloaterGroupInfo::showFromUUID(*group_id, "voting_tab");
01249                 break;
01250         default:
01251                 // Vote Later or
01252                 // close button
01253                 break;
01254         }
01255         delete group_id;
01256         group_id = NULL;
01257 }
01258 
01259 struct LLLureInfo
01260 {
01261         LLLureInfo(const LLUUID& from, const LLUUID& lure_id, BOOL godlike) :
01262                 mFromID(from),
01263                 mLureID(lure_id),
01264                 mGodlike(godlike)
01265         {}
01266 
01267         LLUUID mFromID;
01268         LLUUID mLureID;
01269         BOOL mGodlike;
01270 };
01271 
01272 void lure_callback(S32 option, void* user_data)
01273 {
01274         LLLureInfo* info = (LLLureInfo*)user_data;
01275         if(!info) return;
01276         switch(option)
01277         {
01278         case 0:
01279                 {
01280                         // accept
01281                         gAgent.teleportViaLure(info->mLureID, info->mGodlike);
01282                 }
01283                 break;
01284         case 1:
01285         default:
01286                 // decline
01287                 send_simple_im(info->mFromID,
01288                                            "",
01289                                            IM_LURE_DECLINED,
01290                                            info->mLureID);
01291                 break;
01292         }
01293         delete info;
01294         info = NULL;
01295 }
01296 
01297 void goto_url_callback(S32 option, void* user_data)
01298 {
01299         char* url = (char*)user_data;
01300         if(1 == option)
01301         {
01302                 LLWeb::loadURL(url);
01303         }
01304         delete[] url;
01305 }
01306 
01307 void process_improved_im(LLMessageSystem *msg, void **user_data)
01308 {
01309         if (gNoRender)
01310         {
01311                 return;
01312         }
01313         LLUUID from_id;
01314         BOOL from_group;
01315         LLUUID to_id;
01316         U8 offline;
01317         U8 d = 0;
01318         LLUUID session_id;
01319         U32 t;
01320         char name[DB_FULL_NAME_BUF_SIZE];               /* Flawfinder: ignore */
01321         char message[DB_IM_MSG_BUF_SIZE];               /* Flawfinder: ignore */
01322         U32 parent_estate_id = 0;
01323         LLUUID region_id;
01324         LLVector3 position;
01325         char buffer[DB_IM_MSG_BUF_SIZE * 2];            /* Flawfinder: ignore */
01326         U8 binary_bucket[MTUBYTES];
01327         S32 binary_bucket_size;
01328         LLChat chat;
01329 
01330         // *TODO:translate - need to fix the full name to first/last (maybe)
01331         msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, from_id);
01332         msg->getBOOLFast(_PREHASH_MessageBlock, _PREHASH_FromGroup, from_group);
01333         msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_ToAgentID, to_id);
01334         msg->getU8Fast(  _PREHASH_MessageBlock, _PREHASH_Offline, offline);
01335         msg->getU8Fast(  _PREHASH_MessageBlock, _PREHASH_Dialog, d);
01336         msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_ID, session_id);
01337         msg->getU32Fast( _PREHASH_MessageBlock, _PREHASH_Timestamp, t);
01338         //msg->getData("MessageBlock", "Count",         &count);
01339         msg->getStringFast(_PREHASH_MessageBlock, _PREHASH_FromAgentName, DB_FULL_NAME_BUF_SIZE, name);
01340         msg->getStringFast(_PREHASH_MessageBlock, _PREHASH_Message,             DB_IM_MSG_BUF_SIZE, message);
01341         msg->getU32Fast(_PREHASH_MessageBlock, _PREHASH_ParentEstateID, parent_estate_id);
01342         msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_RegionID, region_id);
01343         msg->getVector3Fast(_PREHASH_MessageBlock, _PREHASH_Position, position);
01344         msg->getBinaryDataFast(  _PREHASH_MessageBlock, _PREHASH_BinaryBucket, binary_bucket, 0, 0, MTUBYTES);
01345         binary_bucket_size = msg->getSizeFast(_PREHASH_MessageBlock, _PREHASH_BinaryBucket);
01346         EInstantMessage dialog = (EInstantMessage)d;
01347         time_t timestamp = (time_t)t;
01348 
01349         BOOL is_busy = gAgent.getBusy();
01350         BOOL is_muted = LLMuteList::getInstance()->isMuted(from_id, name, LLMute::flagTextChat);
01351         BOOL is_linden = LLMuteList::getInstance()->isLinden(name);
01352         BOOL is_owned_by_me = FALSE;
01353         
01354         chat.mMuted = is_muted && !is_linden;
01355         chat.mFromID = from_id;
01356         chat.mFromName = name;
01357         chat.mSourceType = (from_id.isNull() || !strcmp(name, SYSTEM_FROM)) ? CHAT_SOURCE_SYSTEM : CHAT_SOURCE_AGENT;
01358 
01359         LLViewerObject *source = gObjectList.findObject(session_id); //Session ID is probably the wrong thing.
01360         if (source)
01361         {
01362                 is_owned_by_me = source->permYouOwner();
01363         }
01364 
01365         char separator_string[3]=": ";          /* Flawfinder: ignore */
01366         int message_offset=0;
01367 
01368                 //Handle IRC styled /me messages.
01369         if (!strncmp(message, "/me ", 4) || !strncmp(message, "/me'", 4))
01370         {
01371                 strcpy(separator_string,"");            /* Flawfinder: ignore */
01372                 message_offset=3;
01373         }
01374 
01375         LLString::format_map_t args;
01376         switch(dialog)
01377         {
01378         case IM_CONSOLE_AND_CHAT_HISTORY:
01379                 // These are used for system messages, hence don't need the name,
01380                 // as it is always "Second Life".
01381                 // *TODO:translate
01382                 args["[MESSAGE]"] = message;
01383 
01384                 // Note: don't put the message in the IM history, even though was sent
01385                 // via the IM mechanism.
01386                 LLNotifyBox::showXml("SystemMessageTip",args);
01387                 break;
01388 
01389         case IM_NOTHING_SPECIAL: 
01390                 // Don't show dialog, just do IM
01391                 if (!gAgent.isGodlike()
01392                                 && gAgent.getRegion()->isPrelude() 
01393                                 && to_id.isNull() )
01394                 {
01395                         // do nothing -- don't distract newbies in
01396                         // Prelude with global IMs
01397                 }
01398                 else if (offline == IM_ONLINE && !is_linden && is_busy && strcmp(name, SYSTEM_FROM))
01399                 {
01400                         // return a standard "busy" message, but only do it to online IM 
01401                         // (i.e. not other auto responses and not store-and-forward IM)
01402                         if (!gIMMgr->hasSession(session_id))
01403                         {
01404                                 // if there is not a panel for this conversation (i.e. it is a new IM conversation
01405                                 // initiated by the other party) then...
01406                                 std::string my_name;
01407                                 gAgent.buildFullname(my_name);
01408                                 LLString response = gSavedPerAccountSettings.getText("BusyModeResponse");
01409                                 pack_instant_message(
01410                                         gMessageSystem,
01411                                         gAgent.getID(),
01412                                         FALSE,
01413                                         gAgent.getSessionID(),
01414                                         from_id,
01415                                         my_name.c_str(),
01416                                         response.c_str(),
01417                                         IM_ONLINE,
01418                                         IM_BUSY_AUTO_RESPONSE,
01419                                         session_id);
01420                                 gAgent.sendReliableMessage();
01421                         }
01422 
01423                         // now store incoming IM in chat history
01424 
01425                         snprintf(buffer, sizeof(buffer), "%s%s", separator_string, (message+message_offset));           /* Flawfinder: ignore */
01426         
01427                         LL_INFOS("Messaging") << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL;
01428 
01429                         // add to IM panel, but do not bother the user
01430                         gIMMgr->addMessage(
01431                                 session_id,
01432                                 from_id,
01433                                 name,
01434                                 buffer,
01435                                 NULL,
01436                                 dialog,
01437                                 parent_estate_id,
01438                                 region_id,
01439                                 position,
01440                                 true);
01441 
01442                         // pretend this is chat generated by self, so it does not show up on screen
01443                         snprintf(buffer, sizeof(buffer), "IM: %s%s%s", name, separator_string, (message+message_offset));               /* Flawfinder: ignore */
01444                         chat.mText = buffer;
01445                         LLFloaterChat::addChat( chat, TRUE, TRUE );
01446                 }
01447                 else if (from_id.isNull())
01448                 {
01449                         // Messages from "Second Life" ID don't go to IM history
01450                         // messages which should be routed to IM window come from a user ID with name=SYSTEM_NAME
01451                         snprintf(buffer, sizeof(buffer), "%s: %s", name, message);              /* Flawfinder: ignore */
01452                         chat.mText = buffer;
01453                         LLFloaterChat::addChat(chat, FALSE, FALSE);
01454                 }
01455                 else if (to_id.isNull())
01456                 {
01457                         // Message to everyone from GOD
01458                         args["[NAME]"] = name;
01459                         args["[MESSAGE]"] = message;
01460                         LLNotifyBox::showXml("GodMessage", args);
01461 
01462                         // Treat like a system message and put in chat history.
01463                         // Claim to be from a local agent so it doesn't go into
01464                         // console.
01465                         snprintf(buffer, sizeof(buffer), "%s%s%s", name, separator_string, (message+message_offset));           /* Flawfinder: ignore */
01466                         chat.mText = buffer;
01467                         BOOL local_agent = TRUE;
01468                         LLFloaterChat::addChat(chat, FALSE, local_agent);
01469                 }
01470                 else
01471                 {
01472                         // standard message, not from system
01473                         char saved[MAX_STRING];         /* Flawfinder: ignore */
01474                         saved[0] = '\0';
01475                         if(offline == IM_OFFLINE)
01476                         {
01477                                 char time_buf[TIME_STR_LENGTH];         /* Flawfinder: ignore */
01478                                 snprintf(saved, MAX_STRING, "(Saved %s) ",              /* Flawfinder: ignore */
01479                                                 formatted_time(timestamp, time_buf));
01480                         }
01481                         snprintf(buffer, sizeof(buffer), "%s%s%s", separator_string, saved,(message+message_offset));           /* Flawfinder: ignore */
01482 
01483                         LL_INFOS("Messaging") << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL;
01484 
01485                         if (!is_muted || is_linden)
01486                         {
01487                                 gIMMgr->addMessage(
01488                                         session_id,
01489                                         from_id,
01490                                         name,
01491                                         buffer,
01492                                         NULL,
01493                                         dialog,
01494                                         parent_estate_id,
01495                                         region_id,
01496                                         position,
01497                                         true);
01498                                 snprintf(buffer, sizeof(buffer), "IM: %s%s%s%s", name, separator_string, saved, (message+message_offset));              /* Flawfinder: ignore */
01499 
01500                                 chat.mText = buffer;
01501                                 BOOL local_agent = FALSE;
01502                                 LLFloaterChat::addChat( chat, TRUE, local_agent );
01503                         }
01504                         else
01505                         {
01506                                 // muted user, so don't start an IM session, just record line in chat
01507                                 // history.  Pretend the chat is from a local agent,
01508                                 // so it will go into the history but not be shown on screen.
01509                                 chat.mText = buffer;
01510                                 BOOL local_agent = TRUE;
01511                                 LLFloaterChat::addChat( chat, TRUE, local_agent );
01512                         }
01513                 }
01514                 break;
01515 
01516         case IM_TYPING_START:
01517                 {
01518                         LLPointer<LLIMInfo> im_info = new LLIMInfo(gMessageSystem);
01519                         gIMMgr->processIMTypingStart(im_info);
01520                 }
01521                 break;
01522 
01523         case IM_TYPING_STOP:
01524                 {
01525                         LLPointer<LLIMInfo> im_info = new LLIMInfo(gMessageSystem);
01526                         gIMMgr->processIMTypingStop(im_info);
01527                 }
01528                 break;
01529 
01530         case IM_MESSAGEBOX:
01531                 {
01532                         // This is a block, modeless dialog.
01533                         //*TODO:translate
01534                         args["[MESSAGE]"] = message;
01535                         LLNotifyBox::showXml("SystemMessage", args);
01536                 }
01537                 break;
01538         case IM_GROUP_NOTICE:
01539         case IM_GROUP_NOTICE_REQUESTED:
01540                 {
01541                         LL_INFOS("Messaging") << "Received IM_GROUP_NOTICE message." << LL_ENDL;
01542                         // Read the binary bucket for more information.
01543                         struct notice_bucket_header_t
01544                         {
01545                                 U8 has_inventory;
01546                                 U8 asset_type;
01547                                 LLUUID group_id;
01548                         };
01549                         struct notice_bucket_full_t
01550                         {
01551                                 struct notice_bucket_header_t header;
01552                                 U8 item_name[DB_INV_ITEM_NAME_BUF_SIZE];
01553                         }* notice_bin_bucket;
01554 
01555                         // Make sure the binary bucket is big enough to hold the header 
01556                         // and a null terminated item name.
01557                         if ( (binary_bucket_size < (S32)((sizeof(notice_bucket_header_t) + sizeof(U8))))
01558                                 || (binary_bucket[binary_bucket_size - 1] != '\0') )
01559                         {
01560                                 LL_WARNS("Messaging") << "Malformed group notice binary bucket" << LL_ENDL;
01561                                 break;
01562                         }
01563 
01564                         notice_bin_bucket = (struct notice_bucket_full_t*) &binary_bucket[0];
01565                         U8 has_inventory = notice_bin_bucket->header.has_inventory;
01566                         U8 asset_type = notice_bin_bucket->header.asset_type;
01567                         LLUUID group_id = notice_bin_bucket->header.group_id;
01568                         const char* item_name = (const char*) notice_bin_bucket->item_name;
01569 
01570                         // If there is inventory, give the user the inventory offer.
01571                         LLOfferInfo* info = NULL;
01572                         if (has_inventory)
01573                         {
01574                                 info = new LLOfferInfo;
01575                                 info->mIM = IM_GROUP_NOTICE;
01576                                 info->mFromID = from_id;
01577                                 info->mFromGroup = from_group;
01578                                 info->mTransactionID = session_id;
01579                                 info->mType = (LLAssetType::EType) asset_type;
01580                                 info->mFolderID = gInventory.findCategoryUUIDForType(info->mType);
01581                                 std::string from_name;
01582 
01583                                 from_name += "A group member named ";
01584                                 from_name += name;
01585 
01586                                 info->mFromName = from_name;
01587                                 info->mDesc = item_name;
01588                                 info->mHost = msg->getSender();
01589                         }
01590                         
01591                         std::string str(message);
01592 
01593                         // Tokenize the string.
01594                         // TODO: Support escaped tokens ("||" -> "|")
01595                         typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
01596                         boost::char_separator<char> sep("|","",boost::keep_empty_tokens);
01597                         tokenizer tokens(str, sep);
01598                         tokenizer::iterator iter = tokens.begin();
01599 
01600                         LLString subj(*iter++);
01601                         LLString mes(*iter++);
01602 
01603                         if (IM_GROUP_NOTICE == dialog)
01604                         {
01605                                 subj += "\n";
01606                                 mes = "\n\n" + mes;
01607                                 LLGroupNotifyBox::show(subj.c_str(),mes.c_str(),name,group_id,t,has_inventory,item_name,info);
01608                         }
01609                         else if (IM_GROUP_NOTICE_REQUESTED == dialog)
01610                         {
01611                                 LLFloaterGroupInfo::showNotice(subj.c_str(),mes.c_str(),group_id,has_inventory,item_name,info);
01612                         }
01613                 }
01614                 break;
01615         case IM_GROUP_INVITATION:
01616                 {
01617                         //if (!is_linden && (is_busy || is_muted))
01618                         if ((is_busy || is_muted))
01619                         {
01620                                 LLMessageSystem *msg = gMessageSystem;
01621                                 join_group_callback(1, NULL);
01622                                 busy_message(msg,from_id);
01623                         }
01624                         else
01625                         {
01626                                 LL_INFOS("Messaging") << "Received IM_GROUP_INVITATION message." << LL_ENDL;
01627                                 // Read the binary bucket for more information.
01628                                 struct invite_bucket_t
01629                                 {
01630                                         S32 membership_fee;
01631                                         LLUUID role_id;
01632                                 }* invite_bucket;
01633 
01634                                 // Make sure the binary bucket is the correct size.
01635                                 if (binary_bucket_size != sizeof(invite_bucket_t))
01636                                 {
01637                                         LL_WARNS("Messaging") << "Malformed group invite binary bucket" << LL_ENDL;
01638                                         break;
01639                                 }
01640 
01641                                 invite_bucket = (struct invite_bucket_t*) &binary_bucket[0];
01642                                 S32 membership_fee = ntohl(invite_bucket->membership_fee);
01643 
01644                                 LLJoinGroupData* userdata = new LLJoinGroupData;
01645                                 userdata->mTransactionID = session_id;
01646                                 userdata->mGroupID = from_id;
01647                                 userdata->mName.assign(name);
01648                                 userdata->mMessage.assign(message);
01649                                 userdata->mFee = membership_fee;
01650 
01651                                 LLString::format_map_t args;
01652                                 args["[MESSAGE]"] = message;
01653                                 LLNotifyBox::showXml("JoinGroup", args,
01654                                                                          &join_group_callback,
01655                                                                          (void*)userdata);
01656                         }
01657                 }
01658                 break;
01659 
01660         case IM_INVENTORY_OFFERED:
01661         case IM_TASK_INVENTORY_OFFERED:
01662                 // Someone has offered us some inventory.
01663                 {
01664                         LLOfferInfo* info = new LLOfferInfo;
01665 
01666                         if (IM_INVENTORY_OFFERED == dialog)
01667                         {
01668                                 struct offer_agent_bucket_t
01669                                 {
01670                                         S8              asset_type;
01671                                         LLUUID  object_id;
01672                                 }* bucketp;
01673 
01674                                 if (sizeof(offer_agent_bucket_t) != binary_bucket_size)
01675                                 {
01676                                         LL_WARNS("Messaging") << "Malformed inventory offer from agent" << LL_ENDL;
01677                                         break;
01678                                 }
01679                                 bucketp = (struct offer_agent_bucket_t*) &binary_bucket[0];
01680                                 info->mType = (LLAssetType::EType) bucketp->asset_type;
01681                                 info->mObjectID = bucketp->object_id;
01682                         }
01683                         else
01684                         {
01685                                 if (sizeof(S8) != binary_bucket_size)
01686                                 {
01687                                         LL_WARNS("Messaging") << "Malformed inventory offer from object" << LL_ENDL;
01688                                         break;
01689                                 }
01690                                 info->mType = (LLAssetType::EType) binary_bucket[0];
01691                                 info->mObjectID = LLUUID::null;
01692                         }
01693 
01694                         info->mIM = dialog;
01695                         info->mFromID = from_id;
01696                         info->mFromGroup = from_group;
01697                         info->mTransactionID = session_id;
01698                         info->mFolderID = gInventory.findCategoryUUIDForType(info->mType);
01699 
01700                         if (dialog == IM_TASK_INVENTORY_OFFERED)
01701                         {
01702                                 info->mFromObject = TRUE;
01703                         }
01704                         else
01705                         {
01706                                 info->mFromObject = FALSE;
01707                         }
01708                         info->mFromName = name;
01709                         info->mDesc = message;
01710                         info->mHost = msg->getSender();
01711                         //if (((is_busy && !is_owned_by_me) || is_muted))
01712                         if ( is_muted )
01713                         {
01714                                 // Same as closing window
01715                                 inventory_offer_callback(-1, info);
01716                         }
01717                         else
01718                         {
01719                                 inventory_offer_handler(info, dialog == IM_TASK_INVENTORY_OFFERED);
01720                         }
01721                 }
01722                 break;
01723 
01724         case IM_INVENTORY_ACCEPTED:
01725         {
01726                 args["[NAME]"] = name;
01727                 LLNotifyBox::showXml("InventoryAccepted", args);
01728                 break;
01729         }
01730         case IM_INVENTORY_DECLINED:
01731         {
01732                 args["[NAME]"] = name;
01733                 LLNotifyBox::showXml("InventoryDeclined", args);
01734                 break;
01735         }
01736         case IM_GROUP_VOTE:
01737         {
01738                 LLUUID *userdata = new LLUUID(session_id);
01739                 args["[NAME]"] = name;
01740                 args["[MESSAGE]"] = message;
01741                 LLNotifyBox::showXml("GroupVote", args,
01742                                                          &group_vote_callback, userdata);
01743         }
01744         break;
01745 
01746         case IM_GROUP_ELECTION_DEPRECATED:
01747         {
01748                 LL_WARNS("Messaging") << "Received IM: IM_GROUP_ELECTION_DEPRECATED" << LL_ENDL;
01749         }
01750         break;
01751         
01752         case IM_SESSION_SEND:
01753         {
01754                 if (!is_linden && is_busy)
01755                 {
01756                         return;
01757                 }
01758 
01759                 // Only show messages if we have a session open (which
01760                 // should happen after you get an "invitation"
01761                 if ( !gIMMgr->hasSession(session_id) )
01762                 {
01763                         return;
01764                 }
01765 
01766                 // standard message, not from system
01767                 char saved[MAX_STRING];         /* Flawfinder: ignore */
01768                 saved[0] = '\0';
01769                 if(offline == IM_OFFLINE)
01770                 {
01771                         char time_buf[TIME_STR_LENGTH];         /* Flawfinder: ignore */
01772                         snprintf(saved,         /* Flawfinder: ignore */
01773                                          MAX_STRING, 
01774                                          "(Saved %s) ", 
01775                                          formatted_time(timestamp, time_buf));
01776                 }
01777                 snprintf(buffer, sizeof(buffer), "%s%s%s", separator_string, saved, (message+message_offset));          /* Flawfinder: ignore */
01778                 BOOL is_this_agent = FALSE;
01779                 if(from_id == gAgentID)
01780                 {
01781                         is_this_agent = TRUE;
01782                 }
01783                 gIMMgr->addMessage(
01784                         session_id,
01785                         from_id,
01786                         name,
01787                         buffer,
01788                         (char*)binary_bucket,
01789                         IM_SESSION_INVITE,
01790                         parent_estate_id,
01791                         region_id,
01792                         position,
01793                         true);
01794 
01795                 snprintf(buffer, sizeof(buffer), "IM: %s%s%s%s", name, separator_string, saved, (message+message_offset));              /* Flawfinder: ignore */
01796                 chat.mText = buffer;
01797                 LLFloaterChat::addChat(chat, TRUE, is_this_agent);
01798         }
01799         break;
01800 
01801         case IM_FROM_TASK:
01802                 if (is_busy && !is_owned_by_me)
01803                 {
01804                         return;
01805                 }
01806                 snprintf(buffer, sizeof(buffer), "%s%s%s", name, separator_string, (message+message_offset));           /* Flawfinder: ignore */
01807                 // Note: lie to LLFloaterChat::addChat(), pretending that this is NOT an IM, because
01808                 // IMs from objcts don't open IM sessions.
01809                 chat.mText = buffer;
01810                 chat.mSourceType = CHAT_SOURCE_OBJECT;
01811                 LLFloaterChat::addChat(chat, FALSE, FALSE);
01812                 break;
01813         case IM_FROM_TASK_AS_ALERT:
01814                 if (is_busy && !is_owned_by_me)
01815                 {
01816                         return;
01817                 }
01818                 {
01819                         // Construct a viewer alert for this message.
01820                         args["[NAME]"] = name;
01821                         args["[MESSAGE]"] = message;
01822                         LLNotifyBox::showXml("ObjectMessage", args);
01823                 }
01824                 break;
01825         case IM_BUSY_AUTO_RESPONSE:
01826                 if (is_muted)
01827                 {
01828                         LL_DEBUGS("Messaging") << "Ignoring busy response from " << from_id << LL_ENDL;
01829                         return;
01830                 }
01831                 else
01832                 {
01833                         // TODO: after LLTrans hits release, get "busy response" into translatable file
01834                         snprintf(buffer, sizeof(buffer), "%s (%s): %s", name, "busy response", (message+message_offset)); /* Flawfinder: ignore */
01835                         gIMMgr->addMessage(session_id, from_id, name, buffer);
01836                 }
01837                 break;
01838                 
01839         case IM_LURE_USER:
01840                 {
01841                         if (is_muted)
01842                         { 
01843                                 return;
01844                         }
01845                         else if (is_busy) 
01846                         {
01847                                 busy_message(msg,from_id);
01848                         }
01849                         else
01850                         {
01851                                 // *TODO:translate -> [FIRST] [LAST] (maybe)
01852                                 LLLureInfo* info = new LLLureInfo(from_id, session_id, FALSE);
01853                                 args["[NAME]"] = name;
01854                                 args["[MESSAGE]"] = message;
01855                                 LLNotifyBox::showXml("OfferTeleport", args,
01856                                                                          lure_callback, (void*)info);
01857                         }
01858                 }
01859                 break;
01860 
01861         case IM_GODLIKE_LURE_USER:
01862                 {
01863                         LLLureInfo* info = new LLLureInfo(from_id, session_id, TRUE);
01864                         // do not show a message box, because you're about to be
01865                         // teleported.
01866                         lure_callback(0, (void *)info);
01867                 }
01868                 break;
01869 
01870         case IM_GOTO_URL:
01871                 {
01872                         // n.b. this is for URLs sent by the system, not for
01873                         // URLs sent by scripts (i.e. llLoadURL)
01874                         if (binary_bucket_size <= 0)
01875                         {
01876                                 LL_WARNS("Messaging") << "bad binary_bucket_size: "
01877                                         << binary_bucket_size
01878                                         << " - aborting function." << LL_ENDL;
01879                                 return;
01880                         }
01881 
01882                         char* url = new char[binary_bucket_size];
01883                         if (url == NULL)
01884                         {
01885                                 LL_ERRS("Messaging") << "Memory Allocation failed" << LL_ENDL;
01886                                 return;
01887                         }
01888 
01889                         strncpy(url, (char*)binary_bucket, binary_bucket_size-1);               /* Flawfinder: ignore */
01890                         url[binary_bucket_size-1] = '\0';
01891                         args["[MESSAGE]"] = message;
01892                         args["[URL]"] = url;
01893                         LLNotifyBox::showXml("GotoURL", args,
01894                                                                  goto_url_callback, (void*)url);
01895                 }
01896                 break;
01897 
01898         case IM_FRIENDSHIP_OFFERED:
01899                 {
01900                         LLFriendshipOffer* offer = new LLFriendshipOffer;
01901                         offer->mFromID = from_id;
01902                         offer->mTransactionID = session_id;
01903                         offer->mOnline = (offline == IM_ONLINE);
01904                         offer->mHost = msg->getSender();
01905 
01906                         if (is_busy)
01907                         {
01908                                 busy_message(msg, from_id);
01909                                 friendship_offer_callback(1, (void*)offer);
01910                         }
01911                         else if (is_muted)
01912                         {
01913                                 friendship_offer_callback(1, (void*)offer);
01914                         }
01915                         else
01916                         {
01917                                 args["[NAME]"] = name;
01918                                 LLNotifyBox::showXml("OfferFriendship", args,
01919                                         &friendship_offer_callback, (void*)offer);
01920                         }
01921                 }
01922                 break;
01923 
01924         case IM_FRIENDSHIP_ACCEPTED:
01925                 {
01926                         // In the case of an offline IM, the formFriendship() may be extraneous
01927                         // as the database should already include the relationship.  But it
01928                         // doesn't hurt for dupes.
01929                         LLAvatarTracker::formFriendship(from_id);
01930                         
01931                         std::vector<std::string> strings;
01932                         strings.push_back(from_id.asString());
01933                         send_generic_message("requestonlinenotification", strings);
01934                         
01935                         args["[NAME]"] = name;
01936                         LLNotifyBox::showXml("FriendshipAccepted", args);
01937                 }
01938                 break;
01939 
01940         case IM_FRIENDSHIP_DECLINED:
01941                 args["[NAME]"] = name;
01942                 LLNotifyBox::showXml("FriendshipDeclined", args);
01943                 break;
01944 
01945         default:
01946                 LL_WARNS("Messaging") << "Instant message calling for unknown dialog "
01947                                 << (S32)dialog << LL_ENDL;
01948                 break;
01949         }
01950 
01951         LLWindow* viewer_window = gViewerWindow->getWindow();
01952         if (viewer_window && viewer_window->getMinimized())
01953         {
01954                 viewer_window->flashIcon(5.f);
01955         }
01956 }
01957 
01958 void busy_message (LLMessageSystem* msg, LLUUID from_id) 
01959 {
01960         if (gAgent.getBusy())
01961         {
01962                 std::string my_name;
01963                 gAgent.buildFullname(my_name);
01964                 LLString response = gSavedPerAccountSettings.getText("BusyModeResponse");
01965                 pack_instant_message(
01966                         gMessageSystem,
01967                         gAgent.getID(),
01968                         FALSE,
01969                         gAgent.getSessionID(),
01970                         from_id,
01971                         my_name.c_str(),
01972                         response.c_str(),
01973                         IM_ONLINE,
01974                         IM_BUSY_AUTO_RESPONSE);
01975                 gAgent.sendReliableMessage();
01976         }
01977 }
01978 
01979 void friendship_offer_callback(S32 option, void* user_data)
01980 {
01981         LLFriendshipOffer* offer = (LLFriendshipOffer*)user_data;
01982         if(!offer) return;
01983         LLUUID fid;
01984         LLMessageSystem* msg = gMessageSystem;
01985         switch(option)
01986         {
01987         case 0:
01988                 // accept
01989                 LLAvatarTracker::formFriendship(offer->mFromID);
01990 
01991                 fid = gInventory.findCategoryUUIDForType(LLAssetType::AT_CALLINGCARD);
01992 
01993                 // This will also trigger an onlinenotification if the user is online
01994                 msg->newMessageFast(_PREHASH_AcceptFriendship);
01995                 msg->nextBlockFast(_PREHASH_AgentData);
01996                 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
01997                 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
01998                 msg->nextBlockFast(_PREHASH_TransactionBlock);
01999                 msg->addUUIDFast(_PREHASH_TransactionID, offer->mTransactionID);
02000                 msg->nextBlockFast(_PREHASH_FolderData);
02001                 msg->addUUIDFast(_PREHASH_FolderID, fid);
02002                 msg->sendReliable(offer->mHost);
02003                 break;
02004         case 1:
02005                 // decline
02006                 msg->newMessageFast(_PREHASH_DeclineFriendship);
02007                 msg->nextBlockFast(_PREHASH_AgentData);
02008                 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
02009                 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
02010                 msg->nextBlockFast(_PREHASH_TransactionBlock);
02011                 msg->addUUIDFast(_PREHASH_TransactionID, offer->mTransactionID);
02012                 msg->sendReliable(offer->mHost);
02013                 break;
02014         default:
02015                 // close button probably, possibly timed out
02016                 break;
02017         }
02018 
02019         delete offer;
02020         offer = NULL;
02021 }
02022 
02023 struct LLCallingCardOfferData
02024 {
02025         LLUUID mTransactionID;
02026         LLUUID mSourceID;
02027         LLHost mHost;
02028 };
02029 
02030 void callingcard_offer_callback(S32 option, void* user_data)
02031 {
02032         LLCallingCardOfferData* offerdata = (LLCallingCardOfferData*)user_data;
02033         if(!offerdata) return;
02034         LLUUID fid;
02035         LLUUID from_id;
02036         LLMessageSystem* msg = gMessageSystem;
02037         switch(option)
02038         {
02039         case 0:
02040                 // accept
02041                 msg->newMessageFast(_PREHASH_AcceptCallingCard);
02042                 msg->nextBlockFast(_PREHASH_AgentData);
02043                 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
02044                 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
02045                 msg->nextBlockFast(_PREHASH_TransactionBlock);
02046                 msg->addUUIDFast(_PREHASH_TransactionID, offerdata->mTransactionID);
02047                 fid = gInventory.findCategoryUUIDForType(LLAssetType::AT_CALLINGCARD);
02048                 msg->nextBlockFast(_PREHASH_FolderData);
02049                 msg->addUUIDFast(_PREHASH_FolderID, fid);
02050                 msg->sendReliable(offerdata->mHost);
02051                 break;
02052         case 1:
02053                 // decline              
02054                 msg->newMessageFast(_PREHASH_DeclineCallingCard);
02055                 msg->nextBlockFast(_PREHASH_AgentData);
02056                 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
02057                 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
02058                 msg->nextBlockFast(_PREHASH_TransactionBlock);
02059                 msg->addUUIDFast(_PREHASH_TransactionID, offerdata->mTransactionID);
02060                 msg->sendReliable(offerdata->mHost);
02061                 busy_message(msg, offerdata->mSourceID);
02062                 break;
02063         default:
02064                 // close button probably, possibly timed out
02065                 break;
02066         }
02067 
02068         delete offerdata;
02069         offerdata = NULL;
02070 }
02071 
02072 void process_offer_callingcard(LLMessageSystem* msg, void**)
02073 {
02074         // someone has offered to form a friendship
02075         LL_DEBUGS("Messaging") << "callingcard offer" << LL_ENDL;
02076 
02077         LLUUID source_id;
02078         msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, source_id);
02079         LLUUID tid;
02080         msg->getUUIDFast(_PREHASH_AgentBlock, _PREHASH_TransactionID, tid);
02081 
02082         LLCallingCardOfferData* offerdata = new LLCallingCardOfferData;
02083         offerdata->mTransactionID = tid;
02084         offerdata->mSourceID = source_id;
02085         offerdata->mHost = msg->getSender();
02086 
02087         LLViewerObject* source = gObjectList.findObject(source_id);
02088         LLString::format_map_t args;
02089         std::string source_name;
02090         if(source && source->isAvatar())
02091         {
02092                 LLNameValue* nvfirst = source->getNVPair("FirstName");
02093                 LLNameValue* nvlast  = source->getNVPair("LastName");
02094                 if (nvfirst && nvlast)
02095                 {
02096                         args["[FIRST]"] = nvfirst->getString();
02097                         args["[LAST]"] = nvlast->getString();
02098                         source_name = std::string(nvfirst->getString()) + " " + nvlast->getString();
02099                 }
02100         }
02101 
02102         if(!source_name.empty())
02103         {
02104                 if (gAgent.getBusy() 
02105                         || LLMuteList::getInstance()->isMuted(source_id, source_name, LLMute::flagTextChat))
02106                 {
02107                         // automatically decline offer
02108                         callingcard_offer_callback(1, (void*)offerdata);
02109                         offerdata = NULL; // pointer was freed by callback
02110                 }
02111                 else
02112                 {
02113                         LLNotifyBox::showXml("OfferCallingCard", args,
02114                                              &callingcard_offer_callback, (void*)offerdata);
02115                         offerdata = NULL; // pointer ownership transferred
02116                 }
02117         }
02118         else
02119         {
02120                 LL_WARNS("Messaging") << "Calling card offer from an unknown source." << LL_ENDL;
02121         }
02122 
02123         delete offerdata; // !=NULL if we didn't give ownership away
02124         offerdata = NULL;
02125 }
02126 
02127 void process_accept_callingcard(LLMessageSystem* msg, void**)
02128 {
02129         LLNotifyBox::showXml("CallingCardAccepted");
02130 }
02131 
02132 void process_decline_callingcard(LLMessageSystem* msg, void**)
02133 {
02134         LLNotifyBox::showXml("CallingCardDeclined");
02135 }
02136 
02137 
02138 void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
02139 {
02140         LLChat          chat;
02141         char            mesg[DB_CHAT_MSG_BUF_SIZE];             /* Flawfinder: ignore */
02142         char            from_name[DB_FULL_NAME_BUF_SIZE];               /* Flawfinder: ignore */
02143         U8                      source_temp;
02144         U8                      type_temp;
02145         U8                      audible_temp;
02146         LLColor4        color(1.0f, 1.0f, 1.0f, 1.0f);
02147         LLUUID          from_id;
02148         LLUUID          owner_id;
02149         BOOL            is_owned_by_me = FALSE;
02150         LLViewerObject* chatter;
02151 
02152         msg->getString("ChatData", "FromName", DB_FULL_NAME_BUF_SIZE, from_name);
02153         chat.mFromName = from_name;
02154         
02155         msg->getUUID("ChatData", "SourceID", from_id);
02156         chat.mFromID = from_id;
02157         
02158         // Object owner for objects
02159         msg->getUUID("ChatData", "OwnerID", owner_id);
02160         
02161         msg->getU8Fast(_PREHASH_ChatData, _PREHASH_SourceType, source_temp);
02162         chat.mSourceType = (EChatSourceType)source_temp;
02163 
02164         msg->getU8("ChatData", "ChatType", type_temp);
02165         chat.mChatType = (EChatType)type_temp;
02166 
02167         msg->getU8Fast(_PREHASH_ChatData, _PREHASH_Audible, audible_temp);
02168         chat.mAudible = (EChatAudible)audible_temp;
02169         
02170         chat.mTime = LLFrameTimer::getElapsedSeconds();
02171         
02172         BOOL is_self = (from_id == gAgent.getID());
02173         BOOL is_busy = gAgent.getBusy();
02174 
02175         BOOL is_muted = FALSE;
02176         BOOL is_linden = FALSE;
02177         is_muted = LLMuteList::getInstance()->isMuted(
02178                 from_id,
02179                 from_name,
02180                 LLMute::flagTextChat) 
02181                 || LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagTextChat);
02182         is_linden = chat.mSourceType != CHAT_SOURCE_OBJECT &&
02183                 LLMuteList::getInstance()->isLinden(from_name);
02184 
02185         BOOL is_audible = (CHAT_AUDIBLE_FULLY == chat.mAudible);
02186         chatter = gObjectList.findObject(from_id);
02187         if (chatter)
02188         {
02189                 chat.mPosAgent = chatter->getPositionAgent();
02190                 
02191                 // Make swirly things only for talking objects. (not script debug messages, though)
02192                 if (chat.mSourceType == CHAT_SOURCE_OBJECT 
02193                         && chat.mChatType != CHAT_TYPE_DEBUG_MSG)
02194                 {
02195                         LLPointer<LLViewerPartSourceChat> psc = new LLViewerPartSourceChat(chatter->getPositionAgent());
02196                         psc->setSourceObject(chatter);
02197                         psc->setColor(color);
02198                         //We set the particles to be owned by the object's owner, 
02199                         //just in case they should be muted by the mute list
02200                         psc->setOwnerUUID(owner_id);
02201                         LLViewerPartSim::getInstance()->addPartSource(psc);
02202                 }
02203 
02204                 // record last audible utterance
02205                 if (is_audible
02206                         && (is_linden || (!is_muted && !is_busy)))
02207                 {
02208                         if (chat.mChatType != CHAT_TYPE_START 
02209                                 && chat.mChatType != CHAT_TYPE_STOP)
02210                         {
02211                                 gAgent.heardChat(chat.mFromID);
02212                         }
02213                 }
02214 
02215                 is_owned_by_me = chatter->permYouOwner();
02216         }
02217 
02218         if (is_audible)
02219         {
02220                 BOOL visible_in_chat_bubble = FALSE;
02221                 std::string verb;
02222 
02223                 color.setVec(1.f,1.f,1.f,1.f);
02224                 msg->getStringFast(_PREHASH_ChatData, _PREHASH_Message, DB_CHAT_MSG_BUF_SIZE, mesg);
02225 
02226                 BOOL ircstyle = FALSE;
02227 
02228                 // Look for IRC-style emotes here so chatbubbles work
02229                 if (!strncmp(mesg, "/me ", 4) || !strncmp(mesg, "/me'", 4))
02230                 {
02231                         chat.mText = from_name;
02232                         chat.mText += (mesg + 3);
02233                         ircstyle = TRUE;
02234                 }
02235                 else
02236                 {
02237                         chat.mText = mesg;
02238                 }
02239 
02240                 // Look for the start of typing so we can put "..." in the bubbles.
02241                 if (CHAT_TYPE_START == chat.mChatType)
02242                 {
02243                         LLLocalSpeakerMgr::getInstance()->setSpeakerTyping(from_id, TRUE);
02244 
02245                         // Might not have the avatar constructed yet, eg on login.
02246                         if (chatter && chatter->isAvatar())
02247                         {
02248                                 ((LLVOAvatar*)chatter)->startTyping();
02249                         }
02250                         return;
02251                 }
02252                 else if (CHAT_TYPE_STOP == chat.mChatType)
02253                 {
02254                         LLLocalSpeakerMgr::getInstance()->setSpeakerTyping(from_id, FALSE);
02255 
02256                         // Might not have the avatar constructed yet, eg on login.
02257                         if (chatter && chatter->isAvatar())
02258                         {
02259                                 ((LLVOAvatar*)chatter)->stopTyping();
02260                         }
02261                         return;
02262                 }
02263 
02264                 // We have a real utterance now, so can stop showing "..." and proceed.
02265                 if (chatter && chatter->isAvatar())
02266                 {
02267                         LLLocalSpeakerMgr::getInstance()->setSpeakerTyping(from_id, FALSE);
02268                         ((LLVOAvatar*)chatter)->stopTyping();
02269 
02270                         if (!is_muted && !is_busy)
02271                         {
02272                                 visible_in_chat_bubble = gSavedSettings.getBOOL("UseChatBubbles");
02273                                 ((LLVOAvatar*)chatter)->addChat(chat);
02274                         }
02275                 }
02276 
02277                 // Look for IRC-style emotes
02278                 if (ircstyle)
02279                 {
02280                         // Do nothing, ircstyle is fixed above for chat bubbles
02281                 }
02282                 else
02283                 {
02284                         switch(chat.mChatType)
02285                         {
02286                         case CHAT_TYPE_WHISPER:
02287                                 if (is_self)
02288                                 {
02289                                         verb = " whisper: ";
02290                                 }
02291                                 else
02292                                 {
02293                                         verb = " whispers: ";
02294                                 }
02295                                 break;
02296                         case CHAT_TYPE_DEBUG_MSG:
02297                         case CHAT_TYPE_OWNER:
02298                         case CHAT_TYPE_NORMAL:
02299                                 verb = ": ";
02300                                 break;
02301                         case CHAT_TYPE_SHOUT:
02302                                 if (is_self)
02303                                 {
02304                                         verb = " shout: ";
02305                                 }
02306                                 else
02307                                 {
02308                                         verb = " shouts: ";
02309                                 }
02310                                 break;
02311                         case CHAT_TYPE_START:
02312                         case CHAT_TYPE_STOP:
02313                                 LL_WARNS("Messaging") << "Got chat type start/stop in main chat processing." << LL_ENDL;
02314                                 break;
02315                         default:
02316                                 LL_WARNS("Messaging") << "Unknown type " << chat.mChatType << " in chat!" << LL_ENDL;
02317                                 verb = " say, ";
02318                                 break;
02319                         }
02320 
02321                         if (is_self)
02322                         {
02323                                 chat.mText = "You";
02324                         }
02325                         else
02326                         {
02327                                 chat.mText = from_name;
02328                         }
02329                         chat.mText += verb;
02330                         chat.mText += mesg;
02331                 }
02332                 
02333                 if (chatter)
02334                 {
02335                         chat.mPosAgent = chatter->getPositionAgent();
02336                 }
02337 
02338                 // truth table:
02339                 // LINDEN       BUSY    MUTED   OWNED_BY_YOU    TASK            DISPLAY         STORE IN HISTORY
02340                 // F            F               F               F                               *                       Yes                     Yes
02341                 // F            F               F               T                               *                       Yes                     Yes
02342                 // F            F               T               F                               *                       No                      No
02343                 // F            F               T               T                               *                       No                      No
02344                 // F            T               F               F                               *                       No                      Yes
02345                 // F            T               F               T                               *                       Yes                     Yes
02346                 // F            T               T               F                               *                       No                      No
02347                 // F            T               T               T                               *                       No                      No
02348                 // T            *               *               *                               F                       Yes                     Yes
02349 
02350                 chat.mMuted = is_muted && !is_linden;
02351                 
02352                 
02353                 if (!visible_in_chat_bubble 
02354                         && (is_linden || !is_busy || is_owned_by_me))
02355                 {
02356                         // show on screen and add to history
02357                         LLFloaterChat::addChat(chat, FALSE, FALSE);
02358                 }
02359                 else
02360                 {
02361                         // just add to chat history
02362                         LLFloaterChat::addChatHistory(chat);
02363                 }
02364         }
02365 }
02366 
02367 
02368 // Simulator we're on is informing the viewer that the agent
02369 // is starting to teleport (perhaps to another sim, perhaps to the 
02370 // same sim). If we initiated the teleport process by sending some kind 
02371 // of TeleportRequest, then this info is redundant, but if the sim 
02372 // initiated the teleport (via a script call, being killed, etc.) 
02373 // then this info is news to us.
02374 void process_teleport_start(LLMessageSystem *msg, void**)
02375 {
02376         U32 teleport_flags = 0x0;
02377         msg->getU32("Info", "TeleportFlags", teleport_flags);
02378 
02379         if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL)
02380         {
02381                 gViewerWindow->setProgressCancelButtonVisible(FALSE, "");
02382         }
02383         else
02384         {
02385                 gViewerWindow->setProgressCancelButtonVisible(TRUE, "Cancel");
02386         }
02387 
02388         // Freeze the UI and show progress bar
02389         // Note: could add data here to differentiate between normal teleport and death.
02390 
02391         if( gAgent.getTeleportState() == LLAgent::TELEPORT_NONE )
02392         {
02393                 gTeleportDisplay = TRUE;
02394                 gAgent.setTeleportState( LLAgent::TELEPORT_START );
02395                 make_ui_sound("UISndTeleportOut");
02396                 
02397                 // Don't call LLFirstUse::useTeleport here because this could be
02398                 // due to being killed, which would send you home, not to a Telehub
02399         }
02400 }
02401 
02402 void process_teleport_progress(LLMessageSystem* msg, void**)
02403 {
02404         LLUUID agent_id;
02405         msg->getUUID("AgentData", "AgentID", agent_id);
02406         if((gAgent.getID() != agent_id)
02407            || (gAgent.getTeleportState() == LLAgent::TELEPORT_NONE))
02408         {
02409                 LL_WARNS("Messaging") << "Unexpected teleport progress message." << LL_ENDL;
02410                 return;
02411         }
02412         U32 teleport_flags = 0x0;
02413         msg->getU32("Info", "TeleportFlags", teleport_flags);
02414         if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL)
02415         {
02416                 gViewerWindow->setProgressCancelButtonVisible(FALSE, "");
02417         }
02418         else
02419         {
02420                 gViewerWindow->setProgressCancelButtonVisible(TRUE, "Cancel");
02421         }
02422         char buffer[MAX_STRING];                /* Flawfinder: ignore */
02423         msg->getString("Info", "Message", MAX_STRING, buffer);
02424         LL_DEBUGS("Messaging") << "teleport progress: " << buffer << LL_ENDL;
02425 
02426         //Sorta hacky...default to using simulator raw messages
02427         //if we don't find the coresponding mapping in our progress mappings
02428         LLString message = buffer;
02429 
02430         if (LLAgent::sTeleportProgressMessages.find(buffer) != 
02431                 LLAgent::sTeleportProgressMessages.end() )
02432         {
02433                 message = LLAgent::sTeleportProgressMessages[buffer];
02434         }
02435 
02436         gAgent.setTeleportMessage(LLAgent::sTeleportProgressMessages[message]);
02437 }
02438 
02439 class LLFetchInWelcomeArea : public LLInventoryFetchDescendentsObserver
02440 {
02441 public:
02442         LLFetchInWelcomeArea() {}
02443         virtual void done()
02444         {
02445                 LLIsType is_landmark(LLAssetType::AT_LANDMARK);
02446                 LLIsType is_card(LLAssetType::AT_CALLINGCARD);
02447 
02448                 LLInventoryModel::cat_array_t   card_cats;
02449                 LLInventoryModel::item_array_t  card_items;
02450                 LLInventoryModel::cat_array_t   land_cats;
02451                 LLInventoryModel::item_array_t  land_items;
02452 
02453                 folder_ref_t::iterator it = mCompleteFolders.begin();
02454                 folder_ref_t::iterator end = mCompleteFolders.end();
02455                 for(; it != end; ++it)
02456                 {
02457                         gInventory.collectDescendentsIf(
02458                                 (*it),
02459                                 land_cats,
02460                                 land_items,
02461                                 LLInventoryModel::EXCLUDE_TRASH,
02462                                 is_landmark);
02463                         gInventory.collectDescendentsIf(
02464                                 (*it),
02465                                 card_cats,
02466                                 card_items,
02467                                 LLInventoryModel::EXCLUDE_TRASH,
02468                                 is_card);
02469                 }
02470                 LLString::format_map_t args;
02471                 if ( land_items.count() > 0 )
02472                 {       // Show notification that they can now teleport to landmarks.  Use a random landmark from the inventory
02473                         S32 random_land = ll_rand( land_items.count() - 1 );
02474                         args["[NAME]"] = land_items[random_land]->getName();
02475                         LLNotifyBox::showXml("TeleportToLandmark",args);
02476                 }
02477                 if ( card_items.count() > 0 )
02478                 {       // Show notification that they can now contact people.  Use a random calling card from the inventory
02479                         S32 random_card = ll_rand( card_items.count() - 1 );
02480                         args["[NAME]"] = card_items[random_card]->getName();
02481                         LLNotifyBox::showXml("TeleportToPerson",args);
02482                 }
02483 
02484                 gInventory.removeObserver(this);
02485                 delete this;
02486         }
02487 };
02488 
02489 
02490 
02491 class LLPostTeleportNotifiers : public LLEventTimer 
02492 {
02493 public:
02494         LLPostTeleportNotifiers();
02495         virtual ~LLPostTeleportNotifiers();
02496 
02497         //function to be called at the supplied frequency
02498         virtual BOOL tick();
02499 };
02500 
02501 LLPostTeleportNotifiers::LLPostTeleportNotifiers() : LLEventTimer( 2.0 )
02502 {
02503 };
02504 
02505 LLPostTeleportNotifiers::~LLPostTeleportNotifiers()
02506 {
02507 }
02508 
02509 BOOL LLPostTeleportNotifiers::tick()
02510 {
02511         BOOL all_done = FALSE;
02512         if ( gAgent.getTeleportState() == LLAgent::TELEPORT_NONE )
02513         {
02514                 // get callingcards and landmarks available to the user arriving.
02515                 LLInventoryFetchDescendentsObserver::folder_ref_t folders;
02516                 LLUUID folder_id;
02517                 folder_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_CALLINGCARD);
02518                 if(folder_id.notNull()) 
02519                         folders.push_back(folder_id);
02520                 folder_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_LANDMARK);
02521                 if(folder_id.notNull()) 
02522                         folders.push_back(folder_id);
02523                 if(!folders.empty())
02524                 {
02525                         LLFetchInWelcomeArea* fetcher = new LLFetchInWelcomeArea;
02526                         fetcher->fetchDescendents(folders);
02527                         if(fetcher->isEverythingComplete())
02528                         {
02529                                 fetcher->done();
02530                         }
02531                         else
02532                         {
02533                                 gInventory.addObserver(fetcher);
02534                         }
02535                 }
02536                 all_done = TRUE;
02537         }
02538 
02539         return all_done;
02540 }
02541 
02542 
02543 
02544 // Teleport notification from the simulator
02545 // We're going to pretend to be a new agent
02546 void process_teleport_finish(LLMessageSystem* msg, void**)
02547 {
02548         LL_DEBUGS("Messaging") << "Got teleport location message" << LL_ENDL;
02549         LLUUID agent_id;
02550         msg->getUUIDFast(_PREHASH_Info, _PREHASH_AgentID, agent_id);
02551         if (agent_id != gAgent.getID())
02552         {
02553                 LL_WARNS("Messaging") << "Got teleport notification for wrong agent!" << LL_ENDL;
02554                 return;
02555         }
02556 
02557         // Do teleport effect for where you're leaving
02558         // VEFFECT: TeleportStart
02559         LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE);
02560         effectp->setPositionGlobal(gAgent.getPositionGlobal());
02561         effectp->setColor(LLColor4U(gAgent.getEffectColor()));
02562         LLHUDManager::getInstance()->sendEffects();
02563 
02564         U32 location_id;
02565         U32 sim_ip;
02566         U16 sim_port;
02567         LLVector3 pos, look_at;
02568         U64 region_handle;
02569         msg->getU32Fast(_PREHASH_Info, _PREHASH_LocationID, location_id);
02570         msg->getIPAddrFast(_PREHASH_Info, _PREHASH_SimIP, sim_ip);
02571         msg->getIPPortFast(_PREHASH_Info, _PREHASH_SimPort, sim_port);
02572         //msg->getVector3Fast(_PREHASH_Info, _PREHASH_Position, pos);
02573         //msg->getVector3Fast(_PREHASH_Info, _PREHASH_LookAt, look_at);
02574         msg->getU64Fast(_PREHASH_Info, _PREHASH_RegionHandle, region_handle);
02575         U32 teleport_flags;
02576         msg->getU32Fast(_PREHASH_Info, _PREHASH_TeleportFlags, teleport_flags);
02577         
02578         
02579         char seedCap[STD_STRING_BUF_SIZE];              /* Flawfinder: ignore */
02580         msg->getStringFast(_PREHASH_Info, _PREHASH_SeedCapability,
02581                 STD_STRING_BUF_SIZE, seedCap);
02582 
02583         // update home location if we are teleporting out of prelude - specific to teleporting to welcome area 
02584         if((teleport_flags & TELEPORT_FLAGS_SET_HOME_TO_TARGET)
02585            && (!gAgent.isGodlike()))
02586         {
02587                 gAgent.setHomePosRegion(region_handle, pos);
02588 
02589                 // Create a timer that will send notices when teleporting is all finished.  Since this is 
02590                 // based on the LLEventTimer class, it will be managed by that class and not orphaned or leaked.
02591                 new LLPostTeleportNotifiers();
02592         }
02593 
02594         LLHost sim_host(sim_ip, sim_port);
02595 
02596         // Viewer trusts the simulator.
02597         gMessageSystem->enableCircuit(sim_host, TRUE);
02598         LLViewerRegion* regionp =  LLWorld::getInstance()->addRegion(region_handle, sim_host);
02599 
02600 /*
02601         // send camera update to new region
02602         gAgent.updateCamera();
02603 
02604         // likewise make sure the camera is behind the avatar
02605         gAgent.resetView(TRUE);
02606         LLVector3 shift_vector = regionp->getPosRegionFromGlobal(gAgent.getRegion()->getOriginGlobal());
02607         gAgent.setRegion(regionp);
02608         gObjectList.shiftObjects(shift_vector);
02609 
02610         if (gAgent.getAvatarObject())
02611         {
02612                 gAgent.getAvatarObject()->clearChatText();
02613                 gAgent.slamLookAt(look_at);
02614         }
02615         gAgent.setPositionAgent(pos);
02616         gAssetStorage->setUpstream(sim);
02617         gCacheName->setUpstream(sim);
02618 */
02619 
02620         // now, use the circuit info to tell simulator about us!
02621         LL_INFOS("Messaging") << "process_teleport_finish() Enabling "
02622                         << sim_host << " with code " << msg->mOurCircuitCode << LL_ENDL;
02623         msg->newMessageFast(_PREHASH_UseCircuitCode);
02624         msg->nextBlockFast(_PREHASH_CircuitCode);
02625         msg->addU32Fast(_PREHASH_Code, msg->getOurCircuitCode());
02626         msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
02627         msg->addUUIDFast(_PREHASH_ID, gAgent.getID());
02628         msg->sendReliable(sim_host);
02629 
02630         send_complete_agent_movement(sim_host);
02631         gAgent.setTeleportState( LLAgent::TELEPORT_MOVING );
02632         gAgent.setTeleportMessage(LLAgent::sTeleportProgressMessages["contacting"]);
02633 
02634         regionp->setSeedCapability(std::string(seedCap));
02635 
02636         // Don't send camera updates to the new region until we're
02637         // actually there...
02638 
02639 
02640         // Now do teleport effect for where you're going.
02641         // VEFFECT: TeleportEnd
02642         effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE);
02643         effectp->setPositionGlobal(gAgent.getPositionGlobal());
02644 
02645         effectp->setColor(LLColor4U(gAgent.getEffectColor()));
02646         LLHUDManager::getInstance()->sendEffects();
02647 
02648 //      gTeleportDisplay = TRUE;
02649 //      gTeleportDisplayTimer.reset();
02650 //      gViewerWindow->setShowProgress(TRUE);
02651 
02652         // This could be first use of teleport, so test for that
02653         LLFirstUse::useTeleport();
02654 }
02655 
02656 // stuff we have to do every time we get an AvatarInitComplete from a sim
02657 /*
02658 void process_avatar_init_complete(LLMessageSystem* msg, void**)
02659 {
02660         LLVector3 agent_pos;
02661         msg->getVector3Fast(_PREHASH_AvatarData, _PREHASH_Position, agent_pos);
02662         agent_movement_complete(msg->getSender(), agent_pos);
02663 }
02664 */
02665 
02666 static void display_release_message(S32, void* data)
02667 {
02668         std::string* msg = (std::string*)data;
02669         LLFloaterReleaseMsg::displayMessage(msg->c_str());
02670         delete msg;
02671 }
02672 
02673 void process_agent_movement_complete(LLMessageSystem* msg, void**)
02674 {
02675         gAgentMovementCompleted = TRUE;
02676 
02677         LLUUID agent_id;
02678         msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
02679         LLUUID session_id;
02680         msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id);
02681         if((gAgent.getID() != agent_id) || (gAgent.getSessionID() != session_id))
02682         {
02683                 LL_WARNS("Messaging") << "Incorrect id in process_agent_movement_complete()"
02684                                 << LL_ENDL;
02685                 return;
02686         }
02687 
02688         LL_DEBUGS("Messaging") << "process_agent_movement_complete()" << LL_ENDL;
02689 
02690         // *TODO: check timestamp to make sure the movement compleation
02691         // makes sense.
02692         LLVector3 agent_pos;
02693         msg->getVector3Fast(_PREHASH_Data, _PREHASH_Position, agent_pos);
02694         LLVector3 look_at;
02695         msg->getVector3Fast(_PREHASH_Data, _PREHASH_LookAt, look_at);
02696         U64 region_handle;
02697         msg->getU64Fast(_PREHASH_Data, _PREHASH_RegionHandle, region_handle);
02698         
02699         char version_channel_char[MAX_STRING];
02700         msg->getString("SimData", "ChannelVersion", MAX_STRING, version_channel_char);
02701 
02702         LLVOAvatar* avatarp = gAgent.getAvatarObject();
02703         if (!avatarp)
02704         {
02705                 // Could happen if you were immediately god-teleported away on login,
02706                 // maybe other cases.  Continue, but warn.  JC
02707                 LL_WARNS("Messaging") << "agent_movement_complete() with NULL avatarp." << LL_ENDL;
02708         }
02709 
02710         F32 x, y;
02711         from_region_handle(region_handle, &x, &y);
02712         LLViewerRegion* regionp = LLWorld::getInstance()->getRegionFromHandle(region_handle);
02713         if (!regionp)
02714         {
02715                 if (gAgent.getRegion())
02716                 {
02717                         LL_WARNS("Messaging") << "current region " << gAgent.getRegion()->getOriginGlobal() << LL_ENDL;
02718                 }
02719 
02720                 LL_WARNS("Messaging") << "Agent being sent to invalid home region: " 
02721                         << x << ":" << y 
02722                         << " current pos " << gAgent.getPositionGlobal()
02723                         << LL_ENDL;
02724                 LLAppViewer::instance()->forceDisconnect("You were sent to an invalid region.");
02725                 return;
02726 
02727         }
02728 
02729         LL_INFOS("Messaging") << "Changing home region to " << x << ":" << y << LL_ENDL;
02730 
02731         // set our upstream host the new simulator and shuffle things as
02732         // appropriate.
02733         LLVector3 shift_vector = regionp->getPosRegionFromGlobal(
02734                 gAgent.getRegion()->getOriginGlobal());
02735         gAgent.setRegion(regionp);
02736         gObjectList.shiftObjects(shift_vector);
02737         gAssetStorage->setUpstream(msg->getSender());
02738         gCacheName->setUpstream(msg->getSender());
02739         gViewerThrottle.sendToSim();
02740         gViewerWindow->sendShapeToSim();
02741 
02742         bool is_teleport = gAgent.getTeleportState() == LLAgent::TELEPORT_MOVING;
02743 
02744         if( is_teleport )
02745         {
02746                 // Force the camera back onto the agent, don't animate. JC
02747                 gAgent.setFocusOnAvatar(TRUE, FALSE);
02748                 gAgent.slamLookAt(look_at);
02749                 gAgent.updateCamera();
02750 
02751                 gAgent.setTeleportState( LLAgent::TELEPORT_START_ARRIVAL );
02752 
02753                 // set the appearance on teleport since the new sim does not
02754                 // know what you look like.
02755                 gAgent.sendAgentSetAppearance();
02756 
02757                 if (avatarp)
02758                 {
02759                         // Chat the "back" SLURL. (DEV-4907)
02760                         LLChat chat("Teleport completed from " + gAgent.getTeleportSourceSLURL());
02761                         chat.mSourceType = CHAT_SOURCE_SYSTEM;
02762                         LLFloaterChat::addChatHistory(chat);
02763 
02764                         // Set the new position
02765                         avatarp->setPositionAgent(agent_pos);
02766                         avatarp->clearChat();
02767                         avatarp->slamPosition();
02768                 }
02769         }
02770         else
02771         {
02772                 // This is likely just the initial logging in phase.
02773                 gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
02774         }
02775 
02776         if ( LLTracker::isTracking(NULL) )
02777         {
02778                 // Check distance to beacon, if < 5m, remove beacon
02779                 LLVector3d beacon_pos = LLTracker::getTrackedPositionGlobal();
02780                 LLVector3 beacon_dir(agent_pos.mV[VX] - (F32)fmod(beacon_pos.mdV[VX], 256.0), agent_pos.mV[VY] - (F32)fmod(beacon_pos.mdV[VY], 256.0), 0);
02781                 if (beacon_dir.magVecSquared() < 25.f)
02782                 {
02783                         LLTracker::stopTracking(NULL);
02784                 }
02785                 else if ( is_teleport )
02786                 {
02787                         //look at the beacon
02788                         LLVector3 global_agent_pos = agent_pos;
02789                         global_agent_pos[0] += x;
02790                         global_agent_pos[1] += y;
02791                         look_at = (LLVector3)beacon_pos - global_agent_pos;
02792                         look_at.normVec();
02793                         gAgent.slamLookAt(look_at);
02794                 }
02795         }
02796 
02797         // TODO: Put back a check for flying status! DK 12/19/05
02798         // Sim tells us whether the new position is off the ground
02799         /*
02800         if (teleport_flags & TELEPORT_FLAGS_IS_FLYING)
02801         {
02802                 gAgent.setFlying(TRUE);
02803         }
02804         else
02805         {
02806                 gAgent.setFlying(FALSE);
02807         }
02808         */
02809 
02810         send_agent_update(TRUE, TRUE);
02811 
02812         if (gAgent.getRegion()->getBlockFly())
02813         {
02814                 gAgent.setFlying(gAgent.canFly());
02815         }
02816 
02817         // force simulator to recognize busy state
02818         if (gAgent.getBusy())
02819         {
02820                 gAgent.setBusy();
02821         }
02822         else
02823         {
02824                 gAgent.clearBusy();
02825         }
02826 
02827         if (avatarp)
02828         {
02829                 avatarp->mFootPlane.clearVec();
02830         }
02831         
02832         // send walk-vs-run status
02833         gAgent.sendWalkRun(gAgent.getRunning() || gAgent.getAlwaysRun());
02834 
02835         if (LLFloaterReleaseMsg::checkVersion(version_channel_char))
02836         {
02837                 LLNotifyBox::showXml("ServerVersionChanged", display_release_message, new std::string(version_channel_char) );
02838         }
02839 }
02840 
02841 void process_crossed_region(LLMessageSystem* msg, void**)
02842 {
02843         LLUUID agent_id;
02844         msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
02845         LLUUID session_id;
02846         msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id);
02847         if((gAgent.getID() != agent_id) || (gAgent.getSessionID() != session_id))
02848         {
02849                 LL_WARNS("Messaging") << "Incorrect id in process_crossed_region()"
02850                                 << LL_ENDL;
02851                 return;
02852         }
02853         LL_INFOS("Messaging") << "process_crossed_region()" << LL_ENDL;
02854 
02855         U32 sim_ip;
02856         msg->getIPAddrFast(_PREHASH_RegionData, _PREHASH_SimIP, sim_ip);
02857         U16 sim_port;
02858         msg->getIPPortFast(_PREHASH_RegionData, _PREHASH_SimPort, sim_port);
02859         LLHost sim_host(sim_ip, sim_port);
02860         U64 region_handle;
02861         msg->getU64Fast(_PREHASH_RegionData, _PREHASH_RegionHandle, region_handle);
02862         
02863         char seedCap[STD_STRING_BUF_SIZE];              /* Flawfinder: ignore */
02864         msg->getStringFast(_PREHASH_RegionData, _PREHASH_SeedCapability, STD_STRING_BUF_SIZE, seedCap);
02865 
02866         send_complete_agent_movement(sim_host);
02867 
02868         LLViewerRegion* regionp = LLWorld::getInstance()->addRegion(region_handle, sim_host);
02869         regionp->setSeedCapability(std::string(seedCap));
02870 }
02871 
02872 
02873 
02874 // Sends avatar and camera information to simulator.
02875 // Sent roughly once per frame, or 20 times per second, whichever is less often
02876 
02877 const F32 THRESHOLD_HEAD_ROT_QDOT = 0.9997f;    // ~= 2.5 degrees -- if its less than this we need to update head_rot
02878 const F32 MAX_HEAD_ROT_QDOT = 0.99999f;                 // ~= 0.5 degrees -- if its greater than this then no need to update head_rot
02879                                                                                                 // between these values we delay the updates (but no more than one second)
02880 
02881 
02882 void send_agent_update(BOOL force_send, BOOL send_reliable)
02883 {
02884         if (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE)
02885         {
02886                 // We don't care if they want to send an agent update, they're not allowed to until the simulator
02887                 // that's the target is ready to receive them (after avatar_init_complete is received)
02888                 return;
02889         }
02890 
02891         // We have already requested to log out.  Don't send agent updates.
02892         if(LLAppViewer::instance()->logoutRequestSent())
02893         {
02894                 return;
02895         }
02896 
02897         // no region to send update to
02898         if(gAgent.getRegion() == NULL)
02899         {
02900                 return;
02901         }
02902 
02903         const F32 TRANSLATE_THRESHOLD = 0.01f;
02904 
02905         // NOTA BENE: This is (intentionally?) using the small angle sine approximation to test for rotation
02906         //                        Plus, there is an extra 0.5 in the mix since the perpendicular between last_camera_at and getAtAxis() bisects cam_rot_change
02907         //                        Thus, we're actually testing against 0.2 degrees
02908         const F32 ROTATION_THRESHOLD = 0.1f * 2.f*F_PI/360.f;                   //  Rotation thresh 0.2 deg, see note above
02909 
02910         const U8 DUP_MSGS = 1;                          //  HACK!  number of times to repeat data on motionless agent
02911 
02912         //  Store data on last sent update so that if no changes, no send
02913         static LLVector3 last_camera_pos_agent, 
02914                                          last_camera_at, 
02915                                          last_camera_left,
02916                                          last_camera_up;
02917         
02918         static LLVector3 cam_center_chg,
02919                                          cam_rot_chg;
02920 
02921         static LLQuaternion last_head_rot;
02922         static U32 last_control_flags = 0;
02923         static U8 last_render_state;
02924         static U8 duplicate_count = 0;
02925         static F32 head_rot_chg = 1.0;
02926         static U8 last_flags;
02927 
02928         LLMessageSystem *msg = gMessageSystem;
02929         LLVector3               camera_pos_agent;                               // local to avatar's region
02930         U8                              render_state;
02931 
02932         LLQuaternion body_rotation = gAgent.getFrameAgent().getQuaternion();
02933         LLQuaternion head_rotation = gAgent.getHeadRotation();
02934 
02935         camera_pos_agent = gAgent.getCameraPositionAgent();
02936 
02937         render_state = gAgent.getRenderState();
02938 
02939         U32             control_flag_change = 0;
02940         U8              flag_change = 0;
02941 
02942         cam_center_chg = last_camera_pos_agent - camera_pos_agent;
02943         cam_rot_chg = last_camera_at - LLViewerCamera::getInstance()->getAtAxis();
02944 
02945         // If a modifier key is held down, turn off
02946         // LBUTTON and ML_LBUTTON so that using the camera (alt-key) doesn't
02947         // trigger a control event.
02948         U32 control_flags = gAgent.getControlFlags();
02949         MASK    key_mask = gKeyboard->currentMask(TRUE);
02950         if (key_mask & MASK_ALT || key_mask & MASK_CONTROL)
02951         {
02952                 control_flags &= ~(     AGENT_CONTROL_LBUTTON_DOWN |
02953                                                         AGENT_CONTROL_ML_LBUTTON_DOWN );
02954                 control_flags |=        AGENT_CONTROL_LBUTTON_UP |
02955                                                         AGENT_CONTROL_ML_LBUTTON_UP ;
02956         }
02957 
02958         control_flag_change = last_control_flags ^ control_flags;
02959 
02960         U8 flags = AU_FLAGS_NONE;
02961         if (gAgent.isGroupTitleHidden())
02962         {
02963                 flags |= AU_FLAGS_HIDETITLE;
02964         }
02965 
02966         flag_change = last_flags ^ flags;
02967 
02968         head_rot_chg = dot(last_head_rot, head_rotation);
02969 
02970         if (force_send || 
02971                 (cam_center_chg.magVec() > TRANSLATE_THRESHOLD) || 
02972                 (head_rot_chg < THRESHOLD_HEAD_ROT_QDOT) ||     
02973                 (last_render_state != render_state) ||
02974                 (cam_rot_chg.magVec() > ROTATION_THRESHOLD) ||
02975                 control_flag_change != 0 ||
02976                 flag_change != 0)  
02977         {
02978 /*
02979                 if (head_rot_chg < THRESHOLD_HEAD_ROT_QDOT)
02980                 {
02981                         //LL_INFOS("Messaging") << "head rot " << head_rotation << LL_ENDL;
02982                         LL_INFOS("Messaging") << "head_rot_chg = " << head_rot_chg << LL_ENDL;
02983                 }
02984                 if (cam_rot_chg.magVec() > ROTATION_THRESHOLD) 
02985                 {
02986                         LL_INFOS("Messaging") << "cam rot " <<  cam_rot_chg.magVec() << LL_ENDL;
02987                 }
02988                 if (cam_center_chg.magVec() > TRANSLATE_THRESHOLD)
02989                 {
02990                         LL_INFOS("Messaging") << "cam center " << cam_center_chg.magVec() << LL_ENDL;
02991                 }
02992 //              if (drag_delta_chg.magVec() > TRANSLATE_THRESHOLD)
02993 //              {
02994 //                      LL_INFOS("Messaging") << "drag delta " << drag_delta_chg.magVec() << LL_ENDL;
02995 //              }
02996                 if (control_flag_change)
02997                 {
02998                         LL_INFOS("Messaging") << "dcf = " << control_flag_change << LL_ENDL;
02999                 }
03000 */
03001 
03002                 duplicate_count = 0;
03003         }
03004         else
03005         {
03006                 duplicate_count++;
03007 
03008                 if (head_rot_chg < MAX_HEAD_ROT_QDOT  &&  duplicate_count < AGENT_UPDATES_PER_SECOND)
03009                 {
03010                         // The head_rotation is sent for updating things like attached guns.
03011                         // We only trigger a new update when head_rotation deviates beyond
03012                         // some threshold from the last update, however this can break fine
03013                         // adjustments when trying to aim an attached gun, so what we do here
03014                         // (where we would normally skip sending an update when nothing has changed)
03015                         // is gradually reduce the threshold to allow a better update to 
03016                         // eventually get sent... should update to within 0.5 degrees in less 
03017                         // than a second.
03018                         if (head_rot_chg < THRESHOLD_HEAD_ROT_QDOT + (MAX_HEAD_ROT_QDOT - THRESHOLD_HEAD_ROT_QDOT) * duplicate_count / AGENT_UPDATES_PER_SECOND)
03019                         {
03020                                 duplicate_count = 0;
03021                         }
03022                         else
03023                         {
03024                                 return;
03025                         }
03026                 }
03027                 else
03028                 {
03029                         return;
03030                 }
03031         }
03032 
03033         if (duplicate_count < DUP_MSGS && !gDisconnected)
03034         {
03035                 // Build the message
03036                 msg->newMessageFast(_PREHASH_AgentUpdate);
03037                 msg->nextBlockFast(_PREHASH_AgentData);
03038                 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
03039                 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
03040                 msg->addQuatFast(_PREHASH_BodyRotation, body_rotation);
03041                 msg->addQuatFast(_PREHASH_HeadRotation, head_rotation);
03042                 msg->addU8Fast(_PREHASH_State, render_state);
03043                 msg->addU8Fast(_PREHASH_Flags, flags);
03044 
03045 //              if (camera_pos_agent.mV[VY] > 255.f)
03046 //              {
03047 //                      LL_INFOS("Messaging") << "Sending camera center " << camera_pos_agent << LL_ENDL;
03048 //              }
03049                 
03050                 msg->addVector3Fast(_PREHASH_CameraCenter, camera_pos_agent);
03051                 msg->addVector3Fast(_PREHASH_CameraAtAxis, LLViewerCamera::getInstance()->getAtAxis());
03052                 msg->addVector3Fast(_PREHASH_CameraLeftAxis, LLViewerCamera::getInstance()->getLeftAxis());
03053                 msg->addVector3Fast(_PREHASH_CameraUpAxis, LLViewerCamera::getInstance()->getUpAxis());
03054                 msg->addF32Fast(_PREHASH_Far, gAgent.mDrawDistance);
03055                 
03056                 msg->addU32Fast(_PREHASH_ControlFlags, control_flags);
03057 
03058                 if (gDebugClicks)
03059                 {
03060                         if (control_flags & AGENT_CONTROL_LBUTTON_DOWN)
03061                         {
03062                                 LL_INFOS("Messaging") << "AgentUpdate left button down" << LL_ENDL;
03063                         }
03064 
03065                         if (control_flags & AGENT_CONTROL_LBUTTON_UP)
03066                         {
03067                                 LL_INFOS("Messaging") << "AgentUpdate left button up" << LL_ENDL;
03068                         }
03069                 }
03070 
03071                 gAgent.enableControlFlagReset();
03072 
03073                 if (!send_reliable)
03074                 {
03075                         gAgent.sendMessage();
03076                 }
03077                 else
03078                 {
03079                         gAgent.sendReliableMessage();
03080                 }
03081 
03082 //              LL_DEBUGS("Messaging") << "agent " << avatar_pos_agent << " cam " << camera_pos_agent << LL_ENDL;
03083 
03084                 // Copy the old data 
03085                 last_head_rot = head_rotation;
03086                 last_render_state = render_state;
03087                 last_camera_pos_agent = camera_pos_agent;
03088                 last_camera_at = LLViewerCamera::getInstance()->getAtAxis();
03089                 last_camera_left = LLViewerCamera::getInstance()->getLeftAxis();
03090                 last_camera_up = LLViewerCamera::getInstance()->getUpAxis();
03091                 last_control_flags = control_flags;
03092                 last_flags = flags;
03093         }
03094 }
03095 
03096 
03097 
03098 // *TODO: Remove this dependency, or figure out a better way to handle
03099 // this hack.
03100 extern U32 gObjectBits;
03101 
03102 void process_object_update(LLMessageSystem *mesgsys, void **user_data)
03103 {       
03104         LLMemType mt(LLMemType::MTYPE_OBJECT);
03105         // Update the data counters
03106         if (mesgsys->getReceiveCompressedSize())
03107         {
03108                 gObjectBits += mesgsys->getReceiveCompressedSize() * 8;
03109         }
03110         else
03111         {
03112                 gObjectBits += mesgsys->getReceiveSize() * 8;
03113         }
03114 
03115         // Update the object...
03116         gObjectList.processObjectUpdate(mesgsys, user_data, OUT_FULL);
03117         stop_glerror();
03118 }
03119 
03120 void process_compressed_object_update(LLMessageSystem *mesgsys, void **user_data)
03121 {
03122         LLMemType mt(LLMemType::MTYPE_OBJECT);
03123         // Update the data counters
03124         if (mesgsys->getReceiveCompressedSize())
03125         {
03126                 gObjectBits += mesgsys->getReceiveCompressedSize() * 8;
03127         }
03128         else
03129         {
03130                 gObjectBits += mesgsys->getReceiveSize() * 8;
03131         }
03132 
03133         // Update the object...
03134         gObjectList.processCompressedObjectUpdate(mesgsys, user_data, OUT_FULL_COMPRESSED);
03135         stop_glerror();
03136 }
03137 
03138 void process_cached_object_update(LLMessageSystem *mesgsys, void **user_data)
03139 {
03140         LLMemType mt(LLMemType::MTYPE_OBJECT);
03141         // Update the data counters
03142         if (mesgsys->getReceiveCompressedSize())
03143         {
03144                 gObjectBits += mesgsys->getReceiveCompressedSize() * 8;
03145         }
03146         else
03147         {
03148                 gObjectBits += mesgsys->getReceiveSize() * 8;
03149         }
03150 
03151         // Update the object...
03152         gObjectList.processCachedObjectUpdate(mesgsys, user_data, OUT_FULL_CACHED);
03153         stop_glerror();
03154 }
03155 
03156 
03157 void process_terse_object_update_improved(LLMessageSystem *mesgsys, void **user_data)
03158 {
03159         LLMemType mt(LLMemType::MTYPE_OBJECT);
03160         if (mesgsys->getReceiveCompressedSize())
03161         {
03162                 gObjectBits += mesgsys->getReceiveCompressedSize() * 8;
03163         }
03164         else
03165         {
03166                 gObjectBits += mesgsys->getReceiveSize() * 8;
03167         }
03168 
03169         gObjectList.processCompressedObjectUpdate(mesgsys, user_data, OUT_TERSE_IMPROVED);
03170 }
03171 
03172 
03173 
03174 void process_kill_object(LLMessageSystem *mesgsys, void **user_data)
03175 {
03176         LLFastTimer t(LLFastTimer::FTM_PROCESS_OBJECTS);
03177 
03178         LLUUID          id;
03179         U32                     local_id;
03180         S32                     i;
03181         S32                     num_objects;
03182 
03183         num_objects = mesgsys->getNumberOfBlocksFast(_PREHASH_ObjectData);
03184 
03185         for (i = 0; i < num_objects; i++)
03186         {
03187                 mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i);
03188 
03189                 LLViewerObjectList::getUUIDFromLocal(id,
03190                                                                                         local_id,
03191                                                                                         gMessageSystem->getSenderIP(),
03192                                                                                         gMessageSystem->getSenderPort());
03193                 if (id == LLUUID::null)
03194                 {
03195                         LL_DEBUGS("Messaging") << "Unknown kill for local " << local_id << LL_ENDL;
03196                         gObjectList.mNumUnknownKills++;
03197                         continue;
03198                 }
03199                 else
03200                 {
03201                         LL_DEBUGS("Messaging") << "Kill message for local " << local_id << LL_ENDL;
03202                 }
03203 
03204                 LLSelectMgr::getInstance()->removeObjectFromSelections(id);
03205 
03206                 // ...don't kill the avatar
03207                 if (!(id == gAgentID))
03208                 {
03209                         LLViewerObject *objectp = gObjectList.findObject(id);
03210                         if (objectp)
03211                         {
03212                                 // Display green bubble on kill
03213                                 if ( gShowObjectUpdates )
03214                                 {
03215                                         LLViewerObject* newobject;
03216                                         newobject = gObjectList.createObjectViewer(LL_PCODE_LEGACY_TEXT_BUBBLE, objectp->getRegion());
03217 
03218                                         LLVOTextBubble* bubble = (LLVOTextBubble*) newobject;
03219 
03220                                         bubble->mColor.setVec(0.f, 1.f, 0.f, 1.f);
03221                                         bubble->setScale( 2.0f * bubble->getScale() );
03222                                         bubble->setPositionGlobal(objectp->getPositionGlobal());
03223                                         gPipeline.addObject(bubble);
03224                                 }
03225 
03226                                 // Do the kill
03227                                 gObjectList.killObject(objectp);
03228                         }
03229                         else
03230                         {
03231                                 LL_WARNS("Messaging") << "Object in UUID lookup, but not on object list in kill!" << LL_ENDL;
03232                                 gObjectList.mNumUnknownKills++;
03233                         }
03234                 }
03235         }
03236 }
03237 
03238 void process_time_synch(LLMessageSystem *mesgsys, void **user_data)
03239 {
03240         LLVector3 sun_direction;
03241         LLVector3 sun_ang_velocity;
03242         F32 phase;
03243         U64     space_time_usec;
03244 
03245     U32 seconds_per_day;
03246     U32 seconds_per_year;
03247 
03248         // "SimulatorViewerTimeMessage"
03249         mesgsys->getU64Fast(_PREHASH_TimeInfo, _PREHASH_UsecSinceStart, space_time_usec);
03250         mesgsys->getU32Fast(_PREHASH_TimeInfo, _PREHASH_SecPerDay, seconds_per_day);
03251         mesgsys->getU32Fast(_PREHASH_TimeInfo, _PREHASH_SecPerYear, seconds_per_year);
03252 
03253         // This should eventually be moved to an "UpdateHeavenlyBodies" message
03254         mesgsys->getF32Fast(_PREHASH_TimeInfo, _PREHASH_SunPhase, phase);
03255         mesgsys->getVector3Fast(_PREHASH_TimeInfo, _PREHASH_SunDirection, sun_direction);
03256         mesgsys->getVector3Fast(_PREHASH_TimeInfo, _PREHASH_SunAngVelocity, sun_ang_velocity);
03257 
03258         LLWorld::getInstance()->setSpaceTimeUSec(space_time_usec);
03259 
03260         //LL_DEBUGS("Messaging") << "time_synch() - " << sun_direction << ", " << sun_ang_velocity
03261         //               << ", " << phase << LL_ENDL;
03262 
03263         gSky.setSunPhase(phase);
03264         gSky.setSunTargetDirection(sun_direction, sun_ang_velocity);
03265         if (!gNoRender && !(gSavedSettings.getBOOL("SkyOverrideSimSunPosition") || gSky.getOverrideSun()))
03266         {
03267                 gSky.setSunDirection(sun_direction, sun_ang_velocity);
03268         }
03269 }
03270 
03271 void process_sound_trigger(LLMessageSystem *msg, void **)
03272 {
03273         if (!gAudiop) return;
03274 
03275         U64             region_handle = 0;
03276         F32             gain = 0;
03277         LLUUID  sound_id;
03278         LLUUID  owner_id;
03279         LLUUID  object_id;
03280         LLUUID  parent_id;
03281         LLVector3       pos_local;
03282 
03283         msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_SoundID, sound_id);
03284         msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_OwnerID, owner_id);
03285         msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_ObjectID, object_id);
03286         msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_ParentID, parent_id);
03287         msg->getU64Fast(_PREHASH_SoundData, _PREHASH_Handle, region_handle);
03288         msg->getVector3Fast(_PREHASH_SoundData, _PREHASH_Position, pos_local);
03289         msg->getF32Fast(_PREHASH_SoundData, _PREHASH_Gain, gain);
03290 
03291         // adjust sound location to true global coords
03292         LLVector3d      pos_global = from_region_handle(region_handle);
03293         pos_global.mdV[VX] += pos_local.mV[VX];
03294         pos_global.mdV[VY] += pos_local.mV[VY];
03295         pos_global.mdV[VZ] += pos_local.mV[VZ];
03296 
03297         // Don't play a trigger sound if you can't hear it due
03298         // to parcel "local audio only" settings.
03299         if (!LLViewerParcelMgr::getInstance()->canHearSound(pos_global)) return;
03300 
03301         // Don't play sounds triggered by someone you muted.
03302         if (LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagObjectSounds)) return;
03303         
03304         // Don't play sounds from an object you muted
03305         if (LLMuteList::getInstance()->isMuted(object_id)) return;
03306 
03307         // Don't play sounds from an object whose parent you muted
03308         if (parent_id.notNull()
03309                 && LLMuteList::getInstance()->isMuted(parent_id))
03310         {
03311                 return;
03312         }
03313 
03314         F32 volume = gSavedSettings.getBOOL("MuteSounds") ? 0.f : (gain * gSavedSettings.getF32("AudioLevelSFX"));
03315         gAudiop->triggerSound(sound_id, owner_id, volume, pos_global);
03316 }
03317 
03318 void process_preload_sound(LLMessageSystem *msg, void **user_data)
03319 {
03320         if (!gAudiop)
03321         {
03322                 return;
03323         }
03324 
03325         LLUUID sound_id;
03326         LLUUID object_id;
03327         LLUUID owner_id;
03328 
03329         msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_SoundID, sound_id);
03330         msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_ObjectID, object_id);
03331         msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_OwnerID, owner_id);
03332 
03333         LLViewerObject *objectp = gObjectList.findObject(object_id);
03334         if (!objectp) return;
03335 
03336         if (LLMuteList::getInstance()->isMuted(object_id)) return;
03337         if (LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagObjectSounds)) return;
03338         
03339         LLAudioSource *sourcep = objectp->getAudioSource(owner_id);
03340         if (!sourcep) return;
03341         
03342         LLAudioData *datap = gAudiop->getAudioData(sound_id);
03343 
03344         // Note that I don't actually do any loading of the
03345         // audio data into a buffer at this point, as it won't actually
03346         // help us out.
03347 
03348         // Add audioData starts a transfer internally.
03349         sourcep->addAudioData(datap, FALSE);
03350 }
03351 
03352 void process_attached_sound(LLMessageSystem *msg, void **user_data)
03353 {
03354         F32 gain = 0;
03355         LLUUID sound_id;
03356         LLUUID object_id;
03357         LLUUID owner_id;
03358         U8 flags;
03359 
03360         msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_SoundID, sound_id);
03361         msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_ObjectID, object_id);
03362         msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_OwnerID, owner_id);
03363         msg->getF32Fast(_PREHASH_DataBlock, _PREHASH_Gain, gain);
03364         msg->getU8Fast(_PREHASH_DataBlock, _PREHASH_Flags, flags);
03365 
03366         LLViewerObject *objectp = gObjectList.findObject(object_id);
03367         if (!objectp)
03368         {
03369                 // we don't know about this object, just bail
03370                 return;
03371         }
03372         
03373         if (LLMuteList::getInstance()->isMuted(object_id)) return;
03374         
03375         if (LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagObjectSounds)) return;
03376 
03377         objectp->setAttachedSound(sound_id, owner_id, gain, flags);
03378 }
03379 
03380 
03381 void process_attached_sound_gain_change(LLMessageSystem *mesgsys, void **user_data)
03382 {
03383         F32 gain = 0;
03384         LLUUID object_guid;
03385         LLViewerObject *objectp = NULL;
03386 
03387         mesgsys->getUUIDFast(_PREHASH_DataBlock, _PREHASH_ObjectID, object_guid);
03388 
03389         if (!((objectp = gObjectList.findObject(object_guid))))
03390         {
03391                 // we don't know about this object, just bail
03392                 return;
03393         }
03394 
03395         mesgsys->getF32Fast(_PREHASH_DataBlock, _PREHASH_Gain, gain);
03396 
03397         objectp->adjustAudioGain(gain);
03398 }
03399 
03400 
03401 void process_health_message(LLMessageSystem *mesgsys, void **user_data)
03402 {
03403         F32 health;
03404 
03405         mesgsys->getF32Fast(_PREHASH_HealthData, _PREHASH_Health, health);
03406 
03407         if (gStatusBar)
03408         {
03409                 gStatusBar->setHealth((S32)health);
03410         }
03411 }
03412 
03413 
03414 void process_sim_stats(LLMessageSystem *msg, void **user_data)
03415 {       
03416         S32 count = msg->getNumberOfBlocks("Stat");
03417         for (S32 i = 0; i < count; ++i)
03418         {
03419                 U32 stat_id;
03420                 F32 stat_value;
03421                 msg->getU32("Stat", "StatID", stat_id, i);
03422                 msg->getF32("Stat", "StatValue", stat_value, i);
03423                 switch (stat_id)
03424                 {
03425                 case LL_SIM_STAT_TIME_DILATION:
03426                         LLViewerStats::getInstance()->mSimTimeDilation.addValue(stat_value);
03427                         break;
03428                 case LL_SIM_STAT_FPS:
03429                         LLViewerStats::getInstance()->mSimFPS.addValue(stat_value);
03430                         break;
03431                 case LL_SIM_STAT_PHYSFPS:
03432                         LLViewerStats::getInstance()->mSimPhysicsFPS.addValue(stat_value);
03433                         break;
03434                 case LL_SIM_STAT_AGENTUPS:
03435                         LLViewerStats::getInstance()->mSimAgentUPS.addValue(stat_value);
03436                         break;
03437                 case LL_SIM_STAT_FRAMEMS:
03438                         LLViewerStats::getInstance()->mSimFrameMsec.addValue(stat_value);
03439                         break;
03440                 case LL_SIM_STAT_NETMS:
03441                         LLViewerStats::getInstance()->mSimNetMsec.addValue(stat_value);
03442                         break;
03443                 case LL_SIM_STAT_SIMOTHERMS:
03444                         LLViewerStats::getInstance()->mSimSimOtherMsec.addValue(stat_value);
03445                         break;
03446                 case LL_SIM_STAT_SIMPHYSICSMS:
03447                         LLViewerStats::getInstance()->mSimSimPhysicsMsec.addValue(stat_value);
03448                         break;
03449                 case LL_SIM_STAT_AGENTMS:
03450                         LLViewerStats::getInstance()->mSimAgentMsec.addValue(stat_value);
03451                         break;
03452                 case LL_SIM_STAT_IMAGESMS:
03453                         LLViewerStats::getInstance()->mSimImagesMsec.addValue(stat_value);
03454                         break;
03455                 case LL_SIM_STAT_SCRIPTMS:
03456                         LLViewerStats::getInstance()->mSimScriptMsec.addValue(stat_value);
03457                         break;
03458                 case LL_SIM_STAT_NUMTASKS:
03459                         LLViewerStats::getInstance()->mSimObjects.addValue(stat_value);
03460                         break;
03461                 case LL_SIM_STAT_NUMTASKSACTIVE:
03462                         LLViewerStats::getInstance()->mSimActiveObjects.addValue(stat_value);
03463                         break;
03464                 case LL_SIM_STAT_NUMAGENTMAIN:
03465                         LLViewerStats::getInstance()->mSimMainAgents.addValue(stat_value);
03466                         break;
03467                 case LL_SIM_STAT_NUMAGENTCHILD:
03468                         LLViewerStats::getInstance()->mSimChildAgents.addValue(stat_value);
03469                         break;
03470                 case LL_SIM_STAT_NUMSCRIPTSACTIVE:
03471                         LLViewerStats::getInstance()->mSimActiveScripts.addValue(stat_value);
03472                         break;
03473                 case LL_SIM_STAT_LSLIPS:
03474                         LLViewerStats::getInstance()->mSimLSLIPS.addValue(stat_value);
03475                         break;
03476                 case LL_SIM_STAT_INPPS:
03477                         LLViewerStats::getInstance()->mSimInPPS.addValue(stat_value);
03478                         break;
03479                 case LL_SIM_STAT_OUTPPS:
03480                         LLViewerStats::getInstance()->mSimOutPPS.addValue(stat_value);
03481                         break;
03482                 case LL_SIM_STAT_PENDING_DOWNLOADS:
03483                         LLViewerStats::getInstance()->mSimPendingDownloads.addValue(stat_value);
03484                         break;
03485                 case LL_SIM_STAT_PENDING_UPLOADS:
03486                         LLViewerStats::getInstance()->mSimPendingUploads.addValue(stat_value);
03487                         break;
03488                 case LL_SIM_STAT_PENDING_LOCAL_UPLOADS:
03489                         LLViewerStats::getInstance()->mSimPendingLocalUploads.addValue(stat_value);
03490                         break;
03491                 case LL_SIM_STAT_TOTAL_UNACKED_BYTES:
03492                         LLViewerStats::getInstance()->mSimTotalUnackedBytes.addValue(stat_value / 1024.f);
03493                         break;
03494                 case LL_SIM_STAT_PHYSICS_PINNED_TASKS:
03495                         LLViewerStats::getInstance()->mPhysicsPinnedTasks.addValue(stat_value);
03496                         break;
03497                 case LL_SIM_STAT_PHYSICS_LOD_TASKS:
03498                         LLViewerStats::getInstance()->mPhysicsLODTasks.addValue(stat_value);
03499                         break;
03500                 case LL_SIM_STAT_SIMPHYSICSSTEPMS:
03501                         LLViewerStats::getInstance()->mSimSimPhysicsStepMsec.addValue(stat_value);
03502                         break;
03503                 case LL_SIM_STAT_SIMPHYSICSSHAPEMS:
03504                         LLViewerStats::getInstance()->mSimSimPhysicsShapeUpdateMsec.addValue(stat_value);
03505                         break;
03506                 case LL_SIM_STAT_SIMPHYSICSOTHERMS:
03507                         LLViewerStats::getInstance()->mSimSimPhysicsOtherMsec.addValue(stat_value);
03508                         break;
03509                 case LL_SIM_STAT_SIMPHYSICSMEMORY:
03510                         LLViewerStats::getInstance()->mPhysicsMemoryAllocated.addValue(stat_value);
03511                         break;
03512                 default:
03513                         // Used to be a commented out warning.
03514                         LL_DEBUGS("Messaging") << "Unknown stat id" << stat_id << LL_ENDL;
03515                   break;
03516                 }
03517         }
03518 
03519         /*
03520         msg->getF32Fast(_PREHASH_Statistics, _PREHASH_PhysicsTimeDilation, time_dilation);
03521         LLViewerStats::getInstance()->mSimTDStat.addValue(time_dilation);
03522 
03523         // Process information
03524         //      {       CpuUsage                        F32                             }
03525         //      {       SimMemTotal                     F32                             }
03526         //      {       SimMemRSS                       F32                             }
03527         //      {       ProcessUptime           F32                             }
03528         F32 cpu_usage;
03529         F32 sim_mem_total;
03530         F32 sim_mem_rss;
03531         F32 process_uptime;
03532         msg->getF32Fast(_PREHASH_Statistics, _PREHASH_CpuUsage, cpu_usage);
03533         msg->getF32Fast(_PREHASH_Statistics, _PREHASH_SimMemTotal, sim_mem_total);
03534         msg->getF32Fast(_PREHASH_Statistics, _PREHASH_SimMemRSS, sim_mem_rss);
03535         msg->getF32Fast(_PREHASH_Statistics, _PREHASH_ProcessUptime, process_uptime);
03536         LLViewerStats::getInstance()->mSimCPUUsageStat.addValue(cpu_usage);
03537         LLViewerStats::getInstance()->mSimMemTotalStat.addValue(sim_mem_total);
03538         LLViewerStats::getInstance()->mSimMemRSSStat.addValue(sim_mem_rss);
03539         */
03540 
03541         //
03542         // Various hacks that aren't statistics, but are being handled here.
03543         //
03544         U32 max_tasks_per_region;
03545         U32 region_flags;
03546         msg->getU32("Region", "ObjectCapacity", max_tasks_per_region);
03547         msg->getU32("Region", "RegionFlags", region_flags);
03548 
03549         LLViewerRegion* regionp = gAgent.getRegion();
03550         if (regionp)
03551         {
03552                 BOOL was_flying = gAgent.getFlying();
03553                 regionp->setRegionFlags(region_flags);
03554                 regionp->setMaxTasks(max_tasks_per_region);
03555                 // HACK: This makes agents drop from the sky if the region is 
03556                 // set to no fly while people are still in the sim.
03557                 if (was_flying && regionp->getBlockFly())
03558                 {
03559                         gAgent.setFlying(gAgent.canFly());
03560                 }
03561         }
03562 }
03563 
03564 
03565 
03566 void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data)
03567 {
03568         LLUUID  animation_id;
03569         LLUUID  uuid;
03570         S32             anim_sequence_id;
03571         LLVOAvatar *avatarp;
03572         
03573         mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid);
03574 
03575         //clear animation flags
03576         avatarp = (LLVOAvatar *)gObjectList.findObject(uuid);
03577 
03578         if (!avatarp)
03579         {
03580                 // no agent by this ID...error?
03581                 LL_WARNS("Messaging") << "Received animation state for unknown avatar" << uuid << LL_ENDL;
03582                 return;
03583         }
03584 
03585         S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationList);
03586         S32 num_source_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationSourceList);
03587 
03588         avatarp->mSignaledAnimations.clear();
03589         
03590         if (avatarp->mIsSelf)
03591         {
03592                 LLUUID object_id;
03593 
03594                 for( S32 i = 0; i < num_blocks; i++ )
03595                 {
03596                         mesgsys->getUUIDFast(_PREHASH_AnimationList, _PREHASH_AnimID, animation_id, i);
03597                         mesgsys->getS32Fast(_PREHASH_AnimationList, _PREHASH_AnimSequenceID, anim_sequence_id, i);
03598 
03599                         LL_DEBUGS("Messaging") << "Anim sequence ID: " << anim_sequence_id << LL_ENDL;
03600 
03601                         avatarp->mSignaledAnimations[animation_id] = anim_sequence_id;
03602 
03603                         if (i < num_source_blocks)
03604                         {
03605                                 mesgsys->getUUIDFast(_PREHASH_AnimationSourceList, _PREHASH_ObjectID, object_id, i);
03606                         
03607                                 LLViewerObject* object = gObjectList.findObject(object_id);
03608                                 if (object)
03609                                 {
03610                                         object->mFlags |= FLAGS_ANIM_SOURCE;
03611 
03612                                         BOOL anim_found = FALSE;
03613                                         LLVOAvatar::AnimSourceIterator anim_it = avatarp->mAnimationSources.find(object_id);
03614                                         for (;anim_it != avatarp->mAnimationSources.end(); ++anim_it)
03615                                         {
03616                                                 if (anim_it->second == animation_id)
03617                                                 {
03618                                                         anim_found = TRUE;
03619                                                         break;
03620                                                 }
03621                                         }
03622 
03623                                         if (!anim_found)
03624                                         {
03625                                                 avatarp->mAnimationSources.insert(LLVOAvatar::AnimationSourceMap::value_type(object_id, animation_id));
03626                                         }
03627                                 }
03628                         }
03629                 }
03630         }
03631         else
03632         {
03633                 for( S32 i = 0; i < num_blocks; i++ )
03634                 {
03635                         mesgsys->getUUIDFast(_PREHASH_AnimationList, _PREHASH_AnimID, animation_id, i);
03636                         mesgsys->getS32Fast(_PREHASH_AnimationList, _PREHASH_AnimSequenceID, anim_sequence_id, i);
03637                         avatarp->mSignaledAnimations[animation_id] = anim_sequence_id;
03638                 }
03639         }
03640 
03641         if (num_blocks)
03642         {
03643                 avatarp->processAnimationStateChanges();
03644         }
03645 }
03646 
03647 void process_avatar_appearance(LLMessageSystem *mesgsys, void **user_data)
03648 {
03649         LLUUID uuid;
03650         mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid);
03651 
03652         LLVOAvatar* avatarp = (LLVOAvatar *)gObjectList.findObject(uuid);
03653         if( avatarp )
03654         {
03655                 avatarp->processAvatarAppearance( mesgsys );
03656         }
03657         else
03658         {
03659                 LL_WARNS("Messaging") << "avatar_appearance sent for unknown avatar " << uuid << LL_ENDL;
03660         }
03661 }
03662 
03663 void process_camera_constraint(LLMessageSystem *mesgsys, void **user_data)
03664 {
03665         LLVector4 cameraCollidePlane;
03666         mesgsys->getVector4Fast(_PREHASH_CameraCollidePlane, _PREHASH_Plane, cameraCollidePlane);
03667 
03668         gAgent.setCameraCollidePlane(cameraCollidePlane);
03669 }
03670 
03671 void near_sit_object(BOOL success, void *data)
03672 {
03673         if (success)
03674         {
03675                 // Send message to sit on object
03676                 gMessageSystem->newMessageFast(_PREHASH_AgentSit);
03677                 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
03678                 gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
03679                 gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
03680                 gAgent.sendReliableMessage();
03681         }
03682 }
03683 
03684 void process_avatar_sit_response(LLMessageSystem *mesgsys, void **user_data)
03685 {
03686         LLVector3 sitPosition;
03687         LLQuaternion sitRotation;
03688         LLUUID sitObjectID;
03689         BOOL use_autopilot;
03690         mesgsys->getUUIDFast(_PREHASH_SitObject, _PREHASH_ID, sitObjectID);
03691         mesgsys->getBOOLFast(_PREHASH_SitTransform, _PREHASH_AutoPilot, use_autopilot);
03692         mesgsys->getVector3Fast(_PREHASH_SitTransform, _PREHASH_SitPosition, sitPosition);
03693         mesgsys->getQuatFast(_PREHASH_SitTransform, _PREHASH_SitRotation, sitRotation);
03694         LLVector3 camera_eye;
03695         mesgsys->getVector3Fast(_PREHASH_SitTransform, _PREHASH_CameraEyeOffset, camera_eye);
03696         LLVector3 camera_at;
03697         mesgsys->getVector3Fast(_PREHASH_SitTransform, _PREHASH_CameraAtOffset, camera_at);
03698         BOOL force_mouselook;
03699         mesgsys->getBOOLFast(_PREHASH_SitTransform, _PREHASH_ForceMouselook, force_mouselook);
03700 
03701         LLVOAvatar* avatar = gAgent.getAvatarObject();
03702 
03703         if (avatar && dist_vec_squared(camera_eye, camera_at) > 0.0001f)
03704         {
03705                 gAgent.setSitCamera(sitObjectID, camera_eye, camera_at);
03706         }
03707         
03708         gAgent.mForceMouselook = force_mouselook;
03709 
03710         LLViewerObject* object = gObjectList.findObject(sitObjectID);
03711         if (object)
03712         {
03713                 LLVector3 sit_spot = object->getPositionAgent() + (sitPosition * object->getRotation());
03714                 if (!use_autopilot || (avatar && avatar->mIsSitting && avatar->getRoot() == object->getRoot()))
03715                 {
03716                         //we're already sitting on this object, so don't autopilot
03717                 }
03718                 else
03719                 {
03720                         gAgent.startAutoPilotGlobal(gAgent.getPosGlobalFromAgent(sit_spot), "Sit", &sitRotation, near_sit_object, NULL, 0.5f);
03721                 }
03722         }
03723         else
03724         {
03725                 LL_WARNS("Messaging") << "Received sit approval for unknown object " << sitObjectID << LL_ENDL;
03726         }
03727 }
03728 
03729 void process_clear_follow_cam_properties(LLMessageSystem *mesgsys, void **user_data)
03730 {
03731         LLUUID          source_id;
03732 
03733         mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_ObjectID, source_id);
03734 
03735         LLFollowCamMgr::removeFollowCamParams(source_id);
03736 }
03737 
03738 void process_set_follow_cam_properties(LLMessageSystem *mesgsys, void **user_data)
03739 {
03740         S32                     type;
03741         F32                     value;
03742         bool            settingPosition = false;
03743         bool            settingFocus    = false;
03744         bool            settingFocusOffset = false;
03745         LLVector3       position;
03746         LLVector3       focus;
03747         LLVector3       focus_offset;
03748 
03749         LLUUID          source_id;
03750 
03751         mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_ObjectID, source_id);
03752 
03753         LLViewerObject* objectp = gObjectList.findObject(source_id);
03754         if (objectp)
03755         {
03756                 objectp->mFlags |= FLAGS_CAMERA_SOURCE;
03757         }
03758 
03759         S32 num_objects = mesgsys->getNumberOfBlocks("CameraProperty");
03760         for (S32 block_index = 0; block_index < num_objects; block_index++)
03761         {
03762                 mesgsys->getS32("CameraProperty", "Type", type, block_index);
03763                 mesgsys->getF32("CameraProperty", "Value", value, block_index);
03764                 switch(type)
03765                 {
03766                 case FOLLOWCAM_PITCH:
03767                         LLFollowCamMgr::setPitch(source_id, value);
03768                         break;
03769                 case FOLLOWCAM_FOCUS_OFFSET_X:
03770                         focus_offset.mV[VX] = value;
03771                         settingFocusOffset = true;
03772                         break;
03773                 case FOLLOWCAM_FOCUS_OFFSET_Y:
03774                         focus_offset.mV[VY] = value;
03775                         settingFocusOffset = true;
03776                         break;
03777                 case FOLLOWCAM_FOCUS_OFFSET_Z:
03778                         focus_offset.mV[VZ] = value;
03779                         settingFocusOffset = true;
03780                         break;
03781                 case FOLLOWCAM_POSITION_LAG:
03782                         LLFollowCamMgr::setPositionLag(source_id, value);
03783                         break;
03784                 case FOLLOWCAM_FOCUS_LAG:
03785                         LLFollowCamMgr::setFocusLag(source_id, value);
03786                         break;
03787                 case FOLLOWCAM_DISTANCE:
03788                         LLFollowCamMgr::setDistance(source_id, value);
03789                         break;
03790                 case FOLLOWCAM_BEHINDNESS_ANGLE:
03791                         LLFollowCamMgr::setBehindnessAngle(source_id, value);
03792                         break;
03793                 case FOLLOWCAM_BEHINDNESS_LAG:
03794                         LLFollowCamMgr::setBehindnessLag(source_id, value);
03795                         break;
03796                 case FOLLOWCAM_POSITION_THRESHOLD:
03797                         LLFollowCamMgr::setPositionThreshold(source_id, value);
03798                         break;
03799                 case FOLLOWCAM_FOCUS_THRESHOLD:
03800                         LLFollowCamMgr::setFocusThreshold(source_id, value);
03801                         break;
03802                 case FOLLOWCAM_ACTIVE:
03803                         //if 1, set using followcam,. 
03804                         LLFollowCamMgr::setCameraActive(source_id, value != 0.f);
03805                         break;
03806                 case FOLLOWCAM_POSITION_X:
03807                         settingPosition = true;
03808                         position.mV[ 0 ] = value;
03809                         break;
03810                 case FOLLOWCAM_POSITION_Y:
03811                         settingPosition = true;
03812                         position.mV[ 1 ] = value;
03813                         break;
03814                 case FOLLOWCAM_POSITION_Z:
03815                         settingPosition = true;
03816                         position.mV[ 2 ] = value;
03817                         break;
03818                 case FOLLOWCAM_FOCUS_X:
03819                         settingFocus = true;
03820                         focus.mV[ 0 ] = value;
03821                         break;
03822                 case FOLLOWCAM_FOCUS_Y:
03823                         settingFocus = true;
03824                         focus.mV[ 1 ] = value;
03825                         break;
03826                 case FOLLOWCAM_FOCUS_Z:
03827                         settingFocus = true;
03828                         focus.mV[ 2 ] = value;
03829                         break;
03830                 case FOLLOWCAM_POSITION_LOCKED:
03831                         LLFollowCamMgr::setPositionLocked(source_id, value != 0.f);
03832                         break;
03833                 case FOLLOWCAM_FOCUS_LOCKED:
03834                         LLFollowCamMgr::setFocusLocked(source_id, value != 0.f);
03835                         break;
03836 
03837                 default:
03838                         break;
03839                 }
03840         }
03841 
03842         if ( settingPosition )
03843         {
03844                 LLFollowCamMgr::setPosition(source_id, position);
03845         }
03846         if ( settingFocus )
03847         {
03848                 LLFollowCamMgr::setFocus(source_id, focus);
03849         }
03850         if ( settingFocusOffset )
03851         {
03852                 LLFollowCamMgr::setFocusOffset(source_id, focus_offset);
03853         }
03854 }
03855 //end Ventrella 
03856 
03857 
03858 // Culled from newsim lltask.cpp
03859 void process_name_value(LLMessageSystem *mesgsys, void **user_data)
03860 {
03861         char    temp_str[NAME_VALUE_BUF_SIZE];          /* Flawfinder: ignore */
03862         LLUUID  id;
03863         S32             i, num_blocks;
03864 
03865         mesgsys->getUUIDFast(_PREHASH_TaskData, _PREHASH_ID, id);
03866 
03867         LLViewerObject* object = gObjectList.findObject(id);
03868 
03869         if (object)
03870         {
03871                 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_NameValueData);
03872                 for (i = 0; i < num_blocks; i++)
03873                 {
03874                         mesgsys->getStringFast(_PREHASH_NameValueData, _PREHASH_NVPair, NAME_VALUE_BUF_SIZE, temp_str, i);
03875                         LL_INFOS("Messaging") << "Added to object Name Value: " << temp_str << LL_ENDL;
03876                         object->addNVPair(temp_str);
03877                 }
03878         }
03879         else
03880         {
03881                 LL_INFOS("Messaging") << "Can't find object " << id << " to add name value pair" << LL_ENDL;
03882         }
03883 }
03884 
03885 void process_remove_name_value(LLMessageSystem *mesgsys, void **user_data)
03886 {
03887         char    temp_str[NAME_VALUE_BUF_SIZE];          /* Flawfinder: ignore */
03888         LLUUID  id;
03889         S32             i, num_blocks;
03890 
03891         mesgsys->getUUIDFast(_PREHASH_TaskData, _PREHASH_ID, id);
03892 
03893         LLViewerObject* object = gObjectList.findObject(id);
03894 
03895         if (object)
03896         {
03897                 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_NameValueData);
03898                 for (i = 0; i < num_blocks; i++)
03899                 {
03900                         mesgsys->getStringFast(_PREHASH_NameValueData, _PREHASH_NVPair, NAME_VALUE_BUF_SIZE, temp_str, i);
03901                         LL_INFOS("Messaging") << "Removed from object Name Value: " << temp_str << LL_ENDL;
03902                         object->removeNVPair(temp_str);
03903                 }
03904         }
03905         else
03906         {
03907                 LL_INFOS("Messaging") << "Can't find object " << id << " to remove name value pair" << LL_ENDL;
03908         }
03909 }
03910 
03911 void process_kick_user(LLMessageSystem *msg, void** /*user_data*/)
03912 {
03913         char message[2048];             /* Flawfinder: ignore */
03914         message[0] = '\0';
03915 
03916         msg->getStringFast(_PREHASH_UserInfo, _PREHASH_Reason, 2048, message);
03917 
03918         LLAppViewer::instance()->forceDisconnect(message);
03919 }
03920 
03921 
03922 /*
03923 void process_user_list_reply(LLMessageSystem *msg, void **user_data)
03924 {
03925         LLUserList::processUserListReply(msg, user_data);
03926         return;
03927         char    firstname[MAX_STRING+1];
03928         char    lastname[MAX_STRING+1];
03929         U8              status;
03930         S32             user_count;
03931 
03932         user_count = msg->getNumberOfBlocks("UserBlock");
03933 
03934         for (S32 i = 0; i < user_count; i++)
03935         {
03936                 msg->getData("UserBlock", i, "FirstName", firstname);
03937                 msg->getData("UserBlock", i, "LastName", lastname);
03938                 msg->getData("UserBlock", i, "Status", &status);
03939 
03940                 if (status & 0x01)
03941                 {
03942                         dialog_friends_add_friend(buffer, TRUE);
03943                 }
03944                 else
03945                 {
03946                         dialog_friends_add_friend(buffer, FALSE);
03947                 }
03948         }
03949 
03950         dialog_friends_done_adding();
03951 }
03952 */
03953 
03954 // this is not handled in processUpdateMessage
03955 /*
03956 void process_time_dilation(LLMessageSystem *msg, void **user_data)
03957 {
03958         // get the time_dilation
03959         U16 foo;
03960         msg->getData("TimeDilation", "TimeDilation", &foo);
03961         F32 time_dilation = ((F32) foo) / 65535.f;
03962 
03963         // get the pointer to the right region
03964         U32 ip = msg->getSenderIP();
03965         U32 port = msg->getSenderPort();
03966         LLViewerRegion *regionp = LLWorld::getInstance()->getRegion(ip, port);
03967         if (regionp)
03968         {
03969                 regionp->setTimeDilation(time_dilation);
03970         }
03971 }
03972 */
03973 
03974 
03975 
03976 void process_money_balance_reply( LLMessageSystem* msg, void** )
03977 {
03978         S32 balance = 0;
03979         S32 credit = 0;
03980         S32 committed = 0;
03981         char desc[STD_STRING_BUF_SIZE] = "";            /* Flawfinder: ignore */
03982 
03983         msg->getS32("MoneyData", "MoneyBalance", balance);
03984         msg->getS32("MoneyData", "SquareMetersCredit", credit);
03985         msg->getS32("MoneyData", "SquareMetersCommitted", committed);
03986         msg->getStringFast(_PREHASH_MoneyData, _PREHASH_Description,    STD_STRING_BUF_SIZE,    desc);
03987         LL_INFOS("Messaging") << "L$, credit, committed: " << balance << " " << credit << " "
03988                         << committed << LL_ENDL;
03989 
03990         if (gStatusBar)
03991         {
03992                 S32 old_balance = gStatusBar->getBalance();
03993 
03994                 // This is an update, not the first transmission of balance
03995                 if (old_balance != 0)
03996                 {
03997                         // this is actually an update
03998                         if (balance > old_balance)
03999                         {
04000                                 LLFirstUse::useBalanceIncrease(balance - old_balance);
04001                         }
04002                         else if (balance < old_balance)
04003                         {
04004                                 LLFirstUse::useBalanceDecrease(balance - old_balance);
04005                         }
04006                 }
04007 
04008                 gStatusBar->setBalance(balance);
04009                 gStatusBar->setLandCredit(credit);
04010                 gStatusBar->setLandCommitted(committed);
04011         }
04012 
04013         LLUUID tid;
04014         msg->getUUID("MoneyData", "TransactionID", tid);
04015         static std::deque<LLUUID> recent;
04016         if(desc[0] && gSavedSettings.getBOOL("NotifyMoneyChange")
04017            && (std::find(recent.rbegin(), recent.rend(), tid) == recent.rend()))
04018         {
04019                 // Make the user confirm the transaction, since they might
04020                 // have missed something during an event.
04021                 // *TODO:translate
04022                 LLString::format_map_t args;
04023                 args["[MESSAGE]"] = desc;
04024                 LLNotifyBox::showXml("SystemMessage", args);
04025 
04026                 // Once the 'recent' container gets large enough, chop some
04027                 // off the beginning.
04028                 const U32 MAX_LOOKBACK = 30;
04029                 const S32 POP_FRONT_SIZE = 12;
04030                 if(recent.size() > MAX_LOOKBACK)
04031                 {
04032                         LL_DEBUGS("Messaging") << "Removing oldest transaction records" << LL_ENDL;
04033                         recent.erase(recent.begin(), recent.begin() + POP_FRONT_SIZE);
04034                 }
04035                 //LL_DEBUGS("Messaging") << "Pushing back transaction " << tid << LL_ENDL;
04036                 recent.push_back(tid);
04037         }
04038 }
04039 
04040 void process_agent_alert_message(LLMessageSystem* msgsystem, void** user_data)
04041 {
04042         char buffer[MAX_STRING];                /* Flawfinder: ignore */
04043         msgsystem->getStringFast(_PREHASH_AlertData, _PREHASH_Message, MAX_STRING, buffer);
04044         BOOL modal = FALSE;
04045         msgsystem->getBOOL("AlertData", "Modal", modal);
04046         process_alert_core(buffer, modal);
04047 }
04048 
04049 void process_alert_message(LLMessageSystem *msgsystem, void **user_data)
04050 {
04051         char buffer[MAX_STRING];                /* Flawfinder: ignore */
04052         msgsystem->getStringFast(_PREHASH_AlertData, _PREHASH_Message, MAX_STRING, buffer);
04053         BOOL modal = FALSE;
04054         process_alert_core(buffer, modal);
04055 }
04056 
04057 void process_alert_core(const std::string& message, BOOL modal)
04058 {
04059         // make sure the cursor is back to the usual default since the
04060         // alert is probably due to some kind of error.
04061         gViewerWindow->getWindow()->resetBusyCount();
04062 
04063         // HACK -- handle callbacks for specific alerts
04064         if ( message == "You died and have been teleported to your home location")
04065         {
04066                 LLViewerStats::getInstance()->incStat(LLViewerStats::ST_KILLED_COUNT);
04067         }
04068         else if( message == "Home position set." )
04069         {
04070                 // save the home location image to disk
04071                 LLString snap_filename = gDirUtilp->getLindenUserDir();
04072                 snap_filename += gDirUtilp->getDirDelimiter();
04073                 snap_filename += SCREEN_HOME_FILENAME;
04074                 gViewerWindow->saveSnapshot(snap_filename, gViewerWindow->getWindowDisplayWidth(), gViewerWindow->getWindowDisplayHeight(), FALSE, FALSE);
04075         }
04076 
04077         const std::string ALERT_PREFIX("ALERT: ");
04078         const std::string NOTIFY_PREFIX("NOTIFY: ");
04079         if (message.find(ALERT_PREFIX) == 0)
04080         {
04081                 // Allow the server to spawn a named alert so that server alerts can be
04082                 // translated out of English.
04083                 std::string alert_name(message.substr(ALERT_PREFIX.length()));
04084                 LLAlertDialog::showXml(alert_name);
04085         }
04086         else if (message.find(NOTIFY_PREFIX) == 0)
04087         {
04088                 // Allow the server to spawn a named notification so that server notifications can be
04089                 // translated out of English.
04090                 std::string notify_name(message.substr(NOTIFY_PREFIX.length()));
04091                 LLNotifyBox::showXml(notify_name);
04092         }
04093         else if (message[0] == '/')
04094         {
04095                 // System message is important, show in upper-right box not tip
04096                 LLString text(message.substr(1));
04097                 LLString::format_map_t args;
04098                 if (text.substr(0,17) == "RESTART_X_MINUTES")
04099                 {
04100                         S32 mins = 0;
04101                         LLString::convertToS32(text.substr(18), mins);
04102                         args["[MINUTES]"] = llformat("%d",mins);
04103                         LLNotifyBox::showXml("RegionRestartMinutes", args);
04104                 }
04105                 else if (text.substr(0,17) == "RESTART_X_SECONDS")
04106                 {
04107                         S32 secs = 0;
04108                         LLString::convertToS32(text.substr(18), secs);
04109                         args["[SECONDS]"] = llformat("%d",secs);
04110                         LLNotifyBox::showXml("RegionRestartSeconds", args);
04111                 }
04112                 else
04113                 {
04114                         // *TODO:translate
04115                         args["[MESSAGE]"] = text;
04116                         LLNotifyBox::showXml("SystemMessage", args);
04117                 }
04118         }
04119         else if (modal)
04120         {
04121                 // *TODO:translate
04122                 LLString::format_map_t args;
04123                 args["[ERROR_MESSAGE]"] = message;
04124                 gViewerWindow->alertXml("ErrorMessage", args);
04125         }
04126         else
04127         {
04128                 // *TODO:translate
04129                 LLString::format_map_t args;
04130                 args["[MESSAGE]"] = message;
04131                 LLNotifyBox::showXml("SystemMessageTip", args);
04132         }
04133 }
04134 
04135 mean_collision_list_t                           gMeanCollisionList;
04136 time_t                                                          gLastDisplayedTime = 0;
04137 
04138 void handle_show_mean_events(void *)
04139 {
04140         if (gNoRender)
04141         {
04142                 return;
04143         }
04144 
04145         LLFloaterBump::show(NULL);
04146 }
04147 
04148 void mean_name_callback(const LLUUID &id, const char *first, const char *last, BOOL always_false, void* data)
04149 {
04150         if (gNoRender)
04151         {
04152                 return;
04153         }
04154 
04155         static const int max_collision_list_size = 20;
04156         if (gMeanCollisionList.size() > max_collision_list_size)
04157         {
04158                 mean_collision_list_t::iterator iter = gMeanCollisionList.begin();
04159                 for (S32 i=0; i<max_collision_list_size; i++) iter++;
04160                 for_each(iter, gMeanCollisionList.end(), DeletePointer());
04161                 gMeanCollisionList.erase(iter, gMeanCollisionList.end());
04162         }
04163 
04164         for (mean_collision_list_t::iterator iter = gMeanCollisionList.begin();
04165                  iter != gMeanCollisionList.end(); ++iter)
04166         {
04167                 LLMeanCollisionData *mcd = *iter;
04168                 if (mcd->mPerp == id)
04169                 {
04170                         strncpy(mcd->mFirstName, first, DB_FIRST_NAME_BUF_SIZE -1);             /* Flawfinder: ignore */
04171                         mcd->mFirstName[DB_FIRST_NAME_BUF_SIZE -1] = '\0';
04172                         strncpy(mcd->mLastName, last, DB_LAST_NAME_BUF_SIZE -1);                /* Flawfinder: ignore */
04173                         mcd->mLastName[DB_LAST_NAME_BUF_SIZE -1] = '\0';
04174                 }
04175         }
04176 }
04177 
04178 void process_mean_collision_alert_message(LLMessageSystem *msgsystem, void **user_data)
04179 {
04180         if (gAgent.inPrelude())
04181         {
04182                 // JC: In prelude, bumping is OK.  This dialog is rather confusing to 
04183                 // newbies, so we don't show it.  Drop the packet on the floor.
04184                 return;
04185         }
04186 
04187         // make sure the cursor is back to the usual default since the
04188         // alert is probably due to some kind of error.
04189         gViewerWindow->getWindow()->resetBusyCount();
04190 
04191         LLUUID perp;
04192         U32        time;
04193         U8         u8type;
04194         EMeanCollisionType         type;
04195         F32    mag;
04196 
04197         S32 i, num = msgsystem->getNumberOfBlocks(_PREHASH_MeanCollision);
04198 
04199         for (i = 0; i < num; i++)
04200         {
04201                 msgsystem->getUUIDFast(_PREHASH_MeanCollision, _PREHASH_Perp, perp);
04202                 msgsystem->getU32Fast(_PREHASH_MeanCollision, _PREHASH_Time, time);
04203                 msgsystem->getF32Fast(_PREHASH_MeanCollision, _PREHASH_Mag, mag);
04204                 msgsystem->getU8Fast(_PREHASH_MeanCollision, _PREHASH_Type, u8type);
04205 
04206                 type = (EMeanCollisionType)u8type;
04207 
04208                 BOOL b_found = FALSE;
04209 
04210                 for (mean_collision_list_t::iterator iter = gMeanCollisionList.begin();
04211                          iter != gMeanCollisionList.end(); ++iter)
04212                 {
04213                         LLMeanCollisionData *mcd = *iter;
04214                         if ((mcd->mPerp == perp) && (mcd->mType == type))
04215                         {
04216                                 mcd->mTime = time;
04217                                 mcd->mMag = mag;
04218                                 b_found = TRUE;
04219                                 break;
04220                         }
04221                 }
04222 
04223                 if (!b_found)
04224                 {
04225                         LLMeanCollisionData *mcd = new LLMeanCollisionData(gAgentID, perp, time, type, mag);
04226                         gMeanCollisionList.push_front(mcd);
04227                         const BOOL is_group = FALSE;
04228                         gCacheName->get(perp, is_group, mean_name_callback);
04229                 }
04230         }
04231 }
04232 
04233 void process_frozen_message(LLMessageSystem *msgsystem, void **user_data)
04234 {
04235         // make sure the cursor is back to the usual default since the
04236         // alert is probably due to some kind of error.
04237         gViewerWindow->getWindow()->resetBusyCount();
04238         BOOL b_frozen;
04239         
04240         msgsystem->getBOOL("FrozenData", "Data", b_frozen);
04241 
04242         // TODO: make being frozen change view
04243         if (b_frozen)
04244         {
04245         }
04246         else
04247         {
04248         }
04249 }
04250 
04251 // do some extra stuff once we get our economy data
04252 void process_economy_data(LLMessageSystem *msg, void** /*user_data*/)
04253 {
04254         LLGlobalEconomy::processEconomyData(msg, LLGlobalEconomy::Singleton::getInstance());
04255 
04256         S32 upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
04257         LLFloaterImagePreview::setUploadAmount(upload_cost);
04258 
04259         gMenuHolder->childSetLabelArg("Upload Image", "[COST]", llformat("%d", upload_cost));
04260         gMenuHolder->childSetLabelArg("Upload Sound", "[COST]", llformat("%d", upload_cost));
04261         gMenuHolder->childSetLabelArg("Upload Animation", "[COST]", llformat("%d", upload_cost));
04262         gMenuHolder->childSetLabelArg("Bulk Upload", "[COST]", llformat("%d", upload_cost));
04263 }
04264 
04265 class LLScriptQuestionCBData
04266 {
04267 public:
04268         LLScriptQuestionCBData(const LLUUID &taskid, const LLUUID &itemid, const LLHost &sender, S32 questions, const char *object_name, const char *owner_name)
04269                 : mTaskID(taskid), mItemID(itemid), mSender(sender), mQuestions(questions), mObjectName(object_name), mOwnerName(owner_name)
04270         {
04271         }
04272 
04273         LLUUID mTaskID;
04274         LLUUID mItemID;
04275         LLHost mSender;
04276         S32        mQuestions;
04277         LLString mObjectName;
04278         LLString mOwnerName;
04279 };
04280 
04281 void notify_cautioned_script_question(LLScriptQuestionCBData* cbdata, S32 orig_questions, BOOL granted)
04282 {
04283         // only continue if at least some permissions were requested
04284         if (orig_questions)
04285         {
04286                 // check to see if the person we are asking
04287 
04288                 // "'[OBJECTNAME]', an object owned by '[OWNERNAME]', 
04289                 // located in [REGIONNAME] at [REGIONPOS], 
04290                 // has been <granted|denied> permission to: [PERMISSIONS]."
04291 
04292                 LLUIString notice(LLNotifyBox::getTemplateMessage(granted ? "ScriptQuestionCautionChatGranted" : "ScriptQuestionCautionChatDenied"));
04293 
04294                 // always include the object name and owner name 
04295                 notice.setArg("[OBJECTNAME]", cbdata->mObjectName);
04296                 notice.setArg("[OWNERNAME]", cbdata->mOwnerName);
04297 
04298                 // try to lookup viewerobject that corresponds to the object that
04299                 // requested permissions (here, taskid->requesting object id)
04300                 BOOL foundpos = FALSE;
04301                 LLViewerObject* viewobj = gObjectList.findObject(cbdata->mTaskID);
04302                 if (viewobj)
04303                 {
04304                         // found the viewerobject, get it's position in its region
04305                         LLVector3 objpos(viewobj->getPosition());
04306                         
04307                         // try to lookup the name of the region the object is in
04308                         LLViewerRegion* viewregion = viewobj->getRegion();
04309                         if (viewregion)
04310                         {
04311                                 // got the region, so include the region and 3d coordinates of the object
04312                                 notice.setArg("[REGIONNAME]", viewregion->getName());                           
04313                                 LLString formatpos = llformat("%.1f, %.1f,%.1f", objpos[VX], objpos[VY], objpos[VZ]);
04314                                 notice.setArg("[REGIONPOS]", formatpos);
04315 
04316                                 foundpos = TRUE;
04317                         }
04318                 }
04319 
04320                 if (!foundpos)
04321                 {
04322                         // unable to determine location of the object
04323                         notice.setArg("[REGIONNAME]", "(unknown region)");
04324                         notice.setArg("[REGIONPOS]", "(unknown position)");
04325                 }
04326 
04327                 // check each permission that was requested, and list each 
04328                 // permission that has been flagged as a caution permission
04329                 BOOL caution = FALSE;
04330                 S32 count = 0;
04331                 LLString perms;
04332                 for (S32 i = 0; i < SCRIPT_PERMISSION_EOF; i++)
04333                 {
04334                         if ((orig_questions & LSCRIPTRunTimePermissionBits[i]) && LLNotifyBox::getTemplateIsCaution(SCRIPT_QUESTIONS[i]))
04335                         {
04336                                 count++;
04337                                 caution = TRUE;
04338 
04339                                 // add a comma before the permission description if it is not the first permission
04340                                 // added to the list or the last permission to check
04341                                 if ((count > 1) && (i < SCRIPT_PERMISSION_EOF))
04342                                 {
04343                                         perms.append(", ");
04344                                 }
04345 
04346                                 perms.append(LLNotifyBox::getTemplateMessage(SCRIPT_QUESTIONS[i]));
04347                         }
04348                 }
04349 
04350                 notice.setArg("[PERMISSIONS]", perms);
04351 
04352                 // log a chat message as long as at least one requested permission
04353                 // is a caution permission
04354                 if (caution)
04355                 {
04356                         LLChat chat(notice.getString());
04357                         LLFloaterChat::addChat(chat, FALSE, FALSE);
04358                 }
04359         }
04360 }
04361 
04362 void script_question_decline_cb(S32 option, void* user_data)
04363 {
04364         LLMessageSystem *msg = gMessageSystem;
04365         LLScriptQuestionCBData *cbdata = (LLScriptQuestionCBData *)user_data;
04366         
04367         // remember the permissions requested so they can be checked
04368         // when it comes time to log a chat message
04369         S32 orig = cbdata->mQuestions;
04370 
04371         // this callback will always decline all permissions requested
04372         // (any question flags set in the ScriptAnswerYes message
04373         // will be interpreted as having been granted, so clearing all
04374         // the bits will deny every permission)
04375         cbdata->mQuestions = 0;
04376 
04377         // respond with the permissions denial
04378         msg->newMessageFast(_PREHASH_ScriptAnswerYes);
04379         msg->nextBlockFast(_PREHASH_AgentData);
04380         msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
04381         msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
04382         msg->nextBlockFast(_PREHASH_Data);
04383         msg->addUUIDFast(_PREHASH_TaskID, cbdata->mTaskID);
04384         msg->addUUIDFast(_PREHASH_ItemID, cbdata->mItemID);
04385         msg->addS32Fast(_PREHASH_Questions, cbdata->mQuestions);
04386         msg->sendReliable(cbdata->mSender);
04387 
04388         // log a chat message, if appropriate
04389         notify_cautioned_script_question(cbdata, orig, FALSE);
04390 
04391         delete cbdata;
04392 }
04393 
04394 void script_question_cb(S32 option, void* user_data)
04395 {
04396         LLMessageSystem *msg = gMessageSystem;
04397         LLScriptQuestionCBData *cbdata = (LLScriptQuestionCBData *)user_data;
04398         S32 orig = cbdata->mQuestions;
04399 
04400         // check whether permissions were granted or denied
04401         BOOL allowed = TRUE;
04402         // the "yes/accept" button is the first button in the template, making it button 0
04403         // if any other button was clicked, the permissions were denied
04404         if (option != 0)
04405         {
04406                 cbdata->mQuestions = 0;
04407                 allowed = FALSE;
04408         }       
04409 
04410         // reply with the permissions granted or denied
04411         msg->newMessageFast(_PREHASH_ScriptAnswerYes);
04412         msg->nextBlockFast(_PREHASH_AgentData);
04413         msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
04414         msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
04415         msg->nextBlockFast(_PREHASH_Data);
04416         msg->addUUIDFast(_PREHASH_TaskID, cbdata->mTaskID);
04417         msg->addUUIDFast(_PREHASH_ItemID, cbdata->mItemID);
04418         msg->addS32Fast(_PREHASH_Questions, cbdata->mQuestions);
04419         msg->sendReliable(cbdata->mSender);
04420 
04421         // only log a chat message if caution prompts are enabled
04422         if (gSavedSettings.getBOOL("PermissionsCautionEnabled"))
04423         {
04424                 // log a chat message, if appropriate
04425                 notify_cautioned_script_question(cbdata, orig, allowed);
04426         }
04427 
04428         if ( option == 2 ) // mute
04429         {
04430                 LLMuteList::getInstance()->add(LLMute(cbdata->mItemID, cbdata->mObjectName, LLMute::OBJECT));
04431 
04432                 // purge the message queue of any previously queued requests from the same source. DEV-4879
04433                 class OfferMatcher : public LLNotifyBoxView::Matcher
04434                 {
04435                 public:
04436                         OfferMatcher(const LLUUID& to_block) : blocked_id(to_block) {}
04437                         BOOL matches(LLNotifyBox::notify_callback_t callback, void* cb_data) const
04438                         {
04439                                 return callback == script_question_cb && ((LLScriptQuestionCBData*)cb_data)->mItemID == blocked_id;
04440                         }
04441                 private:
04442                         const LLUUID& blocked_id;
04443                 };
04444                 gNotifyBoxView->purgeMessagesMatching(OfferMatcher(cbdata->mItemID));
04445         }
04446         delete cbdata;
04447 }
04448 
04449 void process_script_question(LLMessageSystem *msg, void **user_data)
04450 {
04451         // *TODO:translate owner name -> [FIRST] [LAST]
04452 
04453         LLHost sender = msg->getSender();
04454 
04455         LLUUID taskid;
04456         LLUUID itemid;
04457         S32             questions;
04458         char object_name[255];          /* Flawfinder: ignore */
04459         char owner_name[DB_FULL_NAME_BUF_SIZE];         /* Flawfinder: ignore */
04460 
04461         // taskid -> object key of object requesting permissions
04462         msg->getUUIDFast(_PREHASH_Data, _PREHASH_TaskID, taskid );
04463         // itemid -> script asset key of script requesting permissions
04464         msg->getUUIDFast(_PREHASH_Data, _PREHASH_ItemID, itemid );
04465         msg->getStringFast(_PREHASH_Data, _PREHASH_ObjectName, 255, object_name);
04466         msg->getStringFast(_PREHASH_Data, _PREHASH_ObjectOwner, DB_FULL_NAME_BUF_SIZE, owner_name);
04467         msg->getS32Fast(_PREHASH_Data, _PREHASH_Questions, questions );
04468 
04469         // don't display permission requests if this object is muted - JS.
04470         if (LLMuteList::getInstance()->isMuted(taskid)) return;
04471 
04472         // throttle excessive requests from any specific user's scripts
04473         LLString throttle_owner_name = owner_name;
04474         typedef LLKeyThrottle<LLString> LLStringThrottle;
04475         static LLStringThrottle question_throttle( LLREQUEST_PERMISSION_THROTTLE_LIMIT, LLREQUEST_PERMISSION_THROTTLE_INTERVAL );
04476 
04477         switch (question_throttle.noteAction(throttle_owner_name))
04478         {
04479                 case LLStringThrottle::THROTTLE_NEWLY_BLOCKED:
04480                         LL_INFOS("Messaging") << "process_script_question throttled"
04481                                         << " owner_name:" << owner_name
04482                                         << LL_ENDL;
04483                         // Fall through
04484 
04485                 case LLStringThrottle::THROTTLE_BLOCKED:
04486                         // Escape altogether until we recover
04487                         return;
04488 
04489                 case LLStringThrottle::THROTTLE_OK:
04490                         break;
04491         }
04492 
04493         LLString script_question;
04494         if (questions)
04495         {
04496                 BOOL caution = FALSE;
04497                 S32 count = 0;
04498                 LLString::format_map_t args;
04499                 args["[OBJECTNAME]"] = object_name;
04500                 args["[NAME]"] = owner_name;
04501 
04502                 // check the received permission flags against each permission
04503                 for (S32 i = 0; i < SCRIPT_PERMISSION_EOF; i++)
04504                 {
04505                         if (questions & LSCRIPTRunTimePermissionBits[i])
04506                         {
04507                                 count++;
04508                                 script_question += "    " + LLNotifyBox::getTemplateMessage(SCRIPT_QUESTIONS[i]) + "\n";
04509 
04510                                 // check whether permission question should cause special caution dialog
04511                                 caution |= LLNotifyBox::getTemplateIsCaution(SCRIPT_QUESTIONS[i]);
04512                         }
04513                 }
04514                 args["[QUESTIONS]"] = script_question;
04515 
04516                 LLScriptQuestionCBData *cbdata = new LLScriptQuestionCBData(taskid, itemid, sender, questions, object_name, owner_name);
04517 
04518                 // check whether cautions are even enabled or not
04519                 if (gSavedSettings.getBOOL("PermissionsCautionEnabled"))
04520                 {
04521                         if (caution)
04522                         {
04523                                 // display the caution permissions prompt
04524                                 LLNotifyBox::showXml("ScriptQuestionCaution", args, TRUE, script_question_cb, cbdata);
04525                         }
04526                         else
04527                         {
04528                                 // display the permissions request normally
04529                                 LLNotifyBox::showXml("ScriptQuestion", args, FALSE, script_question_cb, cbdata);
04530                         }
04531                 }
04532                 else
04533                 {
04534                         // fall back to default behavior if cautions are entirely disabled
04535                         LLNotifyBox::showXml("ScriptQuestion", args, FALSE, script_question_cb, cbdata);
04536                 }
04537 
04538         }
04539 }
04540 
04541 
04542 void process_derez_container(LLMessageSystem *msg, void**)
04543 {
04544         LL_WARNS("Messaging") << "call to deprecated process_derez_container" << LL_ENDL;
04545 }
04546 
04547 void container_inventory_arrived(LLViewerObject* object,
04548                                                                  InventoryObjectList* inventory,
04549                                                                  S32 serial_num,
04550                                                                  void* data)
04551 {
04552         LL_DEBUGS("Messaging") << "container_inventory_arrived()" << LL_ENDL;
04553         if( gAgent.cameraMouselook() )
04554         {
04555                 gAgent.changeCameraToDefault();
04556         }
04557 
04558         LLInventoryView* view = LLInventoryView::getActiveInventory();
04559 
04560         if (inventory->size() > 2)
04561         {
04562                 // create a new inventory category to put this in
04563                 LLUUID cat_id;
04564                 cat_id = gInventory.createNewCategory(gAgent.getInventoryRootID(),
04565                                                                                           LLAssetType::AT_NONE,
04566                                                                                           "Acquired Items");
04567 
04568                 InventoryObjectList::const_iterator it = inventory->begin();
04569                 InventoryObjectList::const_iterator end = inventory->end();
04570                 for ( ; it != end; ++it)
04571                 {
04572                         if ((*it)->getType() != LLAssetType::AT_CATEGORY &&
04573                                 (*it)->getType() != LLAssetType::AT_ROOT_CATEGORY)
04574                         {
04575                                 LLInventoryObject* obj = (LLInventoryObject*)(*it);
04576                                 LLInventoryItem* item = (LLInventoryItem*)(obj);
04577                                 LLUUID item_id;
04578                                 item_id.generate();
04579                                 S32 creation_date_utc = time_corrected();
04580                                 LLPointer<LLViewerInventoryItem> new_item
04581                                         = new LLViewerInventoryItem(item_id,
04582                                                                                                 cat_id,
04583                                                                                                 item->getPermissions(),
04584                                                                                                 item->getAssetUUID(),
04585                                                                                                 item->getType(),
04586                                                                                                 item->getInventoryType(),
04587                                                                                                 item->getName(),
04588                                                                                                 item->getDescription(),
04589                                                                                                 LLSaleInfo::DEFAULT,
04590                                                                                                 item->getFlags(),
04591                                                                                                 creation_date_utc);
04592                                 new_item->updateServer(TRUE);
04593                                 gInventory.updateItem(new_item);
04594                         }
04595                 }
04596                 gInventory.notifyObservers();
04597                 if(view)
04598                 {
04599                         view->getPanel()->setSelection(cat_id, TAKE_FOCUS_NO);
04600                 }
04601         }
04602         else if (inventory->size() == 2)
04603         {
04604                 // we're going to get one fake root category as well as the
04605                 // one actual object
04606                 InventoryObjectList::iterator it = inventory->begin();
04607 
04608                 if ((*it)->getType() == LLAssetType::AT_CATEGORY ||
04609                         (*it)->getType() == LLAssetType::AT_ROOT_CATEGORY)
04610                 {
04611                         ++it;
04612                 }
04613 
04614                 LLInventoryItem* item = (LLInventoryItem*)((LLInventoryObject*)(*it));
04615                 LLUUID category = gInventory.findCategoryUUIDForType(item->getType());
04616 
04617                 LLUUID item_id;
04618                 item_id.generate();
04619                 S32 creation_date_utc = time_corrected();
04620                 LLPointer<LLViewerInventoryItem> new_item
04621                         = new LLViewerInventoryItem(item_id, category,
04622                                                                                 item->getPermissions(),
04623                                                                                 item->getAssetUUID(),
04624                                                                                 item->getType(),
04625                                                                                 item->getInventoryType(),
04626                                                                                 item->getName(),
04627                                                                                 item->getDescription(),
04628                                                                                 LLSaleInfo::DEFAULT,
04629                                                                                 item->getFlags(),
04630                                                                                 creation_date_utc);
04631                 new_item->updateServer(TRUE);
04632                 gInventory.updateItem(new_item);
04633                 gInventory.notifyObservers();
04634                 if(view)
04635                 {
04636                         view->getPanel()->setSelection(item_id, TAKE_FOCUS_NO);
04637                 }
04638         }
04639 
04640         // we've got the inventory, now delete this object if this was a take
04641         BOOL delete_object = (BOOL)(intptr_t)data;
04642         LLViewerRegion *region = gAgent.getRegion();
04643         if (delete_object && region)
04644         {
04645                 gMessageSystem->newMessageFast(_PREHASH_ObjectDelete);
04646                 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
04647                 gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
04648                 gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
04649                 const U8 NO_FORCE = 0;
04650                 gMessageSystem->addU8Fast(_PREHASH_Force, NO_FORCE);
04651                 gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
04652                 gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID());
04653                 gMessageSystem->sendReliable(region->getHost());
04654         }
04655 }
04656 
04657 // method to format the time. Buffer should be at least
04658 // TIME_STR_LENGTH long, and the function returns buffer (for use in
04659 // sprintf and the like)
04660 char* formatted_time(const time_t& the_time, char* buffer)
04661 {
04662         LLString::copy(buffer, ctime(&the_time), TIME_STR_LENGTH);
04663         buffer[24] = '\0';
04664         return buffer;
04665 }
04666 
04667 
04668 void process_teleport_failed(LLMessageSystem *msg, void**)
04669 {
04670         char reason[STD_STRING_BUF_SIZE];               /* Flawfinder: ignore */
04671         msg->getStringFast(_PREHASH_Info, _PREHASH_Reason, STD_STRING_BUF_SIZE, reason);
04672 
04673         LLStringBase<char>::format_map_t args;
04674         LLString big_reason = LLAgent::sTeleportErrorMessages[reason];
04675         if ( big_reason.size() > 0 )
04676         {       // Substitute verbose reason from the local map
04677                 args["[REASON]"] = big_reason;
04678         }
04679         else
04680         {       // Nothing found in the map - use what the server returned
04681                 args["[REASON]"] = reason;
04682         }
04683 
04684         gViewerWindow->alertXml("CouldNotTeleportReason", args);
04685 
04686         if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE )
04687         {
04688                 gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
04689         }
04690 }
04691 
04692 void process_teleport_local(LLMessageSystem *msg,void**)
04693 {
04694         LLUUID agent_id;
04695         msg->getUUIDFast(_PREHASH_Info, _PREHASH_AgentID, agent_id);
04696         if (agent_id != gAgent.getID())
04697         {
04698                 LL_WARNS("Messaging") << "Got teleport notification for wrong agent!" << LL_ENDL;
04699                 return;
04700         }
04701 
04702         U32 location_id;
04703         LLVector3 pos, look_at;
04704         U32 teleport_flags;
04705         msg->getU32Fast(_PREHASH_Info, _PREHASH_LocationID, location_id);
04706         msg->getVector3Fast(_PREHASH_Info, _PREHASH_Position, pos);
04707         msg->getVector3Fast(_PREHASH_Info, _PREHASH_LookAt, look_at);
04708         msg->getU32Fast(_PREHASH_Info, _PREHASH_TeleportFlags, teleport_flags);
04709 
04710         if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE )
04711         {
04712                 gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
04713         }
04714 
04715         // Sim tells us whether the new position is off the ground
04716         if (teleport_flags & TELEPORT_FLAGS_IS_FLYING)
04717         {
04718                 gAgent.setFlying(TRUE);
04719         }
04720         else
04721         {
04722                 gAgent.setFlying(FALSE);
04723         }
04724 
04725         gAgent.setPositionAgent(pos);
04726         gAgent.slamLookAt(look_at);
04727 
04728         // likewise make sure the camera is behind the avatar
04729         gAgent.resetView(TRUE);
04730 
04731         // send camera update to new region
04732         gAgent.updateCamera();
04733 
04734         send_agent_update(TRUE, TRUE);
04735 }
04736 
04737 void send_simple_im(const LLUUID& to_id,
04738                                         const char* message,
04739                                         EInstantMessage dialog,
04740                                         const LLUUID& id)
04741 {
04742         std::string my_name;
04743         gAgent.buildFullname(my_name);
04744         send_improved_im(to_id,
04745                                          my_name.c_str(),
04746                                          message,
04747                                          IM_ONLINE,
04748                                          dialog,
04749                                          id,
04750                                          NO_TIMESTAMP,
04751                                          (U8*)EMPTY_BINARY_BUCKET,
04752                                          EMPTY_BINARY_BUCKET_SIZE);
04753 }
04754 
04755 void send_group_notice(const LLUUID& group_id,
04756                                            const char* subject,
04757                                            const char* message,
04758                                            const LLInventoryItem* item)
04759 {
04760         // Put this notice into an instant message form.
04761         // This will mean converting the item to a binary bucket,
04762         // and the subject/message into a single field.
04763         std::string my_name;
04764         gAgent.buildFullname(my_name);
04765 
04766         // Combine subject + message into a single string.
04767         std::ostringstream subject_and_message;
04768         // TODO: turn all existing |'s into ||'s in subject and message.
04769         subject_and_message << subject << "|" << message;
04770 
04771         // Create an empty binary bucket.
04772         U8 bin_bucket[MAX_INVENTORY_BUFFER_SIZE];
04773         U8* bucket_to_send = bin_bucket;
04774         bin_bucket[0] = '\0';
04775         S32 bin_bucket_size = EMPTY_BINARY_BUCKET_SIZE;
04776         // If there is an item being sent, pack it into the binary bucket.
04777         if (item)
04778         {
04779                 LLSD item_def;
04780                 item_def["item_id"] = item->getUUID();
04781                 item_def["owner_id"] = item->getPermissions().getOwner();
04782                 std::ostringstream ostr;
04783                 LLSDSerialize::serialize(item_def, ostr, LLSDSerialize::LLSD_XML);
04784                 bin_bucket_size = ostr.str().copy(
04785                         (char*)bin_bucket, ostr.str().size());
04786                 bin_bucket[bin_bucket_size] = '\0';
04787         }
04788         else
04789         {
04790                 bucket_to_send = (U8*) EMPTY_BINARY_BUCKET;
04791         }
04792    
04793 
04794         send_improved_im(
04795                         group_id,
04796                         my_name.c_str(),
04797                         subject_and_message.str().c_str(),
04798                         IM_ONLINE,
04799                         IM_GROUP_NOTICE,
04800                         LLUUID::null,
04801                         NO_TIMESTAMP,
04802                         bucket_to_send,
04803                         bin_bucket_size);
04804 }
04805 
04806 void handle_lure_callback(S32 option, const LLString& text, void* userdata)
04807 {
04808         LLDynamicArray<LLUUID>* invitees = (LLDynamicArray<LLUUID>*)userdata;
04809 
04810         if(0 == option)
04811         {
04812                 LLMessageSystem* msg = gMessageSystem;
04813                 msg->newMessageFast(_PREHASH_StartLure);
04814                 msg->nextBlockFast(_PREHASH_AgentData);
04815                 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
04816                 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
04817                 msg->nextBlockFast(_PREHASH_Info);
04818                 msg->addU8Fast(_PREHASH_LureType, (U8)0); // sim will fill this in.
04819                 msg->addStringFast(_PREHASH_Message, text.c_str());
04820                 for(LLDynamicArray<LLUUID>::iterator itr = invitees->begin(); itr != invitees->end(); ++itr)
04821                 {
04822                         msg->nextBlockFast(_PREHASH_TargetData);
04823                         msg->addUUIDFast(_PREHASH_TargetID, *itr);
04824                 }
04825                 gAgent.sendReliableMessage();
04826         }
04827 
04828         delete invitees;
04829         invitees = NULL;
04830 }
04831 
04832 void handle_lure_callback_godlike(S32 option, void* userdata)
04833 {
04834         handle_lure_callback(option, LLString::null, userdata);
04835 }
04836 
04837 void handle_lure(const LLUUID& invitee)
04838 {
04839         LLDynamicArray<LLUUID> ids;
04840         ids.push_back(invitee);
04841         handle_lure(ids);
04842 }
04843 
04844 // Prompt for a message to the invited user.
04845 void handle_lure(LLDynamicArray<LLUUID>& ids) 
04846 {
04847         LLDynamicArray<LLUUID>* userdata = new LLDynamicArray<LLUUID>(ids);
04848 
04849         LLString::format_map_t edit_args;
04850         edit_args["[REGION]"] = gAgent.getRegion()->getName();
04851         if (gAgent.isGodlike())
04852         {
04853                 gViewerWindow->alertXmlEditText("OfferTeleportFromGod", edit_args,
04854                                                                                 &handle_lure_callback_godlike, userdata,
04855                                                                                 NULL, NULL, edit_args);
04856         }
04857         else
04858         {
04859                 gViewerWindow->alertXmlEditText("OfferTeleport", edit_args,
04860                                                                                 NULL, NULL,
04861                                                                                 handle_lure_callback, userdata, edit_args);
04862         }
04863 }
04864 
04865 
04866 void send_improved_im(const LLUUID& to_id,
04867                                                         const char* name,
04868                                                         const char* message,
04869                                                         U8 offline,
04870                                                         EInstantMessage dialog,
04871                                                         const LLUUID& id,
04872                                                         U32 timestamp, 
04873                                                         const U8* binary_bucket,
04874                                                         S32 binary_bucket_size)
04875 {
04876         pack_instant_message(
04877                 gMessageSystem,
04878                 gAgent.getID(),
04879                 FALSE,
04880                 gAgent.getSessionID(),
04881                 to_id,
04882                 name,
04883                 message,
04884                 offline,
04885                 dialog,
04886                 id,
04887                 0,
04888                 LLUUID::null,
04889                 gAgent.getPositionAgent(),
04890                 timestamp,
04891                 binary_bucket,
04892                 binary_bucket_size);
04893         gAgent.sendReliableMessage();
04894 }
04895 
04896 
04897 void send_places_query(const LLUUID& query_id,
04898                                            const LLUUID& trans_id,
04899                                            const char* query_text,
04900                                            U32 query_flags,
04901                                            S32 category,
04902                                            const char* sim_name)
04903 {
04904         LLMessageSystem* msg = gMessageSystem;
04905 
04906         msg->newMessage("PlacesQuery");
04907         msg->nextBlock("AgentData");
04908         msg->addUUID("AgentID", gAgent.getID());
04909         msg->addUUID("SessionID", gAgent.getSessionID());
04910         msg->addUUID("QueryID", query_id);
04911         msg->nextBlock("TransactionData");
04912         msg->addUUID("TransactionID", trans_id);
04913         msg->nextBlock("QueryData");
04914         msg->addString("QueryText", query_text);
04915         msg->addU32("QueryFlags", query_flags);
04916         msg->addS8("Category", (S8)category);
04917         msg->addString("SimName", sim_name);
04918         gAgent.sendReliableMessage();
04919 }
04920 
04921 
04922 void process_user_info_reply(LLMessageSystem* msg, void**)
04923 {
04924         LLUUID agent_id;
04925         msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
04926         if(agent_id != gAgent.getID())
04927         {
04928                 LL_WARNS("Messaging") << "process_user_info_reply - "
04929                                 << "wrong agent id." << LL_ENDL;
04930         }
04931         
04932         BOOL im_via_email;
04933         msg->getBOOLFast(_PREHASH_UserData, _PREHASH_IMViaEMail, im_via_email);
04934         char email[DB_USER_EMAIL_ADDR_BUF_SIZE];                /* Flawfinder: ignore */
04935         msg->getStringFast(_PREHASH_UserData, _PREHASH_EMail, DB_USER_EMAIL_ADDR_BUF_SIZE,
04936                                            email);
04937         char dir_visibility[MAX_STRING];                        /* Flawfinder: ignore */        
04938         msg->getString(
04939                 "UserData", "DirectoryVisibility", MAX_STRING, dir_visibility);
04940 
04941         LLFloaterPreference::updateUserInfo(dir_visibility, im_via_email, email);
04942         LLFloaterPostcard::updateUserInfo(email);
04943 }
04944 
04945 
04946 //---------------------------------------------------------------------------
04947 // Script Dialog
04948 //---------------------------------------------------------------------------
04949 
04950 const S32 SCRIPT_DIALOG_MAX_BUTTONS = 12;
04951 const S32 SCRIPT_DIALOG_BUTTON_STR_SIZE = 24;
04952 const S32 SCRIPT_DIALOG_MAX_MESSAGE_SIZE = 512;
04953 const char* SCRIPT_DIALOG_HEADER = "Script Dialog:\n";
04954 
04955 struct ScriptDialogInfo
04956 {
04957         LLHost mSender;
04958         LLUUID mObjectID;
04959         S32 mChatChannel;
04960         std::vector<LLString> mButtons;
04961 };
04962 
04963 void callback_script_dialog(S32 option, void* data)
04964 {
04965         ScriptDialogInfo* info = (ScriptDialogInfo*)data;
04966         if (!info) return;
04967 
04968         // Didn't click "Ignore"
04969         if (0 != option)
04970         {
04971                 LLMessageSystem* msg = gMessageSystem;
04972                 msg->newMessage("ScriptDialogReply");
04973                 msg->nextBlock("AgentData");
04974                 msg->addUUID("AgentID", gAgent.getID());
04975                 msg->addUUID("SessionID", gAgent.getSessionID());
04976                 msg->nextBlock("Data");
04977                 msg->addUUID("ObjectID", info->mObjectID);
04978                 msg->addS32("ChatChannel", info->mChatChannel);
04979                 msg->addS32("ButtonIndex", option);
04980                 msg->addString("ButtonLabel", info->mButtons[option-1]);
04981                 msg->sendReliable(info->mSender);
04982         }
04983 
04984         delete info;
04985 }
04986 
04987 void process_script_dialog(LLMessageSystem* msg, void**)
04988 {
04989         S32 i;
04990 
04991         ScriptDialogInfo* info = new ScriptDialogInfo;
04992 
04993         const S32 messageLength = SCRIPT_DIALOG_MAX_MESSAGE_SIZE + sizeof(SCRIPT_DIALOG_HEADER);
04994         char message[messageLength];            /* Flawfinder: ignore */                // Account for size of "Script Dialog:\n"
04995 
04996         char first_name[DB_FIRST_NAME_BUF_SIZE];                /* Flawfinder: ignore */
04997         char last_name[DB_GROUP_NAME_BUF_SIZE];         /* Flawfinder: ignore */
04998         char title[DB_INV_ITEM_NAME_BUF_SIZE];          /* Flawfinder: ignore */
04999         info->mSender = msg->getSender();
05000 
05001         msg->getUUID("Data", "ObjectID", info->mObjectID);
05002         msg->getString("Data", "FirstName", DB_FIRST_NAME_BUF_SIZE, first_name);
05003         msg->getString("Data", "LastName", DB_LAST_NAME_BUF_SIZE, last_name);
05004         msg->getString("Data", "ObjectName", DB_INV_ITEM_NAME_BUF_SIZE, title);
05005         msg->getString("Data", "Message", SCRIPT_DIALOG_MAX_MESSAGE_SIZE, message);
05006         msg->getS32("Data", "ChatChannel", info->mChatChannel);
05007 
05008                 // unused for now
05009         LLUUID image_id;
05010         msg->getUUID("Data", "ImageID", image_id);
05011 
05012         S32 button_count = msg->getNumberOfBlocks("Buttons");
05013         if (button_count > SCRIPT_DIALOG_MAX_BUTTONS)
05014         {
05015                 button_count = SCRIPT_DIALOG_MAX_BUTTONS;
05016         }
05017 
05018         for (i = 0; i < button_count; i++)
05019         {
05020                 char tdesc[SCRIPT_DIALOG_BUTTON_STR_SIZE+1];            /* Flawfinder: ignore */
05021                 msg->getString("Buttons", "ButtonLabel", SCRIPT_DIALOG_BUTTON_STR_SIZE + 1,  tdesc, i);
05022                 info->mButtons.push_back(LLString(tdesc));
05023         }
05024 
05025         LLStringBase<char>::format_map_t args;
05026         args["[TITLE]"] = title;
05027         args["[MESSAGE]"] = message;
05028         if (strlen(first_name) > 0)             /* Flawfinder: ignore */
05029         {
05030                 args["[FIRST]"] = first_name;
05031                 args["[LAST]"] = last_name;
05032                 LLNotifyBox::showXml("ScriptDialog", args,
05033                                                          callback_script_dialog, info,
05034                                                          info->mButtons,
05035                                                          TRUE);
05036         }
05037         else
05038         {
05039                 args["[GROUPNAME]"] = last_name;
05040                 LLNotifyBox::showXml("ScriptDialogGroup", args,
05041                                                          callback_script_dialog, info,
05042                                                          info->mButtons,
05043                                                          TRUE);
05044         }
05045 }
05046 
05047 //---------------------------------------------------------------------------
05048 
05049 struct LoadUrlInfo
05050 {
05051         LLUUID mObjectID;
05052         LLUUID mOwnerID;
05053         BOOL mOwnerIsGroup;
05054         char mObjectName[256];          /* Flawfinder: ignore */
05055         char mMessage[256];             /* Flawfinder: ignore */
05056         char mUrl[256];         /* Flawfinder: ignore */
05057 };
05058 
05059 std::vector<LoadUrlInfo*> gLoadUrlList;
05060 
05061 void callback_load_url(S32 option, void* data)
05062 {
05063         LoadUrlInfo* infop = (LoadUrlInfo*)data;
05064         if (!infop) return;
05065 
05066         if (0 == option)
05067         {
05068                 LLWeb::loadURLExternal(infop->mUrl);
05069         }
05070 
05071         delete infop;
05072         infop = NULL;
05073 }
05074 
05075 
05076 // We've got the name of the person who owns the object hurling the url.
05077 // Display confirmation dialog.
05078 void callback_load_url_name(const LLUUID& id, const char* first, const char* last, BOOL is_group, void* data)
05079 {
05080         std::vector<LoadUrlInfo*>::iterator it;
05081         for (it = gLoadUrlList.begin(); it != gLoadUrlList.end(); )
05082         {
05083                 LoadUrlInfo* infop = *it;
05084                 if (infop->mOwnerID == id)
05085                 {
05086                         it = gLoadUrlList.erase(it);
05087 
05088                         std::string owner_name(first);
05089                         if (is_group)
05090                         {
05091                                 owner_name += " (group)";
05092                         }
05093                         else
05094                         {
05095                                 owner_name += " ";
05096                                 owner_name += last;
05097                         }
05098 
05099                         // For legacy name-only mutes.
05100                         if (LLMuteList::getInstance()->isMuted(LLUUID::null, owner_name))
05101                         {
05102                                 delete infop;
05103                                 infop = NULL;
05104                                 continue;
05105                         }
05106                         LLString::format_map_t args;
05107                         args["[URL]"] = infop->mUrl;
05108                         args["[MESSAGE]"] = infop->mMessage;
05109                         args["[OBJECTNAME]"] = infop->mObjectName;
05110                         args["[NAME]"] = owner_name;
05111                         LLNotifyBox::showXml("LoadWebPage", args, callback_load_url, infop);
05112                 }
05113                 else
05114                 {
05115                         ++it;
05116                 }
05117         }
05118 }
05119 
05120 void process_load_url(LLMessageSystem* msg, void**)
05121 {
05122         LoadUrlInfo* infop = new LoadUrlInfo;
05123 
05124         msg->getString("Data", "ObjectName", 256, infop->mObjectName);
05125         msg->getUUID(  "Data", "ObjectID", infop->mObjectID);
05126         msg->getUUID(  "Data", "OwnerID", infop->mOwnerID);
05127         msg->getBOOL(  "Data", "OwnerIsGroup", infop->mOwnerIsGroup);
05128         msg->getString("Data", "Message", 256, infop->mMessage);
05129         msg->getString("Data", "URL", 256, infop->mUrl);
05130 
05131         // URL is safety checked in load_url above
05132 
05133         // Check if object or owner is muted
05134         if (LLMuteList::getInstance()->isMuted(infop->mObjectID, infop->mObjectName) ||
05135             LLMuteList::getInstance()->isMuted(infop->mOwnerID))
05136         {
05137                 LL_INFOS("Messaging")<<"Ignoring load_url from muted object/owner."<<LL_ENDL;
05138                 delete infop;
05139                 infop = NULL;
05140                 return;
05141         }
05142 
05143         // Add to list of pending name lookups
05144         gLoadUrlList.push_back(infop);
05145 
05146         gCacheName->get(infop->mOwnerID, infop->mOwnerIsGroup, callback_load_url_name);
05147 }
05148 
05149 
05150 void callback_download_complete(void** data, S32 result, LLExtStat ext_status)
05151 {
05152         LLString* filepath = (LLString*)data;
05153         LLString::format_map_t args;
05154         args["[DOWNLOAD_PATH]"] = *filepath;
05155         gViewerWindow->alertXml("FinishedRawDownload", args);
05156         delete filepath;
05157 }
05158 
05159 
05160 void process_initiate_download(LLMessageSystem* msg, void**)
05161 {
05162         LLUUID agent_id;
05163         msg->getUUID("AgentData", "AgentID", agent_id);
05164         if (agent_id != gAgent.getID())
05165         {
05166                 LL_WARNS("Messaging") << "Initiate download for wrong agent" << LL_ENDL;
05167                 return;
05168         }
05169 
05170         char sim_filename[MAX_PATH];            /* Flawfinder: ignore */
05171         char viewer_filename[MAX_PATH];         /* Flawfinder: ignore */
05172         msg->getString("FileData", "SimFilename", MAX_PATH, sim_filename);
05173         msg->getString("FileData", "ViewerFilename", MAX_PATH, viewer_filename);
05174 
05175         gXferManager->requestFile(viewer_filename,
05176                 sim_filename,
05177                 LL_PATH_NONE,
05178                 msg->getSender(),
05179                 FALSE,  // don't delete remote
05180                 callback_download_complete,
05181                 (void**)new LLString(viewer_filename));
05182 }
05183 
05184 
05185 void process_script_teleport_request(LLMessageSystem* msg, void**)
05186 {
05187         char object_name[256];  /* Flawfinder: ignore */                
05188         char sim_name[256];             /* Flawfinder: ignore */
05189         LLVector3 pos;
05190         LLVector3 look_at;
05191 
05192         msg->getString("Data", "ObjectName", 255, object_name);
05193         msg->getString(  "Data", "SimName", 255, sim_name);
05194         msg->getVector3("Data", "SimPosition", pos);
05195         msg->getVector3("Data", "LookAt", look_at);
05196 
05197         // gFloaterWorldMap->trackURL(sim_name, (S32)pos.mV[VX], (S32)pos.mV[VY], (S32)pos.mV[VZ]);
05198         // LLFloaterWorldMap::show(NULL, TRUE);
05199 
05200         LLURLDispatcher::dispatch(LLURLDispatcher::buildSLURL(sim_name, (S32)pos.mV[VX], (S32)pos.mV[VY], (S32)pos.mV[VZ]), FALSE);
05201         
05202 }
05203 
05204 void process_covenant_reply(LLMessageSystem* msg, void**)
05205 {
05206         LLUUID covenant_id, estate_owner_id;
05207         char estate_name[MAX_STRING];           /* Flawfinder: ignore */
05208         U32 covenant_timestamp;
05209         msg->getUUID("Data", "CovenantID", covenant_id);
05210         msg->getU32("Data", "CovenantTimestamp", covenant_timestamp);
05211         msg->getString("Data", "EstateName", MAX_STRING, estate_name);
05212         msg->getUUID("Data", "EstateOwnerID", estate_owner_id);
05213 
05214         LLPanelEstateCovenant::updateEstateName(estate_name);
05215         LLPanelLandCovenant::updateEstateName(estate_name);
05216         LLFloaterBuyLand::updateEstateName(estate_name);
05217 
05218         // standard message, not from system
05219         char last_modified[MAX_STRING];         /* Flawfinder: ignore */
05220         last_modified[0] = '\0';
05221         char time_buf[TIME_STR_LENGTH];         /* Flawfinder: ignore */
05222         snprintf(last_modified, MAX_STRING, "Last Modified %s",         /* Flawfinder: ignore */
05223         formatted_time((time_t)covenant_timestamp, time_buf));
05224 
05225         LLPanelEstateCovenant::updateLastModified(last_modified);
05226         LLPanelLandCovenant::updateLastModified(last_modified);
05227         LLFloaterBuyLand::updateLastModified(last_modified);
05228 
05229         gCacheName->getName(estate_owner_id, callbackCacheEstateOwnerName);
05230         
05231         // load the actual covenant asset data
05232         const BOOL high_priority = TRUE;
05233         if (covenant_id.notNull())
05234         {
05235                 gAssetStorage->getEstateAsset(gAgent.getRegionHost(),
05236                                                                         gAgent.getID(),
05237                                                                         gAgent.getSessionID(),
05238                                                                         covenant_id,
05239                                     LLAssetType::AT_NOTECARD,
05240                                                                         ET_Covenant,
05241                                     onCovenantLoadComplete,
05242                                                                         NULL,
05243                                                                         high_priority);
05244         }
05245         else
05246         {
05247                 std::string covenant_text;
05248                 if (estate_owner_id.isNull())
05249                 {
05250                         // mainland
05251                         covenant_text = "There is no Covenant provided for this Estate.";
05252                 }
05253                 else
05254                 {
05255                         covenant_text = "There is no Covenant provided for this Estate. The land on this estate is being sold by the Estate owner, not Linden Lab.  Please contact the Estate Owner for sales details.";
05256                 }
05257                 LLPanelEstateCovenant::updateCovenantText(covenant_text, covenant_id);
05258                 LLPanelLandCovenant::updateCovenantText(covenant_text);
05259                 LLFloaterBuyLand::updateCovenantText(covenant_text, covenant_id);
05260         }
05261 }
05262 
05263 void callbackCacheEstateOwnerName(
05264                 const LLUUID& id,
05265                 const char* first,
05266                 const char* last,
05267                 BOOL is_group,
05268                 void*)
05269 {
05270         std::string name;
05271         
05272         if (id.isNull())
05273         {
05274                 name = "(none)";
05275         }
05276         else
05277         {
05278                 name = first;
05279                 name += " ";
05280                 name += last;
05281         }
05282         LLPanelEstateCovenant::updateEstateOwnerName(name);
05283         LLPanelLandCovenant::updateEstateOwnerName(name);
05284         LLFloaterBuyLand::updateEstateOwnerName(name);
05285 }
05286 
05287 void onCovenantLoadComplete(LLVFS *vfs,
05288                                         const LLUUID& asset_uuid,
05289                                         LLAssetType::EType type,
05290                                         void* user_data, S32 status, LLExtStat ext_status)
05291 {
05292         LL_DEBUGS("Messaging") << "onCovenantLoadComplete()" << LL_ENDL;
05293         std::string covenant_text;
05294         if(0 == status)
05295         {
05296                 LLVFile file(vfs, asset_uuid, type, LLVFile::READ);
05297                 
05298                 S32 file_length = file.getSize();
05299                 
05300                 char* buffer = new char[file_length+1];
05301                 if (buffer == NULL)
05302                 {
05303                         LL_ERRS("Messaging") << "Memory Allocation failed" << LL_ENDL;
05304                         return;
05305                 }
05306 
05307                 file.read((U8*)buffer, file_length);            /* Flawfinder: ignore */
05308                 
05309                 // put a EOS at the end
05310                 buffer[file_length] = 0;
05311                 
05312                 if( (file_length > 19) && !strncmp( buffer, "Linden text version", 19 ) )
05313                 {
05314                         LLViewerTextEditor* editor =
05315                                 new LLViewerTextEditor("temp",
05316                                                        LLRect(0,0,0,0),
05317                                                        file_length+1);
05318                         if( !editor->importBuffer( buffer ) )
05319                         {
05320                                 LL_WARNS("Messaging") << "Problem importing estate covenant." << LL_ENDL;
05321                                 covenant_text = "Problem importing estate covenant.";
05322                         }
05323                         else
05324                         {
05325                                 // Version 0 (just text, doesn't include version number)
05326                                 covenant_text = editor->getText();
05327                         }
05328                         delete[] buffer;
05329                         delete editor;
05330                 }
05331                 else
05332                 {
05333                         LL_WARNS("Messaging") << "Problem importing estate covenant: Covenant file format error." << LL_ENDL;
05334                         covenant_text = "Problem importing estate covenant: Covenant file format error.";
05335                 }
05336         }
05337         else
05338         {
05339                 LLViewerStats::getInstance()->incStat( LLViewerStats::ST_DOWNLOAD_FAILED );
05340                 
05341                 if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status ||
05342                     LL_ERR_FILE_EMPTY == status)
05343                 {
05344                         covenant_text = "Estate covenant notecard is missing from database.";
05345                 }
05346                 else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status)
05347                 {
05348                         covenant_text = "Insufficient permissions to view estate covenant.";
05349                 }
05350                 else
05351                 {
05352                         covenant_text = "Unable to load estate covenant at this time.";
05353                 }
05354                 
05355                 LL_WARNS("Messaging") << "Problem loading notecard: " << status << LL_ENDL;
05356         }
05357         LLPanelEstateCovenant::updateCovenantText(covenant_text, asset_uuid);
05358         LLPanelLandCovenant::updateCovenantText(covenant_text);
05359         LLFloaterBuyLand::updateCovenantText(covenant_text, asset_uuid);
05360 }
05361 
05362 
05363 void process_feature_disabled_message(LLMessageSystem* msg, void**)
05364 {
05365         // Handle Blacklisted feature simulator response...
05366         LLUUID  agentID;
05367         LLUUID  transactionID;
05368         char    messageText[MAX_STRING];                /* Flawfinder: ignore */
05369         msg->getStringFast(_PREHASH_FailureInfo,_PREHASH_ErrorMessage,MAX_STRING,&messageText[0],0);
05370         msg->getUUIDFast(_PREHASH_FailureInfo,_PREHASH_AgentID,agentID);
05371         msg->getUUIDFast(_PREHASH_FailureInfo,_PREHASH_TransactionID,transactionID);
05372         
05373         LL_WARNS("Messaging") << "Blacklisted Feature Response:" << &messageText[0] << LL_ENDL;
05374 }
05375 
05376 // ------------------------------------------------------------
05377 // Message system exception callbacks
05378 // ------------------------------------------------------------
05379 
05380 void invalid_message_callback(LLMessageSystem* msg,
05381                                                                    void*,
05382                                                                    EMessageException exception)
05383 {
05384     LLAppViewer::instance()->badNetworkHandler();
05385 }
05386 
05387 // Please do not add more message handlers here. This file is huge.
05388 // Put them in a file related to the functionality you are implementing. JC

Generated on Fri May 16 08:34:14 2008 for SecondLife by  doxygen 1.5.5