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

Generated on Thu Jul 1 06:09:31 2010 for Second Life Viewer by  doxygen 1.4.7