aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llviewermessage.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/llviewermessage.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/newview/llviewermessage.cpp')
-rw-r--r--linden/indra/newview/llviewermessage.cpp5029
1 files changed, 5029 insertions, 0 deletions
diff --git a/linden/indra/newview/llviewermessage.cpp b/linden/indra/newview/llviewermessage.cpp
new file mode 100644
index 0000000..ba5be0a
--- /dev/null
+++ b/linden/indra/newview/llviewermessage.cpp
@@ -0,0 +1,5029 @@
1/**
2 * @file llviewermessage.cpp
3 * @brief Dumping ground for viewer-side message system callbacks.
4 *
5 * Copyright (c) 2002-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "llviewerprecompiledheaders.h"
29
30#include "llviewermessage.h"
31
32#include <deque>
33#include <stdio.h>
34#include <string.h>
35
36#include "audioengine.h"
37#include "audiosettings.h"
38#include "indra_constants.h"
39#include "lscript_byteformat.h"
40#include "mean_collision_data.h"
41#include "llfloaterbump.h"
42#include "llassetstorage.h"
43#include "llcachename.h"
44#include "llchat.h"
45#include "lldbstrings.h"
46#include "lleconomy.h"
47#include "llfilepicker.h"
48#include "llfloaterimport.h"
49#include "llfocusmgr.h"
50#include "llfollowcamparams.h"
51#include "llinstantmessage.h"
52#include "llquantize.h"
53#include "llregionflags.h"
54#include "llregionhandle.h"
55#include "llsdserialize.h"
56#include "llstring.h"
57#include "llteleportflags.h"
58#include "lltracker.h"
59#include "lltransactionflags.h"
60#include "llwindow.h" // shell_open()
61#include "llxfermanager.h"
62#include "message.h"
63#include "sound_ids.h"
64#include "lltimer.h"
65
66#include "llagent.h"
67#include "llcallingcard.h"
68#include "llconsole.h"
69#include "llviewercontrol.h"
70#include "lldrawpool.h"
71#include "llfirstuse.h"
72#include "llfloaterbuycurrency.h"
73#include "llfloaterbuyland.h"
74#include "llfloaterchat.h"
75#include "llfloatergroupinfo.h"
76#include "llfloaterimagepreview.h"
77#include "llfloaterland.h"
78#include "llfloaterregioninfo.h"
79#include "llfloaterlandholdings.h"
80#include "llfloatermap.h"
81#include "llfloatermute.h"
82#include "llfloaterpostcard.h"
83#include "llfloaterpreference.h"
84#include "llfollowcam.h"
85#include "llgroupnotify.h"
86#include "llhudeffect.h"
87#include "llhudeffecttrail.h"
88#include "llhudmanager.h"
89#include "llimpanel.h"
90#include "llinventorymodel.h"
91#include "llinventoryview.h"
92#include "llmenugl.h"
93#include "llmutelist.h"
94#include "llnetmap.h"
95#include "llnotify.h"
96#include "llpanelgrouplandmoney.h"
97#include "llselectmgr.h"
98#include "llstartup.h"
99#include "llsky.h"
100#include "llstatenums.h"
101#include "llstatusbar.h"
102#include "llimview.h"
103#include "lltool.h"
104#include "lltoolbar.h"
105#include "lltoolmgr.h"
106#include "llui.h" // for make_ui_sound
107#include "lluploaddialog.h"
108#include "llviewercamera.h"
109#include "llviewerinventory.h"
110#include "llviewermenu.h"
111#include "llviewerobject.h"
112#include "llviewerobjectlist.h"
113#include "llviewerparcelmgr.h"
114#include "llviewerpartsource.h"
115#include "llviewerregion.h"
116#include "llviewerstats.h"
117#include "llviewertexteditor.h"
118#include "llviewerthrottle.h"
119#include "llviewerwindow.h"
120#include "llvlmanager.h"
121#include "llvoavatar.h"
122#include "llvotextbubble.h"
123#include "llweb.h"
124#include "llworld.h"
125#include "pipeline.h"
126#include "viewer.h"
127#include "llfloaterworldmap.h"
128
129#include <boost/tokenizer.hpp>
130
131#if LL_WINDOWS // For Windows specific error handler
132#include "llwindebug.h" // For the invalid message handler
133#endif
134
135//
136// Constants
137//
138const F32 BIRD_AUDIBLE_RADIUS = 32.0f;
139const F32 SIT_DISTANCE_FROM_TARGET = 0.25f;
140static const F32 LOGOUT_REPLY_TIME = 3.f; // Wait this long after LogoutReply before quitting.
141extern BOOL gDebugClicks;
142
143extern void bad_network_handler();
144
145LLDispatcher gGenericDispatcher;
146
147// function prototypes
148void open_offer(const std::vector<LLUUID>& items);
149void friendship_offer_callback(S32 option, void* user_data);
150
151struct LLFriendshipOffer
152{
153 LLUUID mFromID;
154 LLUUID mTransactionID;
155 BOOL mOnline;
156 LLHost mHost;
157};
158
159//const char BUSY_AUTO_RESPONSE[] = "The Resident you messaged is in 'busy mode' which means they have "
160// "requested not to be disturbed. Your message will still be shown in their IM "
161// "panel for later viewing.";
162
163//
164// Functions
165//
166
167void give_money(const LLUUID& uuid, LLViewerRegion* region, S32 amount, BOOL is_group,
168 S32 trx_type, const LLString& desc)
169{
170 if(0 == amount) return;
171 amount = abs(amount);
172 llinfos << "give_money(" << uuid << "," << amount << ")"<< llendl;
173 if(can_afford_transaction(amount))
174 {
175// gStatusBar->debitBalance(amount);
176 LLMessageSystem* msg = gMessageSystem;
177 msg->newMessageFast(_PREHASH_MoneyTransferRequest);
178 msg->nextBlockFast(_PREHASH_AgentData);
179 msg->addUUIDFast(_PREHASH_AgentID, agent_get_id());
180 msg->addUUIDFast(_PREHASH_SessionID, agent_get_session_id());
181 msg->nextBlockFast(_PREHASH_MoneyData);
182 msg->addUUIDFast(_PREHASH_SourceID, gAgent.getID() );
183 msg->addUUIDFast(_PREHASH_DestID, uuid);
184 msg->addU8Fast(_PREHASH_Flags, pack_transaction_flags(FALSE, is_group));
185 msg->addS32Fast(_PREHASH_Amount, amount);
186 msg->addU8Fast(_PREHASH_AggregatePermNextOwner, (U8)LLAggregatePermissions::AP_EMPTY);
187 msg->addU8Fast(_PREHASH_AggregatePermInventory, (U8)LLAggregatePermissions::AP_EMPTY);
188 msg->addS32Fast(_PREHASH_TransactionType, trx_type );
189 msg->addStringFast(_PREHASH_Description, desc.c_str());
190 msg->sendReliable(region->getHost());
191 }
192 else
193 {
194 LLFloaterBuyCurrency::buyCurrency("Giving", amount);
195 }
196}
197
198BOOL can_afford_transaction(S32 cost)
199{
200 return((cost <= 0)||((gStatusBar) && (gStatusBar->getBalance() >=cost)));
201}
202
203void send_complete_agent_movement(const LLHost& sim_host)
204{
205 LLMessageSystem* msg = gMessageSystem;
206 msg->newMessageFast(_PREHASH_CompleteAgentMovement);
207 msg->nextBlockFast(_PREHASH_AgentData);
208 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
209 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
210 msg->addU32Fast(_PREHASH_CircuitCode, msg->mOurCircuitCode);
211 msg->sendReliable(sim_host);
212}
213
214void process_logout_reply(LLMessageSystem* msg, void**)
215{
216 // The server has told us it's ok to quit.
217 llinfos << "process_logout_reply" << llendl;
218
219 LLUUID agent_id;
220 msg->getUUID("AgentData", "AgentID", agent_id);
221 LLUUID session_id;
222 msg->getUUID("AgentData", "SessionID", session_id);
223 if((agent_id != agent_get_id()) || (session_id != agent_get_session_id()))
224 {
225 llwarns << "Bogus Logout Reply" << llendl;
226 }
227
228 LLInventoryModel::update_map_t parents;
229 S32 count = msg->getNumberOfBlocksFast( _PREHASH_InventoryData );
230 for(S32 i = 0; i < count; ++i)
231 {
232 LLUUID item_id;
233 msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id, i);
234
235 if( (1 == count) && item_id.isNull() )
236 {
237 // Detect dummy item. Indicates an empty list.
238 break;
239 }
240
241 // We do not need to track the asset ids, just account for an
242 // updated inventory version.
243 llinfos << "process_logout_reply itemID=" << item_id << llendl;
244 LLInventoryItem* item = gInventory.getItem( item_id );
245 if( item )
246 {
247 parents[item->getParentUUID()] = 0;
248 gInventory.addChangedMask(LLInventoryObserver::INTERNAL, item_id);
249 }
250 else
251 {
252 llinfos << "process_logout_reply item not found: " << item_id << llendl;
253 }
254 }
255 if(!parents.empty())
256 {
257 gInventory.accountForUpdate(parents);
258 gInventory.notifyObservers();
259 }
260 app_force_quit(NULL);
261}
262
263void process_layer_data(LLMessageSystem *mesgsys, void **user_data)
264{
265 LLViewerRegion *regionp = gWorldp->getRegion(mesgsys->getSender());
266
267 if (!regionp || gNoRender)
268 {
269 return;
270 }
271
272
273 S32 size;
274 S8 type;
275
276 mesgsys->getS8Fast(_PREHASH_LayerID, _PREHASH_Type, type);
277 size = mesgsys->getSizeFast(_PREHASH_LayerData, _PREHASH_Data);
278 if(!size)
279 {
280 llwarns << "Layer data has zero size." << llendl;
281 return;
282 }
283 U8 *datap = new U8[size];
284 mesgsys->getBinaryDataFast(_PREHASH_LayerData, _PREHASH_Data, datap, size);
285 LLVLData *vl_datap = new LLVLData(regionp, type, datap, size);
286 if (mesgsys->getReceiveCompressedSize())
287 {
288 gVLManager.addLayerData(vl_datap, mesgsys->getReceiveCompressedSize());
289 }
290 else
291 {
292 gVLManager.addLayerData(vl_datap, mesgsys->getReceiveSize());
293 }
294}
295
296S32 exported_object_count = 0;
297S32 exported_image_count = 0;
298S32 current_object_count = 0;
299S32 current_image_count = 0;
300
301extern LLNotifyBox *gExporterNotify;
302extern LLUUID gExporterRequestID;
303extern LLString gExportDirectory;
304
305extern LLUploadDialog *gExportDialog;
306
307LLString gExportedFile;
308
309std::map<LLUUID, LLString> gImageChecksums;
310
311void export_complete()
312{
313 LLUploadDialog::modalUploadFinished();
314 gExporterRequestID.setNull();
315 gExportDirectory = "";
316
317 FILE *fXML = LLFile::fopen(gExportedFile.c_str(), "rb");
318 fseek(fXML, 0, SEEK_END);
319 U32 length = ftell(fXML);
320 fseek(fXML, 0, SEEK_SET);
321 U8 *buffer = new U8[length];
322 fread(buffer, 1, length, fXML);
323 fclose(fXML);
324
325 char *pos = (char *)buffer;
326 while ((pos = strstr(pos+1, "<sl:image ")) != 0)
327 {
328 char *pos_check = strstr(pos, "checksum=\"");
329 char *pos_uuid = strstr(pos_check, "\">");
330
331 if (pos_check && pos_uuid)
332 {
333 char image_uuid_str[UUID_STR_SIZE];
334 memcpy(image_uuid_str, pos_uuid+2, UUID_STR_SIZE-1);
335 image_uuid_str[UUID_STR_SIZE-1] = 0;
336
337 LLUUID image_uuid(image_uuid_str);
338
339 llinfos << "Found UUID: " << image_uuid << llendl;
340
341 std::map<LLUUID, LLString>::iterator itor = gImageChecksums.find(image_uuid);
342 if (itor != gImageChecksums.end())
343 {
344 llinfos << "Replacing with checksum: " << itor->second << llendl;
345 memcpy(&pos_check[10], itor->second.c_str(), 32);
346 }
347 }
348 }
349
350 FILE *fXMLOut = LLFile::fopen(gExportedFile.c_str(), "wb");
351 fwrite(buffer, 1, length, fXMLOut);
352 fclose(fXMLOut);
353
354 delete buffer;
355}
356
357
358void exported_item_complete(const LLTSCode status, void *user_data)
359{
360 //LLString *filename = (LLString *)user_data;
361
362 if (status < LLTS_OK)
363 {
364 llinfos << "Export failed!" << llendl;
365 }
366 else
367 {
368 ++current_object_count;
369 if (current_image_count == exported_image_count && current_object_count == exported_object_count)
370 {
371 llinfos << "*** Export complete ***" << llendl;
372
373 export_complete();
374 }
375 else
376 {
377 gExportDialog->setMessage(llformat("Exported %d/%d object files, %d/%d textures.", current_object_count, exported_object_count, current_image_count, exported_image_count));
378 }
379 }
380}
381
382struct exported_image_info
383{
384 LLUUID image_id;
385 LLString filename;
386 U32 image_num;
387};
388
389void exported_j2c_complete(const LLTSCode status, void *user_data)
390{
391 exported_image_info *info = (exported_image_info *)user_data;
392 LLUUID image_id = info->image_id;
393 U32 image_num = info->image_num;
394 LLString filename = info->filename;
395 delete info;
396
397 if (status < LLTS_OK)
398 {
399 llinfos << "Image download failed!" << llendl;
400 }
401 else
402 {
403 FILE *fIn = LLFile::fopen(filename.c_str(), "rb");
404 if (fIn)
405 {
406 LLPointer<LLImageJ2C> ImageUtility = new LLImageJ2C;
407 LLPointer<LLImageTGA> TargaUtility = new LLImageTGA;
408
409 fseek(fIn, 0, SEEK_END);
410 S32 length = ftell(fIn);
411 fseek(fIn, 0, SEEK_SET);
412 U8 *buffer = ImageUtility->allocateData(length);
413 fread(buffer, 1, length, fIn);
414 fclose(fIn);
415 LLFile::remove(filename.c_str());
416
417 // Convert to TGA
418 LLPointer<LLImageRaw> image = new LLImageRaw();
419
420 ImageUtility->updateData();
421 ImageUtility->decode(image, 100000.0f);
422
423 TargaUtility->encode(image);
424 U8 *data = TargaUtility->getData();
425 S32 data_size = TargaUtility->getDataSize();
426
427 char *file_path = new char[filename.size()+1];
428 strcpy(file_path, filename.c_str());
429 char *end = strrchr(file_path, gDirUtilp->getDirDelimiter()[0]);
430 end[0] = 0;
431 LLString output_file = llformat("%s/image-%03d.tga", file_path, image_num);//filename;
432 delete file_path;
433 //S32 name_len = output_file.length();
434 //strcpy(&output_file[name_len-3], "tga");
435 FILE *fOut = LLFile::fopen(output_file.c_str(), "wb");
436 char md5_hash_string[33];
437 strcpy(md5_hash_string, "00000000000000000000000000000000");
438 if (fOut)
439 {
440 fwrite(data, 1, data_size, fOut);
441 fseek(fOut, 0, SEEK_SET);
442 fclose(fOut);
443 fOut = LLFile::fopen(output_file.c_str(), "rb");
444 LLMD5 my_md5_hash(fOut);
445 my_md5_hash.hex_digest(md5_hash_string);
446 }
447
448 gImageChecksums.insert(std::pair<LLUUID, LLString>(image_id, md5_hash_string));
449 }
450 }
451
452 ++current_image_count;
453 if (current_image_count == exported_image_count && current_object_count == exported_object_count)
454 {
455 llinfos << "*** Export textures complete ***" << llendl;
456 export_complete();
457 }
458 else
459 {
460 gExportDialog->setMessage(llformat("Exported %d/%d object files, %d/%d textures.", current_object_count, exported_object_count, current_image_count, exported_image_count));
461 }
462}
463
464void process_derez_ack(LLMessageSystem*, void**)
465{
466 if(gViewerWindow) gViewerWindow->getWindow()->decBusyCount();
467}
468
469void process_places_reply(LLMessageSystem* msg, void** data)
470{
471 LLUUID query_id;
472
473 msg->getUUID("AgentData", "QueryID", query_id);
474 if (query_id.isNull())
475 {
476 LLFloaterLandHoldings::processPlacesReply(msg, data);
477 }
478 else if(gAgent.isInGroup(query_id))
479 {
480 LLPanelGroupLandMoney::processPlacesReply(msg, data);
481 }
482 else
483 {
484 llwarns << "Got invalid PlacesReply message" << llendl;
485 }
486}
487
488void send_sound_trigger(const LLUUID& sound_id, F32 gain)
489{
490 if (sound_id.isNull())
491 {
492 // zero guids don't get sent (no sound)
493 return;
494 }
495
496 LLMessageSystem* msg = gMessageSystem;
497 msg->newMessageFast(_PREHASH_SoundTrigger);
498 msg->nextBlockFast(_PREHASH_SoundData);
499 msg->addUUIDFast(_PREHASH_SoundID, sound_id);
500 // Client untrusted, ids set on sim
501 msg->addUUIDFast(_PREHASH_OwnerID, LLUUID::null );
502 msg->addUUIDFast(_PREHASH_ObjectID, LLUUID::null );
503 msg->addUUIDFast(_PREHASH_ParentID, LLUUID::null );
504
505 msg->addU64Fast(_PREHASH_Handle, gAgent.getRegion()->getHandle());
506
507 LLVector3 position = gAgent.getPositionAgent();
508 msg->addVector3Fast(_PREHASH_Position, position);
509 msg->addF32Fast(_PREHASH_Gain, gain);
510
511 gAgent.sendMessage();
512}
513
514struct LLJoinGroupData
515{
516 LLUUID mGroupID;
517 LLUUID mTransactionID;
518 std::string mName;
519 std::string mMessage;
520 S32 mFee;
521};
522
523void join_group_callback(S32 option, void* user_data)
524{
525 LLJoinGroupData* data = (LLJoinGroupData*)user_data;
526 BOOL delete_context_data = TRUE;
527 bool accept_invite = false;
528 if(option == 0 && data && !data->mGroupID.isNull())
529 {
530 // check for promotion or demotion.
531 S32 max_groups = MAX_AGENT_GROUPS;
532 if(gAgent.isInGroup(data->mGroupID)) ++max_groups;
533
534 if(gAgent.mGroups.count() < max_groups)
535 {
536 accept_invite = true;
537 }
538 else
539 {
540 delete_context_data = FALSE;
541 LLString::format_map_t args;
542 args["[NAME]"] = data->mName;
543 args["[INVITE]"] = data->mMessage;
544 LLAlertDialog::showXml("JoinedTooManyGroupsMember", args, join_group_callback, (void*)data);
545 }
546 }
547
548 if (accept_invite)
549 {
550 // If there is a fee to join this group, make
551 // sure the user is sure they want to join.
552 if (data->mFee > 0)
553 {
554 delete_context_data = FALSE;
555 LLString::format_map_t args;
556 args["[COST]"] = llformat("%d", data->mFee);
557 // Set the fee to 0, so that we don't keep
558 // asking about a fee.
559 data->mFee = 0;
560 gViewerWindow->alertXml("JoinGroupCanAfford",
561 args,
562 join_group_callback,
563 (void*)data);
564 }
565 else
566 {
567 send_improved_im(data->mGroupID,
568 "name",
569 "message",
570 IM_ONLINE,
571 IM_GROUP_INVITATION_ACCEPT,
572 data->mTransactionID);
573 }
574 }
575 else if (data)
576 {
577 send_improved_im(data->mGroupID,
578 "name",
579 "message",
580 IM_ONLINE,
581 IM_GROUP_INVITATION_DECLINE,
582 data->mTransactionID);
583 }
584
585 if(delete_context_data)
586 {
587 delete data;
588 data = NULL;
589 }
590}
591
592
593//-----------------------------------------------------------------------------
594// Instant Message
595//-----------------------------------------------------------------------------
596class LLOpenAgentOffer : public LLInventoryFetchObserver
597{
598public:
599 LLOpenAgentOffer() {}
600 virtual ~LLOpenAgentOffer() {}
601
602 virtual void done()
603 {
604 open_offer(mComplete);
605 gInventory.removeObserver(this);
606 delete this;
607 }
608};
609
610class LLOpenTaskOffer : public LLInventoryExistenceObserver
611{
612public:
613 LLOpenTaskOffer() {}
614 virtual ~LLOpenTaskOffer() {}
615
616protected:
617 virtual void done()
618 {
619 open_offer(mExist);
620 gInventory.removeObserver(this);
621 delete this;
622 }
623};
624
625class LLDiscardAgentOffer : public LLInventoryFetchComboObserver
626{
627public:
628 LLDiscardAgentOffer(const LLUUID& folder_id, const LLUUID& object_id) :
629 mFolderID(folder_id),
630 mObjectID(object_id) {}
631 virtual ~LLDiscardAgentOffer() {}
632 virtual void done()
633 {
634 lldebugs << "LLDiscardAgentOffer::done()" << llendl;
635 LLUUID trash_id;
636 trash_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_TRASH);
637 bool notify = false;
638 if(trash_id.notNull() && mObjectID.notNull())
639 {
640 LLInventoryModel::update_list_t update;
641 LLInventoryModel::LLCategoryUpdate old_folder(mFolderID, -1);
642 update.push_back(old_folder);
643 LLInventoryModel::LLCategoryUpdate new_folder(trash_id, 1);
644 update.push_back(new_folder);
645 gInventory.accountForUpdate(update);
646 gInventory.moveObject(mObjectID, trash_id);
647 LLInventoryObject* obj = gInventory.getObject(mObjectID);
648 if(obj)
649 {
650 // no need to restamp since this is already a freshly
651 // stamped item.
652 obj->updateParentOnServer(FALSE);
653 notify = true;
654 }
655 }
656 else
657 {
658 llwarns << "DiscardAgentOffer unable to find: "
659 << (trash_id.isNull() ? "trash " : "")
660 << (mObjectID.isNull() ? "object" : "") << llendl;
661 }
662 gInventory.removeObserver(this);
663 if(notify)
664 {
665 gInventory.notifyObservers();
666 }
667 delete this;
668 }
669protected:
670 LLUUID mFolderID;
671 LLUUID mObjectID;
672};
673
674
675void open_offer(const std::vector<LLUUID>& items)
676{
677 std::vector<LLUUID>::const_iterator it = items.begin();
678 std::vector<LLUUID>::const_iterator end = items.end();
679 LLUUID trash_id(gInventory.findCategoryUUIDForType(LLAssetType::AT_TRASH));
680 LLInventoryItem* item;
681 for(; it != end; ++it)
682 {
683 item = gInventory.getItem(*it);
684 if(!item)
685 {
686 llwarns << "Unable to show inventory item: " << *it << llendl;
687 continue;
688 }
689 if(gInventory.isObjectDescendentOf(*it, trash_id))
690 {
691 continue;
692 }
693 switch(item->getType())
694 {
695 case LLAssetType::AT_NOTECARD:
696 open_notecard(*it, LLString("Note: ") + item->getName(), TRUE, LLUUID::null, FALSE);
697 break;
698 case LLAssetType::AT_LANDMARK:
699 open_landmark(*it, LLString("Landmark: ") + item->getName(), TRUE, LLUUID::null, FALSE);
700 break;
701 case LLAssetType::AT_TEXTURE:
702 open_texture(*it, LLString("Texture: ") + item->getName(), TRUE, LLUUID::null, FALSE);
703 break;
704 default:
705 {
706 // Don't auto-open the inventory - just select it if we
707 // already have an active inventory.
708 LLInventoryView* view = LLInventoryView::getActiveInventory();
709 if(view)
710 {
711 LLUICtrl* focus_ctrl = gFocusMgr.getKeyboardFocus();
712 LLFocusMgr::FocusLostCallback callback;
713 callback = gFocusMgr.getFocusCallback();
714 view->getPanel()->setSelection(item->getUUID(), TAKE_FOCUS_NO);
715 gFocusMgr.setKeyboardFocus(focus_ctrl, callback);
716 break;
717 }
718 }
719 }
720 }
721}
722
723void inventory_offer_mute_callback(const LLUUID& blocked_id,
724 const char* first_name,
725 const char* last_name,
726 BOOL is_group,
727 void*)
728{
729 LLString from_name;
730 LLMute::EType type;
731
732 if (is_group)
733 {
734 type = LLMute::GROUP;
735 from_name = first_name;
736 }
737 else
738 {
739 type = LLMute::AGENT;
740 from_name += first_name;
741 from_name += " ";
742 from_name += last_name;
743 }
744
745 LLMute mute(blocked_id, from_name, type);
746 if (gMuteListp->add(mute))
747 {
748 gFloaterMute->show();
749 gFloaterMute->selectMute(blocked_id);
750 }
751}
752
753void inventory_offer_callback(S32 option, void* user_data)
754{
755 LLChat chat;
756 LLString log_message;
757
758 LLOfferInfo* info = (LLOfferInfo*)user_data;
759 if(!info) return;
760
761 // For muting, we need to add the mute, then decline the offer.
762 // This must be done here because:
763 // * callback may be called immediately,
764 // * adding the mute sends a message,
765 // * we can't build two messages at once. JC
766 if (option == 2)
767 {
768 gCacheName->get(info->mFromID, info->mFromGroup, inventory_offer_mute_callback, NULL);
769 }
770
771 LLMessageSystem* msg = gMessageSystem;
772 msg->newMessageFast(_PREHASH_ImprovedInstantMessage);
773 msg->nextBlockFast(_PREHASH_AgentData);
774 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
775 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
776 msg->nextBlockFast(_PREHASH_MessageBlock);
777 msg->addBOOLFast(_PREHASH_FromGroup, FALSE);
778 msg->addUUIDFast(_PREHASH_ToAgentID, info->mFromID);
779 msg->addU8Fast(_PREHASH_Offline, IM_ONLINE);
780 msg->addUUIDFast(_PREHASH_ID, info->mTransactionID);
781 msg->addU32Fast(_PREHASH_Timestamp, NO_TIMESTAMP); // no timestamp necessary
782 std::string name;
783 gAgent.buildFullname(name);
784 msg->addStringFast(_PREHASH_FromAgentName, name);
785 msg->addStringFast(_PREHASH_Message, "");
786 msg->addU32Fast(_PREHASH_ParentEstateID, 0);
787 msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null);
788 msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent());
789 LLInventoryObserver* opener = NULL;
790 LLViewerInventoryCategory* catp = NULL;
791 catp = (LLViewerInventoryCategory*)gInventory.getCategory(info->mObjectID);
792 LLViewerInventoryItem* itemp = NULL;
793 if(!catp)
794 {
795 itemp = (LLViewerInventoryItem*)gInventory.getItem(info->mObjectID);
796 }
797
798 // XUI:translate
799 LLString from_string;
800 if (info->mFromObject == TRUE)
801 {
802 if (info->mFromGroup)
803 {
804 char group_name[MAX_STRING];
805 if (gCacheName->getGroupName(info->mFromID, group_name))
806 {
807 from_string = LLString("An object named ") + info->mFromName + " owned by the group '" + group_name + "'";
808 }
809 else
810 {
811 from_string = LLString("An object named ") + info->mFromName + " owned by an unknown group";
812 }
813 }
814 else
815 {
816 char first_name[MAX_STRING];
817 char last_name[MAX_STRING];
818 if (gCacheName->getName(info->mFromID, first_name, last_name))
819 {
820 from_string = LLString("An object named ") + info->mFromName + " owned by " + first_name + " " + last_name;
821 }
822 else
823 {
824 from_string = LLString("An object named ") + info->mFromName + " owned by an unknown user";
825 }
826 }
827 }
828 else
829 {
830 from_string = info->mFromName;
831 }
832
833 switch(option)
834 {
835 case 0:
836 // ACCEPT. The math for the dialog works, because the accept
837 // for inventory_offered, task_inventory_offer or
838 // group_notice_inventory is 1 greater than the offer integer value.
839 // Generates IM_INVENTORY_ACCEPTED, IM_TASK_INVENTORY_ACCEPTED,
840 // or IM_GROUP_NOTICE_INVENTORY_ACCEPTED
841 msg->addU8Fast(_PREHASH_Dialog, (U8)(info->mIM + 1));
842 msg->addBinaryDataFast(_PREHASH_BinaryBucket, &(info->mFolderID.mData),
843 sizeof(info->mFolderID.mData));
844 // send the message
845 msg->sendReliable(info->mHost);
846 log_message = info->mFromName + " gave you " + info->mDesc + ".";
847 chat.mText = log_message;
848 LLFloaterChat::addChatHistory(chat);
849 // we will want to open this item when it comes back.
850 lldebugs << "Initializing an opener for tid: " << info->mTransactionID
851 << llendl;
852 switch (info->mIM)
853 {
854 case IM_INVENTORY_OFFERED:
855 {
856 // This is an offer from an agent. In this case, the back
857 // end has already copied the items into your inventory,
858 // so we can fetch it out of our inventory.
859 LLInventoryFetchObserver::item_ref_t items;
860 items.push_back(info->mObjectID);
861 LLOpenAgentOffer* open_agent_offer = new LLOpenAgentOffer;
862 open_agent_offer->fetchItems(items);
863 if(catp || (itemp && itemp->isComplete()))
864 {
865 open_agent_offer->done();
866 }
867 else
868 {
869 opener = open_agent_offer;
870 }
871 }
872 break;
873 case IM_TASK_INVENTORY_OFFERED:
874 case IM_GROUP_NOTICE:
875 case IM_GROUP_NOTICE_REQUESTED:
876 {
877 // This is an offer from a task or group.
878 // Because it would be easy
879 // to write a task which would overload your inventory, we
880 // force the offer to stay in an instant message until
881 // accepted. Thus, we have to respond, and then wait for
882 // the update to come back before we open the item.
883 LLOpenTaskOffer* open_task_offer = new LLOpenTaskOffer;
884 open_task_offer->watchItem(info->mObjectID);
885 if(itemp && itemp->isComplete())
886 {
887 opener->changed(0x0);
888 }
889 else
890 {
891 opener = open_task_offer;
892 }
893 }
894 break;
895 default:
896 llwarns << "inventory_offer_callback: unknown offer type" << llendl;
897 break;
898 }
899 break;
900
901 case 2:
902 // MUTE falls through to decline
903 case 1:
904 // DECLINE. The math for the dialog works, because the decline
905 // for inventory_offered, task_inventory_offer or
906 // group_notice_inventory is 2 greater than the offer integer value.
907 // Generates IM_INVENTORY_DECLINED, IM_TASK_INVENTORY_DECLINED,
908 // or IM_GROUP_NOTICE_INVENTORY_DECLINED
909 default:
910 // close button probably
911 msg->addU8Fast(_PREHASH_Dialog, (U8)(info->mIM + 2));
912 msg->addBinaryDataFast(_PREHASH_BinaryBucket, EMPTY_BINARY_BUCKET, EMPTY_BINARY_BUCKET_SIZE);
913 // send the message
914 msg->sendReliable(info->mHost);
915
916 log_message = "You decline " + info->mDesc + " from " + info->mFromName + ".";
917 chat.mText = log_message;
918 LLFloaterChat::addChatHistory(chat);
919
920 // If it's from an agent, we have to fetch the item to throw
921 // it away. If it's from a task or group, just denying the
922 // request will suffice to discard the item.
923 if(IM_INVENTORY_OFFERED == info->mIM)
924 {
925 LLInventoryFetchComboObserver::folder_ref_t folders;
926 LLInventoryFetchComboObserver::item_ref_t items;
927 items.push_back(info->mObjectID);
928 LLDiscardAgentOffer* discard_agent_offer;
929 discard_agent_offer = new LLDiscardAgentOffer(info->mFolderID, info->mObjectID);
930 discard_agent_offer->fetch(folders, items);
931 if(catp || (itemp && itemp->isComplete()))
932 {
933 discard_agent_offer->done();
934 }
935 else
936 {
937 opener = discard_agent_offer;
938 }
939
940 }
941 if (!info->mFromGroup)
942 {
943 busy_message(msg,info->mFromID);
944 }
945 break;
946 }
947
948 if(opener)
949 {
950 gInventory.addObserver(opener);
951 }
952
953 delete info;
954 info = NULL;
955
956 // Allow these to stack up, but once you deal with one, reset the
957 // position.
958 gFloaterView->resetStartingFloaterPosition();
959}
960
961
962void inventory_offer_handler(LLOfferInfo* info, BOOL from_task)
963{
964 switch(info->mType)
965 {
966 // For certain types, just accept the items into the inventory,
967 // and we'll automatically open them on receipt.
968 case LLAssetType::AT_NOTECARD:
969 case LLAssetType::AT_LANDMARK:
970 case LLAssetType::AT_TEXTURE:
971 {
972 // 0 = accept button
973 inventory_offer_callback(0, info);
974 //LLInventoryView::sOpenNextNewItem = TRUE;
975 }
976 break;
977
978 case LLAssetType::AT_SOUND:
979 case LLAssetType::AT_CALLINGCARD:
980 case LLAssetType::AT_SCRIPT:
981 case LLAssetType::AT_CLOTHING:
982 case LLAssetType::AT_OBJECT:
983 case LLAssetType::AT_CATEGORY:
984 case LLAssetType::AT_ROOT_CATEGORY:
985 case LLAssetType::AT_LSL_TEXT:
986 case LLAssetType::AT_LSL_BYTECODE:
987 case LLAssetType::AT_TEXTURE_TGA:
988 case LLAssetType::AT_BODYPART:
989 case LLAssetType::AT_TRASH:
990 case LLAssetType::AT_SNAPSHOT_CATEGORY:
991 case LLAssetType::AT_LOST_AND_FOUND:
992 case LLAssetType::AT_ANIMATION:
993 case LLAssetType::AT_GESTURE:
994 default:
995 {
996 LLString::format_map_t args;
997 args["[OBJECTNAME]"] = info->mDesc;
998 args["[OBJECTTYPE]"] = LLAssetType::lookupHumanReadable(info->mType);
999
1000 // Name cache callbacks don't store userdata, so can't save
1001 // off the LLOfferInfo. Argh. JC
1002 BOOL name_found = FALSE;
1003 char first_name[MAX_STRING];
1004 char last_name[MAX_STRING];
1005 if (info->mFromGroup)
1006 {
1007 if (gCacheName->getGroupName(info->mFromID, first_name))
1008 {
1009 args["[FIRST]"] = first_name;
1010 args["[LAST]"] = "";
1011 name_found = TRUE;
1012 }
1013 }
1014 else
1015 {
1016 if (gCacheName->getName(info->mFromID, first_name, last_name))
1017 {
1018 args["[FIRST]"] = first_name;
1019 args["[LAST]"] = last_name;
1020 name_found = TRUE;
1021 }
1022 }
1023 if (from_task)
1024 {
1025 args["[OBJECTFROMNAME]"] = info->mFromName;
1026 if (name_found)
1027 {
1028 LLNotifyBox::showXml("ObjectGiveItem", args,
1029 &inventory_offer_callback, (void*)info);
1030 }
1031 else
1032 {
1033 LLNotifyBox::showXml("ObjectGiveItemUnknownUser", args,
1034 &inventory_offer_callback, (void*)info);
1035 }
1036 }
1037 else
1038 {
1039 // XUI:translate -> [FIRST] [LAST]
1040 args["[NAME]"] = info->mFromName;
1041 LLNotifyBox::showXml("UserGiveItem", args,
1042 &inventory_offer_callback, (void*)info);
1043 }
1044 break;
1045 }
1046 }
1047}
1048
1049
1050void group_vote_callback(S32 option, void *userdata)
1051{
1052 LLUUID *group_id = (LLUUID *)userdata;
1053 if (!group_id) return;
1054
1055 switch(option)
1056 {
1057 case 0:
1058 // Vote Now
1059 // Open up the voting tab
1060 LLFloaterGroupInfo::showFromUUID(*group_id, "voting_tab");
1061 break;
1062 default:
1063 // Vote Later or
1064 // close button
1065 break;
1066 }
1067 delete group_id;
1068 group_id = NULL;
1069}
1070
1071struct LLLureInfo
1072{
1073 LLLureInfo(const LLUUID& from, const LLUUID& lure_id, BOOL godlike) :
1074 mFromID(from),
1075 mLureID(lure_id),
1076 mGodlike(godlike)
1077 {}
1078
1079 LLUUID mFromID;
1080 LLUUID mLureID;
1081 BOOL mGodlike;
1082};
1083
1084void lure_callback(S32 option, void* user_data)
1085{
1086 LLLureInfo* info = (LLLureInfo*)user_data;
1087 if(!info) return;
1088 switch(option)
1089 {
1090 case 0:
1091 {
1092 // accept
1093 send_simple_im(info->mFromID,
1094 "",
1095 IM_LURE_ACCEPTED,
1096 info->mLureID);
1097 gAgent.teleportViaLure(info->mLureID, info->mGodlike);
1098 }
1099 break;
1100 case 1:
1101 default:
1102 // decline
1103 send_simple_im(info->mFromID,
1104 "",
1105 IM_LURE_DECLINED,
1106 info->mLureID);
1107 break;
1108 }
1109 delete info;
1110 info = NULL;
1111}
1112
1113void goto_url_callback(S32 option, void* user_data)
1114{
1115 char* url = (char*)user_data;
1116 if(1 == option)
1117 {
1118 LLWeb::loadURL(url);
1119 }
1120 delete[] url;
1121}
1122
1123void process_improved_im(LLMessageSystem *msg, void **user_data)
1124{
1125 if (gNoRender)
1126 {
1127 return;
1128 }
1129 LLUUID from_id;
1130 BOOL from_group;
1131 LLUUID to_id;
1132 U8 offline;
1133 U8 d = 0;
1134 LLUUID session_id;
1135 U32 t;
1136 char name[DB_FULL_NAME_BUF_SIZE];
1137 char message[DB_IM_MSG_BUF_SIZE];
1138 U32 parent_estate_id = 0;
1139 LLUUID region_id;
1140 LLVector3 position;
1141 char buffer[DB_IM_MSG_BUF_SIZE * 2];
1142 U8 binary_bucket[MTUBYTES];
1143 S32 binary_bucket_size;
1144 LLChat chat;
1145
1146 //XUI:translate - need to fix the full name to first/last
1147 msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, from_id);
1148 msg->getBOOLFast(_PREHASH_MessageBlock, _PREHASH_FromGroup, from_group);
1149 msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_ToAgentID, to_id);
1150 msg->getU8Fast( _PREHASH_MessageBlock, _PREHASH_Offline, offline);
1151 msg->getU8Fast( _PREHASH_MessageBlock, _PREHASH_Dialog, d);
1152 msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_ID, session_id);
1153 msg->getU32Fast( _PREHASH_MessageBlock, _PREHASH_Timestamp, t);
1154 //msg->getData("MessageBlock", "Count", &count);
1155 msg->getStringFast(_PREHASH_MessageBlock, _PREHASH_FromAgentName, DB_FULL_NAME_BUF_SIZE, name);
1156 msg->getStringFast(_PREHASH_MessageBlock, _PREHASH_Message, DB_IM_MSG_BUF_SIZE, message);
1157 msg->getU32Fast(_PREHASH_MessageBlock, _PREHASH_ParentEstateID, parent_estate_id);
1158 msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_RegionID, region_id);
1159 msg->getVector3Fast(_PREHASH_MessageBlock, _PREHASH_Position, position);
1160 msg->getBinaryDataFast( _PREHASH_MessageBlock, _PREHASH_BinaryBucket, binary_bucket, 0, 0, MTUBYTES);
1161 binary_bucket_size = msg->getSizeFast(_PREHASH_MessageBlock, _PREHASH_BinaryBucket);
1162 EInstantMessage dialog = (EInstantMessage)d;
1163 time_t timestamp = (time_t)t;
1164
1165 BOOL is_busy = gAgent.getBusy();
1166 BOOL is_muted = gMuteListp->isMuted(from_id, name);
1167 BOOL is_linden = gMuteListp->isLinden(name);
1168 BOOL is_owned_by_me = FALSE;
1169
1170 chat.mMuted = is_muted && !is_linden;
1171 chat.mFromID = from_id;
1172 chat.mFromName = name;
1173
1174 LLViewerObject *source = gObjectList.findObject(session_id);
1175 if (source)
1176 {
1177 is_owned_by_me = source->permYouOwner();
1178 }
1179
1180 char separator_string[3]=": ";
1181 int message_offset=0;
1182
1183 //Handle IRC styled /me messages.
1184 if (!strncmp(message, "/me ", 4) || !strncmp(message, "/me'", 4))
1185 {
1186 strcpy(separator_string,"");
1187 message_offset=3;
1188 }
1189
1190 LLString::format_map_t args;
1191 switch(dialog)
1192 {
1193 case IM_CONSOLE_AND_CHAT_HISTORY:
1194 // These are used for system messages, hence don't need the name,
1195 // as it is always "Second Life".
1196 // XUI:translate
1197 args["[MESSAGE]"] = message;
1198
1199 // Note: don't put the message in the IM history, even though was sent
1200 // via the IM mechanism.
1201 LLNotifyBox::showXml("SystemMessageTip",args);
1202 break;
1203
1204 case IM_NOTHING_SPECIAL:
1205 // Don't show dialog, just do IM
1206 if (!gAgent.isGodlike()
1207 && gAgent.getRegion()->isPrelude()
1208 && to_id.isNull() )
1209 {
1210 // do nothing -- don't distract newbies in
1211 // Prelude with global IMs
1212 }
1213 else if (offline == IM_ONLINE && !is_linden && is_busy && strcmp(name, SYSTEM_FROM))
1214 {
1215 // return a standard "busy" message, but only do it to online IM
1216 // (i.e. not other auto responses and not store-and-forward IM)
1217 if (!gIMView->hasSession(session_id))
1218 {
1219 // if there is not a panel for this conversation (i.e. it is a new IM conversation
1220 // initiated by the other party) then...
1221 std::string my_name;
1222 gAgent.buildFullname(my_name);
1223 LLString response = gSavedPerAccountSettings.getText("BusyModeResponse");
1224 pack_instant_message(
1225 gMessageSystem,
1226 gAgent.getID(),
1227 FALSE,
1228 gAgent.getSessionID(),
1229 from_id,
1230 my_name.c_str(),
1231 response.c_str(),
1232 IM_ONLINE,
1233 IM_BUSY_AUTO_RESPONSE,
1234 session_id);
1235 gAgent.sendReliableMessage();
1236 }
1237
1238 // now store incoming IM in chat history
1239
1240 sprintf(buffer, "%s%s%s", name, separator_string, (message+message_offset));
1241
1242 if(from_id == gAgentID)
1243 {
1244 from_id = LLUUID::null;
1245 }
1246 llinfos << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << llendl;
1247
1248 // add to IM panel, but do not bother the user
1249 gIMView->addMessage(
1250 session_id,
1251 from_id,
1252 name,
1253 buffer,
1254 NULL,
1255 dialog,
1256 parent_estate_id,
1257 region_id,
1258 position);
1259
1260 // pretend this is chat generated by self, so it does not show up on screen
1261 sprintf(buffer, "IM: %s%s%s", name, separator_string, (message+message_offset));
1262 chat.mText = buffer;
1263 LLFloaterChat::addChat( chat, TRUE, TRUE );
1264 }
1265 else if (from_id.isNull())
1266 {
1267 // Messages from "Second Life" don't go to IM history
1268 sprintf(buffer, "%s: %s", name, message);
1269 chat.mText = buffer;
1270 LLFloaterChat::addChat(chat, FALSE, FALSE);
1271 }
1272 else if (to_id.isNull())
1273 {
1274 // Message to everyone from GOD
1275 args["[NAME]"] = name;
1276 args["[MESSAGE]"] = message;
1277 LLNotifyBox::showXml("GodMessage", args);
1278
1279 // Treat like a system message and put in chat history.
1280 // Claim to be from a local agent so it doesn't go into
1281 // console.
1282 sprintf(buffer, "%s%s%s", name, separator_string, (message+message_offset));
1283 chat.mText = buffer;
1284 BOOL local_agent = TRUE;
1285 LLFloaterChat::addChat(chat, FALSE, local_agent);
1286 }
1287 else
1288 {
1289 // standard message, not from system
1290 char saved[MAX_STRING];
1291 saved[0] = '\0';
1292 if(offline == IM_OFFLINE)
1293 {
1294 char time_buf[TIME_STR_LENGTH];
1295 sprintf(saved, "(Saved %s) ",
1296 formatted_time(timestamp, time_buf));
1297 }
1298 sprintf(buffer, "%s%s%s%s", name, separator_string, saved,(message+message_offset));
1299 if(from_id == gAgentID)
1300 {
1301 from_id = LLUUID::null;
1302 }
1303 llinfos << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << llendl;
1304
1305 if (!is_muted || is_linden)
1306 {
1307 gIMView->addMessage(
1308 session_id,
1309 from_id,
1310 name,
1311 buffer,
1312 NULL,
1313 dialog,
1314 parent_estate_id,
1315 region_id,
1316 position);
1317 sprintf(buffer, "IM: %s%s%s%s", name, separator_string, saved, (message+message_offset));
1318
1319 chat.mText = buffer;
1320 BOOL local_agent = FALSE;
1321 LLFloaterChat::addChat( chat, TRUE, local_agent );
1322 }
1323 else
1324 {
1325 // muted user, so don't start an IM session, just record line in chat
1326 // history. Pretend the chat is from a local agent,
1327 // so it will go into the history but not be shown on screen.
1328 chat.mText = buffer;
1329 BOOL local_agent = TRUE;
1330 LLFloaterChat::addChat( chat, TRUE, local_agent );
1331 }
1332 }
1333 break;
1334
1335 case IM_TYPING_START:
1336 {
1337 LLPointer<LLIMInfo> im_info = new LLIMInfo(gMessageSystem);
1338 gIMView->processIMTypingStart(im_info);
1339 }
1340 break;
1341
1342 case IM_TYPING_STOP:
1343 {
1344 LLPointer<LLIMInfo> im_info = new LLIMInfo(gMessageSystem);
1345 gIMView->processIMTypingStop(im_info);
1346 }
1347 break;
1348
1349 case IM_MESSAGEBOX:
1350 {
1351 // This is a block, modeless dialog.
1352 //XUI:translate
1353 args["[MESSAGE]"] = message;
1354 LLNotifyBox::showXml("SystemMessage", args);
1355 }
1356 break;
1357 case IM_GROUP_NOTICE:
1358 case IM_GROUP_NOTICE_REQUESTED:
1359 {
1360 llinfos << "Received IM_GROUP_NOTICE message." << llendl;
1361 // Read the binary bucket for more information.
1362 struct notice_bucket_header_t
1363 {
1364 U8 has_inventory;
1365 U8 asset_type;
1366 LLUUID group_id;
1367 };
1368 struct notice_bucket_full_t
1369 {
1370 struct notice_bucket_header_t header;
1371 U8 item_name[DB_INV_ITEM_NAME_BUF_SIZE];
1372 }* notice_bin_bucket;
1373
1374 // Make sure the binary bucket is big enough to hold the header
1375 // and a null terminated item name.
1376 if ( (binary_bucket_size < (sizeof(notice_bucket_header_t) + sizeof(U8)))
1377 || (binary_bucket[binary_bucket_size - 1] != '\0') )
1378 {
1379 llwarns << "Malformed group notice binary bucket" << llendl;
1380 break;
1381 }
1382
1383 notice_bin_bucket = (struct notice_bucket_full_t*) &binary_bucket[0];
1384 U8 has_inventory = notice_bin_bucket->header.has_inventory;
1385 U8 asset_type = notice_bin_bucket->header.asset_type;
1386 LLUUID group_id = notice_bin_bucket->header.group_id;
1387 const char* item_name = (const char*) notice_bin_bucket->item_name;
1388
1389 // If there is inventory, give the user the inventory offer.
1390 LLOfferInfo* info = NULL;
1391 if (has_inventory)
1392 {
1393 info = new LLOfferInfo;
1394 info->mIM = IM_GROUP_NOTICE;
1395 info->mFromID = from_id;
1396 info->mFromGroup = from_group;
1397 info->mTransactionID = session_id;
1398 info->mType = (LLAssetType::EType) asset_type;
1399 info->mFolderID = gInventory.findCategoryUUIDForType(info->mType);
1400 std::string from_name;
1401
1402 from_name += "A group member named ";
1403 from_name += name;
1404
1405 info->mFromName = from_name;
1406 info->mDesc = item_name;
1407 info->mHost = msg->getSender();
1408 }
1409
1410 std::string str(message);
1411
1412 // Tokenize the string.
1413 // TODO: Support escaped tokens ("||" -> "|")
1414 typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
1415 boost::char_separator<char> sep("|","",boost::keep_empty_tokens);
1416 tokenizer tokens(str, sep);
1417 tokenizer::iterator iter = tokens.begin();
1418
1419 LLString subj(*iter++);
1420 LLString mes(*iter++);
1421
1422 if (IM_GROUP_NOTICE == dialog)
1423 {
1424 subj += "\n";
1425 mes = "\n\n" + mes;
1426 LLGroupNotifyBox::show(subj.c_str(),mes.c_str(),name,group_id,t,has_inventory,item_name,info);
1427 }
1428 else if (IM_GROUP_NOTICE_REQUESTED == dialog)
1429 {
1430 LLFloaterGroupInfo::showNotice(subj.c_str(),mes.c_str(),group_id,has_inventory,item_name,info);
1431 }
1432 }
1433 break;
1434 case IM_GROUP_INVITATION:
1435 {
1436 //if (!is_linden && (is_busy || is_muted))
1437 if ((is_busy || is_muted))
1438 {
1439 LLMessageSystem *msg = gMessageSystem;
1440 join_group_callback(1, NULL);
1441 busy_message(msg,from_id);
1442 }
1443 else
1444 {
1445 llinfos << "Received IM_GROUP_INVITATION message." << llendl;
1446 // Read the binary bucket for more information.
1447 struct invite_bucket_t
1448 {
1449 S32 membership_fee;
1450 LLUUID role_id;
1451 }* invite_bucket;
1452
1453 // Make sure the binary bucket is the correct size.
1454 if (binary_bucket_size != sizeof(invite_bucket_t))
1455 {
1456 llwarns << "Malformed group invite binary bucket" << llendl;
1457 break;
1458 }
1459
1460 invite_bucket = (struct invite_bucket_t*) &binary_bucket[0];
1461 S32 membership_fee = ntohl(invite_bucket->membership_fee);
1462
1463 LLJoinGroupData* userdata = new LLJoinGroupData;
1464 userdata->mTransactionID = session_id;
1465 userdata->mGroupID = from_id;
1466 userdata->mName.assign(name);
1467 userdata->mMessage.assign(message);
1468 userdata->mFee = membership_fee;
1469
1470 LLString::format_map_t args;
1471 args["[MESSAGE]"] = message;
1472 LLNotifyBox::showXml("JoinGroup", args,
1473 &join_group_callback,
1474 (void*)userdata);
1475 }
1476 }
1477 break;
1478
1479 case IM_INVENTORY_OFFERED:
1480 case IM_TASK_INVENTORY_OFFERED:
1481 // Someone has offered us some inventory.
1482 {
1483 LLOfferInfo* info = new LLOfferInfo;
1484
1485 if (IM_INVENTORY_OFFERED == dialog)
1486 {
1487 struct offer_agent_bucket_t
1488 {
1489 S8 asset_type;
1490 LLUUID object_id;
1491 }* bucketp;
1492
1493 if (sizeof(offer_agent_bucket_t) != binary_bucket_size)
1494 {
1495 llwarns << "Malformed inventory offer from agent" << llendl;
1496 break;
1497 }
1498 bucketp = (struct offer_agent_bucket_t*) &binary_bucket[0];
1499 info->mType = (LLAssetType::EType) bucketp->asset_type;
1500 info->mObjectID = bucketp->object_id;
1501 }
1502 else
1503 {
1504 if (sizeof(S8) != binary_bucket_size)
1505 {
1506 llwarns << "Malformed inventory offer from object" << llendl;
1507 break;
1508 }
1509 info->mType = (LLAssetType::EType) binary_bucket[0];
1510 info->mObjectID = LLUUID::null;
1511 }
1512
1513 info->mIM = dialog;
1514 info->mFromID = from_id;
1515 info->mFromGroup = from_group;
1516 info->mTransactionID = session_id;
1517 info->mFolderID = gInventory.findCategoryUUIDForType(info->mType);
1518
1519 if (dialog == IM_TASK_INVENTORY_OFFERED)
1520 {
1521 info->mFromObject = TRUE;
1522 }
1523 else
1524 {
1525 info->mFromObject = FALSE;
1526 }
1527 info->mFromName = name;
1528 info->mDesc = message;
1529 info->mHost = msg->getSender();
1530 //if (!is_linden && ((is_busy && !is_owned_by_me) || is_muted))
1531 if (((is_busy && !is_owned_by_me) || is_muted))
1532 {
1533 // Same as closing window
1534 inventory_offer_callback(-1, info);
1535 }
1536 else
1537 {
1538 if (dialog == IM_TASK_INVENTORY_OFFERED)
1539 inventory_offer_handler(info, TRUE);
1540 else
1541 inventory_offer_handler(info, FALSE);
1542 }
1543 }
1544 break;
1545
1546 case IM_INVENTORY_ACCEPTED:
1547 {
1548 args["[NAME]"] = name;
1549 LLNotifyBox::showXml("InventoryAccepted", args);
1550 break;
1551 }
1552 case IM_INVENTORY_DECLINED:
1553 {
1554 args["[NAME]"] = name;
1555 LLNotifyBox::showXml("InventoryDeclined", args);
1556 break;
1557 }
1558 case IM_GROUP_VOTE:
1559 {
1560 LLUUID *userdata = new LLUUID(session_id);
1561 args["[NAME]"] = name;
1562 args["[MESSAGE]"] = message;
1563 LLNotifyBox::showXml("GroupVote", args,
1564 &group_vote_callback, userdata);
1565 }
1566 break;
1567
1568 case IM_GROUP_ELECTION_DEPRECATED:
1569 {
1570 llwarns << "Received IM: IM_GROUP_ELECTION_DEPRECATED" << llendl;
1571 }
1572 break;
1573 case IM_SESSION_SEND:
1574 {
1575 if (!is_linden && is_busy)
1576 {
1577 return;
1578 }
1579
1580 // standard message, not from system
1581 char saved[MAX_STRING];
1582 saved[0] = '\0';
1583 if(offline == IM_OFFLINE)
1584 {
1585 char time_buf[TIME_STR_LENGTH];
1586 sprintf(saved,
1587 "(Saved %s) ",
1588 formatted_time(timestamp, time_buf));
1589 }
1590 sprintf(buffer, "%s%s%s%s", name, separator_string, saved, (message+message_offset));
1591 BOOL is_this_agent = FALSE;
1592 if(from_id == gAgentID)
1593 {
1594 from_id = LLUUID::null;
1595 is_this_agent = TRUE;
1596 }
1597 gIMView->addMessage(
1598 session_id,
1599 from_id,
1600 name,
1601 buffer,
1602 (char*)binary_bucket,
1603 IM_SESSION_ADD,
1604 parent_estate_id,
1605 region_id,
1606 position);
1607
1608 sprintf(buffer, "IM: %s%s%s%s", name, separator_string, saved, (message+message_offset));
1609 chat.mText = buffer;
1610 LLFloaterChat::addChat(chat, TRUE, is_this_agent);
1611 }
1612 break;
1613
1614 case IM_FROM_TASK:
1615 if (is_busy && !is_owned_by_me)
1616 {
1617 return;
1618 }
1619 sprintf(buffer, "%s%s%s", name, separator_string, (message+message_offset));
1620 // Note: lie to LLFloaterChat::addChat(), pretending that this is NOT an IM, because
1621 // IMs from objcts don't open IM sessions.
1622 chat.mText = buffer;
1623 chat.mSourceType = CHAT_SOURCE_OBJECT;
1624 LLFloaterChat::addChat(chat, FALSE, FALSE);
1625 break;
1626 case IM_FROM_TASK_AS_ALERT:
1627 if (is_busy && !is_owned_by_me)
1628 {
1629 return;
1630 }
1631 {
1632 // Construct a viewer alert for this message.
1633 args["[NAME]"] = name;
1634 args["[MESSAGE]"] = message;
1635 LLNotifyBox::showXml("ObjectMessage", args);
1636 }
1637 break;
1638 case IM_BUSY_AUTO_RESPONSE:
1639 gIMView->addMessage(session_id, from_id, name, message);
1640 break;
1641
1642 case IM_LURE_USER:
1643 {
1644 if (is_muted)
1645 {
1646 return;
1647 }
1648 else if (is_busy)
1649 {
1650 busy_message(msg,from_id);
1651 }
1652 else
1653 {
1654 // XUI:translate -> [FIRST] [LAST]
1655 LLLureInfo* info = new LLLureInfo(from_id, session_id, FALSE);
1656 args["[NAME]"] = name;
1657 args["[MESSAGE]"] = message;
1658 LLNotifyBox::showXml("OfferTeleport", args,
1659 lure_callback, (void*)info);
1660 }
1661 }
1662 break;
1663
1664 case IM_GODLIKE_LURE_USER:
1665 {
1666 LLLureInfo* info = new LLLureInfo(from_id, session_id, TRUE);
1667 // do not show a message box, because you're about to be
1668 // teleported.
1669 lure_callback(0, (void *)info);
1670 }
1671 break;
1672
1673 case IM_LURE_911:
1674 {
1675 // HACK -- the from_id is the im_session_id
1676 LLFloaterIMPanel* panel = gIMView->findFloaterBySession(session_id);
1677 if (panel)
1678 {
1679 panel->addTeleportButton(from_id);
1680 }
1681 else
1682 {
1683 llinfos << "LLFloaterIMPanel not found for " << session_id << " from " << from_id << llendl;
1684 }
1685 }
1686 break;
1687
1688 case IM_GOTO_URL:
1689 {
1690 char* url = new char[binary_bucket_size];
1691 strcpy(url, (char*)binary_bucket);
1692 args["[MESSAGE]"] = message;
1693 args["[URL]"] = url;
1694 LLNotifyBox::showXml("GotoURL", args,
1695 goto_url_callback, (void*)url);
1696 }
1697 break;
1698
1699 case IM_FRIENDSHIP_OFFERED:
1700 {
1701 LLFriendshipOffer* offer = new LLFriendshipOffer;
1702 offer->mFromID = from_id;
1703 offer->mTransactionID = session_id;
1704 offer->mOnline = (offline == IM_ONLINE);
1705 offer->mHost = msg->getSender();
1706
1707 if (is_busy)
1708 {
1709 busy_message(msg, from_id);
1710 friendship_offer_callback(1, (void*)offer);
1711 }
1712 else if (is_muted)
1713 {
1714 friendship_offer_callback(1, (void*)offer);
1715 }
1716 else
1717 {
1718 args["[NAME]"] = name;
1719 LLNotifyBox::showXml("OfferFriendship", args,
1720 &friendship_offer_callback, (void*)offer);
1721 }
1722 }
1723 break;
1724
1725 case IM_FRIENDSHIP_ACCEPTED:
1726 {
1727 // In the case of an offline IM, the formFriendship() may be extraneous
1728 // as the database should already include the relationship. But it
1729 // doesn't hurt for dupes.
1730 LLAvatarTracker::formFriendship(from_id);
1731
1732 std::vector<std::string> strings;
1733 strings.push_back( from_id.getString() );
1734 send_generic_message("requestonlinenotification", strings);
1735
1736 args["[NAME]"] = name;
1737 LLNotifyBox::showXml("FriendshipAccepted", args);
1738 }
1739 break;
1740
1741 case IM_FRIENDSHIP_DECLINED:
1742 args["[NAME]"] = name;
1743 LLNotifyBox::showXml("FriendshipDeclined", args);
1744 break;
1745
1746 default:
1747 llwarns << "Instant message calling for unknown dialog "
1748 << (S32)dialog << llendl;
1749 break;
1750 }
1751
1752 LLWindow* viewer_window = gViewerWindow->getWindow();
1753 if (viewer_window && viewer_window->getMinimized())
1754 {
1755 viewer_window->flashIcon(5.f);
1756 }
1757}
1758
1759void busy_message (LLMessageSystem* msg, LLUUID from_id)
1760{
1761 if (gAgent.getBusy())
1762 {
1763 LLString response = gSavedPerAccountSettings.getText("BusyModeResponse");
1764 pack_instant_message(
1765 gMessageSystem,
1766 gAgent.getID(),
1767 FALSE,
1768 gAgent.getSessionID(),
1769 from_id,
1770 SYSTEM_FROM,
1771 response.c_str(),
1772 IM_ONLINE,
1773 IM_CONSOLE_AND_CHAT_HISTORY);
1774 gAgent.sendReliableMessage();
1775 }
1776}
1777
1778void friendship_offer_callback(S32 option, void* user_data)
1779{
1780 LLFriendshipOffer* offer = (LLFriendshipOffer*)user_data;
1781 if(!offer) return;
1782 LLUUID fid;
1783 LLMessageSystem* msg = gMessageSystem;
1784 switch(option)
1785 {
1786 case 0:
1787 // accept
1788 LLAvatarTracker::formFriendship(offer->mFromID);
1789
1790 fid = gInventory.findCategoryUUIDForType(LLAssetType::AT_CALLINGCARD);
1791
1792 // This will also trigger an onlinenotification if the user is online
1793 msg->newMessageFast(_PREHASH_AcceptFriendship);
1794 msg->nextBlockFast(_PREHASH_AgentData);
1795 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
1796 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
1797 msg->nextBlockFast(_PREHASH_TransactionBlock);
1798 msg->addUUIDFast(_PREHASH_TransactionID, offer->mTransactionID);
1799 msg->nextBlockFast(_PREHASH_FolderData);
1800 msg->addUUIDFast(_PREHASH_FolderID, fid);
1801 msg->sendReliable(offer->mHost);
1802 break;
1803 case 1:
1804 // decline
1805 msg->newMessageFast(_PREHASH_DeclineFriendship);
1806 msg->nextBlockFast(_PREHASH_AgentData);
1807 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
1808 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
1809 msg->nextBlockFast(_PREHASH_TransactionBlock);
1810 msg->addUUIDFast(_PREHASH_TransactionID, offer->mTransactionID);
1811 msg->sendReliable(offer->mHost);
1812 break;
1813 default:
1814 // close button probably, possibly timed out
1815 break;
1816 }
1817
1818 delete offer;
1819 offer = NULL;
1820}
1821
1822struct LLCallingCardOfferData
1823{
1824 LLUUID mTransactionID;
1825 LLUUID mSourceID;
1826 LLHost mHost;
1827};
1828
1829void callingcard_offer_callback(S32 option, void* user_data)
1830{
1831 LLCallingCardOfferData* offerdata = (LLCallingCardOfferData*)user_data;
1832 if(!offerdata) return;
1833 LLUUID fid;
1834 LLUUID from_id;
1835 LLMessageSystem* msg = gMessageSystem;
1836 switch(option)
1837 {
1838 case 0:
1839 // accept
1840 msg->newMessageFast(_PREHASH_AcceptCallingCard);
1841 msg->nextBlockFast(_PREHASH_AgentData);
1842 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
1843 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
1844 msg->nextBlockFast(_PREHASH_TransactionBlock);
1845 msg->addUUIDFast(_PREHASH_TransactionID, offerdata->mTransactionID);
1846 fid = gInventory.findCategoryUUIDForType(LLAssetType::AT_CALLINGCARD);
1847 msg->nextBlockFast(_PREHASH_FolderData);
1848 msg->addUUIDFast(_PREHASH_FolderID, fid);
1849 msg->sendReliable(offerdata->mHost);
1850 break;
1851 case 1:
1852 // decline
1853 msg->newMessageFast(_PREHASH_DeclineCallingCard);
1854 msg->nextBlockFast(_PREHASH_AgentData);
1855 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
1856 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
1857 msg->nextBlockFast(_PREHASH_TransactionBlock);
1858 msg->addUUIDFast(_PREHASH_TransactionID, offerdata->mTransactionID);
1859 msg->sendReliable(offerdata->mHost);
1860 busy_message(msg, offerdata->mSourceID);
1861 break;
1862 default:
1863 // close button probably, possibly timed out
1864 break;
1865 }
1866
1867 delete offerdata;
1868 offerdata = NULL;
1869}
1870
1871void process_offer_callingcard(LLMessageSystem* msg, void**)
1872{
1873 // someone has offered to form a friendship
1874 lldebugs << "callingcard offer" << llendl;
1875
1876 LLUUID source_id;
1877 msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, source_id);
1878 LLUUID tid;
1879 msg->getUUIDFast(_PREHASH_AgentBlock, _PREHASH_TransactionID, tid);
1880
1881 LLCallingCardOfferData* offerdata = new LLCallingCardOfferData;
1882 offerdata->mTransactionID = tid;
1883 offerdata->mSourceID = source_id;
1884 offerdata->mHost = msg->getSender();
1885
1886 LLViewerObject* source = gObjectList.findObject(source_id);
1887 LLString::format_map_t args;
1888 std::string source_name;
1889 if(source && source->isAvatar())
1890 {
1891 LLNameValue* nvfirst = source->getNVPair("FirstName");
1892 LLNameValue* nvlast = source->getNVPair("LastName");
1893 if (nvfirst && nvlast)
1894 {
1895 args["[FIRST]"] = nvfirst->getString();
1896 args["[LAST]"] = nvlast->getString();
1897 source_name = std::string(nvfirst->getString()) + " " + nvlast->getString();
1898 }
1899 }
1900
1901 if(!source_name.empty())
1902 {
1903 if (gAgent.getBusy()
1904 || gMuteListp->isMuted(source_id, source_name))
1905 {
1906 // automatically decline offer
1907 callingcard_offer_callback(1, (void*)offerdata);
1908 return;
1909 }
1910
1911 LLNotifyBox::showXml("OfferCallingCard", args,
1912 &callingcard_offer_callback, (void*)offerdata);
1913 }
1914 else
1915 {
1916 llwarns << "Calling card offer from an unknown source." << llendl;
1917 }
1918}
1919
1920void process_accept_callingcard(LLMessageSystem* msg, void**)
1921{
1922 LLNotifyBox::showXml("CallingCardAccepted");
1923}
1924
1925void process_decline_callingcard(LLMessageSystem* msg, void**)
1926{
1927 LLNotifyBox::showXml("CallingCardDeclined");
1928}
1929
1930
1931void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
1932{
1933 LLChat chat;
1934 char mesg[DB_CHAT_MSG_BUF_SIZE];
1935 char from_name[DB_FULL_NAME_BUF_SIZE];
1936 U8 source_temp;
1937 U8 type_temp;
1938 U8 audible_temp;
1939 LLColor4 color(1.0f, 1.0f, 1.0f, 1.0f);
1940 LLUUID from_id;
1941 LLUUID owner_id;
1942 BOOL is_owned_by_me = FALSE;
1943 LLViewerObject* chatter;
1944
1945 msg->getString("ChatData", "FromName", DB_FULL_NAME_BUF_SIZE, from_name);
1946 chat.mFromName = from_name;
1947
1948 msg->getUUID("ChatData", "SourceID", from_id);
1949 chat.mFromID = from_id;
1950
1951 // Object owner for objects
1952 msg->getUUID("ChatData", "OwnerID", owner_id);
1953
1954 msg->getU8Fast(_PREHASH_ChatData, _PREHASH_SourceType, source_temp);
1955 chat.mSourceType = (EChatSourceType)source_temp;
1956
1957 msg->getU8("ChatData", "ChatType", type_temp);
1958 chat.mChatType = (EChatType)type_temp;
1959
1960 msg->getU8Fast(_PREHASH_ChatData, _PREHASH_Audible, audible_temp);
1961 chat.mAudible = (EChatAudible)audible_temp;
1962
1963 chat.mTime = LLFrameTimer::getElapsedSeconds();
1964
1965 BOOL is_self = (from_id == gAgent.getID());
1966 BOOL is_busy = gAgent.getBusy();
1967
1968 // Apparently you can receive chat before app is fully initialized, hence
1969 // gMuteListp can be null. JC
1970 BOOL is_muted = FALSE;
1971 BOOL is_linden = FALSE;
1972 if (gMuteListp)
1973 {
1974 is_muted = gMuteListp->isMuted(from_id, from_name)
1975 || gMuteListp->isMuted(owner_id);
1976 is_linden = gMuteListp->isLinden(from_name);
1977 }
1978
1979 chatter = gObjectList.findObject(from_id);
1980 if (chatter)
1981 {
1982 chat.mPosAgent = chatter->getPositionAgent();
1983
1984 // Make swirly things only for talking objects. (not script debug messages, though)
1985 if (chat.mSourceType == CHAT_SOURCE_OBJECT
1986 && chat.mChatType != CHAT_TYPE_DEBUG_MSG)
1987 {
1988 LLViewerPartSourceChat *psc = new LLViewerPartSourceChat(chatter->getPositionAgent());
1989 psc->setSourceObject(chatter);
1990 psc->setColor(color);
1991 //We set the particles to be owned by the object's owner,
1992 //just in case they should be muted by the mute list
1993 psc->setOwnerUUID(owner_id);
1994 gWorldPointer->mPartSim.addPartSource(psc);
1995 }
1996
1997 // only pay attention to other people chatting
1998 if ((is_linden || (!is_muted && !is_busy))
1999 && chatter != gAgent.getAvatarObject())
2000 {
2001 gAgent.heardChat(chat);
2002 if (gLindenLabRandomNumber.llrand(2) == 0)
2003 {
2004 gAgent.setLookAt(LOOKAT_TARGET_AUTO_LISTEN, chatter, LLVector3::zero);
2005 }
2006 }
2007
2008 is_owned_by_me = chatter->permYouOwner();
2009 }
2010
2011 BOOL is_audible = (CHAT_AUDIBLE_FULLY == chat.mAudible);
2012 if (is_audible)
2013 {
2014 BOOL visible_in_chat_bubble = FALSE;
2015 std::string verb;
2016
2017 color.setVec(1,1,1,1);
2018 msg->getStringFast(_PREHASH_ChatData, _PREHASH_Message, DB_CHAT_MSG_BUF_SIZE, mesg);
2019
2020 BOOL ircstyle = FALSE;
2021
2022 // Look for IRC-style emotes here so chatbubbles work
2023 if (!strncmp(mesg, "/me ", 4) || !strncmp(mesg, "/me'", 4))
2024 {
2025 chat.mText = from_name;
2026 chat.mText += (mesg + 3);
2027 ircstyle = TRUE;
2028 }
2029 else
2030 {
2031 chat.mText = mesg;
2032 }
2033
2034 // Look for the start of typing so we can put "..." in the bubbles.
2035 if (CHAT_TYPE_START == chat.mChatType)
2036 {
2037 // Might not have the avatar constructed yet, eg on login.
2038 if (chatter && chatter->isAvatar())
2039 {
2040 ((LLVOAvatar*)chatter)->startTyping();
2041 }
2042 return;
2043 }
2044 else if (CHAT_TYPE_STOP == chat.mChatType)
2045 {
2046 // Might not have the avatar constructed yet, eg on login.
2047 if (chatter && chatter->isAvatar())
2048 {
2049 ((LLVOAvatar*)chatter)->stopTyping();
2050 }
2051 return;
2052 }
2053
2054 // We have a real utterance now, so can stop showing "..." and proceed.
2055 if (chatter && chatter->isAvatar())
2056 {
2057 ((LLVOAvatar*)chatter)->stopTyping();
2058
2059 if (!is_muted && !is_busy)
2060 {
2061 visible_in_chat_bubble = gSavedSettings.getBOOL("UseChatBubbles");
2062 ((LLVOAvatar*)chatter)->addChat(chat);
2063 }
2064 }
2065
2066 // Look for IRC-style emotes
2067 if (ircstyle)
2068 {
2069 // Do nothing, ircstyle is fixed above for chat bubbles
2070 }
2071 else
2072 {
2073 switch(chat.mChatType)
2074 {
2075 case CHAT_TYPE_WHISPER:
2076 if (is_self)
2077 {
2078 verb = " whisper: ";
2079 }
2080 else
2081 {
2082 verb = " whispers: ";
2083 }
2084 break;
2085 case CHAT_TYPE_DEBUG_MSG:
2086 case CHAT_TYPE_NORMAL:
2087 verb = ": ";
2088 break;
2089 case CHAT_TYPE_SHOUT:
2090 if (is_self)
2091 {
2092 verb = " shout: ";
2093 }
2094 else
2095 {
2096 verb = " shouts: ";
2097 }
2098 break;
2099 case CHAT_TYPE_START:
2100 case CHAT_TYPE_STOP:
2101 llwarns << "Got chat type start/stop in main chat processing." << llendl;
2102 break;
2103 default:
2104 llwarns << "Unknown type " << chat.mChatType << " in chat!" << llendl;
2105 verb = " say, ";
2106 break;
2107 }
2108
2109 if (is_self)
2110 {
2111 chat.mText = "You";
2112 }
2113 else
2114 {
2115 chat.mText = from_name;
2116 }
2117 chat.mText += verb;
2118 chat.mText += mesg;
2119 }
2120
2121 if (chatter)
2122 {
2123 chat.mPosAgent = chatter->getPositionAgent();
2124 }
2125
2126 // truth table:
2127 // LINDEN BUSY MUTED OWNED_BY_YOU DISPLAY STORE IN HISTORY
2128 // F F F F Yes Yes
2129 // F F F T Yes Yes
2130 // F F T F No No
2131 // F F T T No No
2132 // F T F F No Yes
2133 // F T F T Yes Yes
2134 // F T T F No No
2135 // F T T T No No
2136 // T * * * Yes Yes
2137
2138 chat.mMuted = is_muted && !is_linden;
2139
2140
2141 if (!visible_in_chat_bubble
2142 && (is_linden || !is_busy || is_owned_by_me))
2143 {
2144 // show on screen and add to history
2145 LLFloaterChat::addChat(chat, FALSE, FALSE);
2146 }
2147 else
2148 {
2149 // just add to chat history
2150 LLFloaterChat::addChatHistory(chat);
2151 }
2152 }
2153}
2154
2155/*
2156void process_agent_to_new_region(LLMessageSystem *mesgsys, void **user_data)
2157{
2158// LLFastTimer t(LLFastTimer::FTM_TEMP8);
2159
2160 U64 handle;
2161 U32 ip;
2162 U16 port;
2163 LLUUID session_id;
2164
2165 // Actually, the agent itself should process this message.
2166 // From a "AgentToNewRegion" message
2167 mesgsys->getIPAddrFast(_PREHASH_RegionData, _PREHASH_IP, ip);
2168 mesgsys->getIPPortFast(_PREHASH_RegionData, _PREHASH_Port, port);
2169 mesgsys->getU64Fast(_PREHASH_RegionData, _PREHASH_Handle, handle);
2170 mesgsys->getUUIDFast(_PREHASH_RegionData, _PREHASH_SessionID, session_id);
2171
2172 if (gAgent.getSessionID() != session_id)
2173 {
2174 llwarns << "Got AgentToNewRegion with invalid session ID, ignoring" << llendl;
2175 return;
2176 }
2177
2178 LLViewerRegion *regionp;
2179
2180 F32 x, y;
2181 from_region_handle(handle, &x, &y);
2182 regionp = gWorldp->getRegionFromHandle(handle);
2183 if (!regionp)
2184 {
2185 if (gAgent.getRegion())
2186 {
2187 llwarns << "current region " << gAgent.getRegion()->getOriginGlobal() << llendl;
2188 }
2189
2190 llwarns << "Agent being sent to invalid home region: "
2191 << x << ":" << y
2192 << " current pos " << gAgent.getPositionGlobal()
2193 << llendl;
2194 do_disconnect("You were sent to an invalid region.");
2195 return;
2196
2197 }
2198
2199 if (regionp == gAgent.getRegion())
2200 {
2201 llinfos << "Agent being sent to current home region, skipping." << llendl;
2202 return;
2203 }
2204
2205
2206 llinfos << "AgentToNewRegion - being sent to " << x << ":" << y
2207 << ""
2208
2209 LLVector3 shift_vector = regionp->getPosRegionFromGlobal(gAgent.getRegion()->getOriginGlobal());
2210
2211 gAgent.setRegion(regionp);
2212
2213 gObjectList.shiftObjects(shift_vector);
2214
2215 llinfos << "Changing home region to " << x << ":" << y << llendl;
2216
2217 // send camera update to new region
2218
2219 send_agent_update(TRUE, TRUE);
2220
2221 // set our upstream asset provider to the new simulator
2222 LLHost upstream(ip, port);
2223 gAssetStorage->setUpstream(upstream);
2224 gCacheName->setUpstream(upstream);
2225
2226 // Not needed, as simulator will always send request as it creates the new
2227 // agent in the new region.
2228 // send_current_avatar_info();
2229}
2230*/
2231
2232// Simulator we're on is informing the viewer that the agent
2233// is starting to teleport (perhaps to another sim, perhaps to the
2234// same sim). If we initiated the teleport process by sending some kind
2235// of TeleportRequest, then this info is redundant, but if the sim
2236// initiated the teleport (via a script call, being killed, etc.)
2237// then this info is news to us.
2238void process_teleport_start(LLMessageSystem *msg, void**)
2239{
2240 U32 teleport_flags = 0x0;
2241 msg->getU32("Info", "TeleportFlags", teleport_flags);
2242
2243 if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL)
2244 {
2245 gViewerWindow->setProgressCancelButtonVisible(FALSE, "");
2246 }
2247 else
2248 {
2249 gViewerWindow->setProgressCancelButtonVisible(TRUE, "Cancel");
2250 }
2251
2252 // Freeze the UI and show progress bar
2253 // Note: could add data here to differentiate between normal teleport and death.
2254
2255 if( gAgent.getTeleportState() == LLAgent::TELEPORT_NONE )
2256 {
2257 gTeleportDisplay = TRUE;
2258 gAgent.setTeleportState( LLAgent::TELEPORT_START );
2259 make_ui_sound("UISndTeleportOut");
2260
2261 // Don't call LLFirstUse::useTeleport here because this could be
2262 // due to being killed, which would send you home, not to a Telehub
2263 }
2264}
2265
2266void process_teleport_progress(LLMessageSystem* msg, void**)
2267{
2268 LLUUID agent_id;
2269 msg->getUUID("AgentData", "AgentID", agent_id);
2270 if((gAgent.getID() != agent_id)
2271 || (gAgent.getTeleportState() == LLAgent::TELEPORT_NONE))
2272 {
2273 llwarns << "Unexpected teleport progress message." << llendl;
2274 return;
2275 }
2276 U32 teleport_flags = 0x0;
2277 msg->getU32("Info", "TeleportFlags", teleport_flags);
2278 if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL)
2279 {
2280 gViewerWindow->setProgressCancelButtonVisible(FALSE, "");
2281 }
2282 else
2283 {
2284 gViewerWindow->setProgressCancelButtonVisible(TRUE, "Cancel");
2285 }
2286 char buffer[MAX_STRING];
2287 msg->getString("Info", "Message", MAX_STRING, buffer);
2288 lldebugs << "teleport progress: " << buffer << llendl;
2289 gAgent.setTeleportMessage(buffer);
2290}
2291
2292class LLFetchInWelcomeArea : public LLInventoryFetchDescendentsObserver
2293{
2294public:
2295 LLFetchInWelcomeArea() {}
2296 virtual void done()
2297 {
2298 LLIsType is_landmark(LLAssetType::AT_LANDMARK);
2299 LLIsType is_card(LLAssetType::AT_CALLINGCARD);
2300 LLInventoryModel::cat_array_t cats;
2301 LLInventoryModel::item_array_t items;
2302 folder_ref_t::iterator it = mCompleteFolders.begin();
2303 folder_ref_t::iterator end = mCompleteFolders.end();
2304 for(; it != end; ++it)
2305 {
2306 gInventory.collectDescendentsIf(
2307 (*it),
2308 cats,
2309 items,
2310 LLInventoryModel::EXCLUDE_TRASH,
2311 is_landmark);
2312 gInventory.collectDescendentsIf(
2313 (*it),
2314 cats,
2315 items,
2316 LLInventoryModel::EXCLUDE_TRASH,
2317 is_card);
2318 }
2319 S32 count = items.count();
2320 for(S32 i = 0; i < count; ++i)
2321 {
2322 LLString::format_map_t args;
2323 args["[NAME]"] = items[i]->getName();
2324 switch(items[i]->getType())
2325 {
2326 case LLAssetType::AT_LANDMARK:
2327 LLNotifyBox::showXml("TeleportToLandmark",args);
2328 break;
2329 case LLAssetType::AT_CALLINGCARD:
2330 LLNotifyBox::showXml("TeleportToPerson",args);
2331 break;
2332 default:
2333 break;
2334 }
2335 }
2336 gInventory.removeObserver(this);
2337 delete this;
2338 }
2339};
2340
2341// Teleport notification from the simulator
2342// We're going to pretend to be a new agent
2343void process_teleport_finish(LLMessageSystem* msg, void**)
2344{
2345 //llinfos << "Got teleport location message" << llendl;
2346 LLUUID agent_id;
2347 msg->getUUIDFast(_PREHASH_Info, _PREHASH_AgentID, agent_id);
2348 if (agent_id != gAgent.getID())
2349 {
2350 llwarns << "Got teleport notification for wrong agent!" << llendl;
2351 return;
2352 }
2353
2354 // Do teleport effect for where you're leaving
2355 // VEFFECT: TeleportStart
2356 LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)gHUDManager->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE);
2357 effectp->setPositionGlobal(gAgent.getPositionGlobal());
2358 effectp->setColor(LLColor4U(gAgent.getEffectColor()));
2359 gHUDManager->sendEffects();
2360
2361 U32 location_id;
2362 U32 sim_ip;
2363 U16 sim_port;
2364 LLVector3 pos, look_at;
2365 U64 region_handle;
2366 msg->getU32Fast(_PREHASH_Info, _PREHASH_LocationID, location_id);
2367 msg->getIPAddrFast(_PREHASH_Info, _PREHASH_SimIP, sim_ip);
2368 msg->getIPPortFast(_PREHASH_Info, _PREHASH_SimPort, sim_port);
2369 //msg->getVector3Fast(_PREHASH_Info, _PREHASH_Position, pos);
2370 //msg->getVector3Fast(_PREHASH_Info, _PREHASH_LookAt, look_at);
2371 msg->getU64Fast(_PREHASH_Info, _PREHASH_RegionHandle, region_handle);
2372 U32 teleport_flags;
2373 msg->getU32Fast(_PREHASH_Info, _PREHASH_TeleportFlags, teleport_flags);
2374
2375
2376 char seedCap[STD_STRING_BUF_SIZE];
2377 msg->getStringFast(_PREHASH_Info, _PREHASH_SeedCapability,
2378 STD_STRING_BUF_SIZE, seedCap);
2379
2380 // update home location if we are teleporting out of prelude
2381 if((teleport_flags & TELEPORT_FLAGS_SET_HOME_TO_TARGET)
2382 && (!gAgent.isGodlike()))
2383 {
2384 gAgent.setHomePosRegion(region_handle, pos);
2385
2386 // get callingcards and landmarks available to the user arriving.
2387 LLInventoryFetchDescendentsObserver::folder_ref_t folders;
2388 LLUUID folder_id;
2389 folder_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_CALLINGCARD);
2390 if(folder_id.notNull()) folders.push_back(folder_id);
2391 folder_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_LANDMARK);
2392 if(folder_id.notNull()) folders.push_back(folder_id);
2393 if(!folders.empty())
2394 {
2395 LLFetchInWelcomeArea* fetcher = new LLFetchInWelcomeArea;
2396 fetcher->fetchDescendents(folders);
2397 if(fetcher->isEverythingComplete())
2398 {
2399 fetcher->done();
2400 }
2401 else
2402 {
2403 gInventory.addObserver(fetcher);
2404 }
2405 }
2406 }
2407
2408 LLHost sim_host(sim_ip, sim_port);
2409
2410 // Viewer trusts the simulator.
2411 gMessageSystem->enableCircuit(sim_host, TRUE);
2412 LLViewerRegion* regionp = gWorldp->addRegion(region_handle, sim_host);
2413
2414/*
2415 // send camera update to new region
2416 gAgent.updateCamera();
2417
2418 // likewise make sure the camera is behind the avatar
2419 gAgent.resetView(TRUE);
2420 LLVector3 shift_vector = regionp->getPosRegionFromGlobal(gAgent.getRegion()->getOriginGlobal());
2421 gAgent.setRegion(regionp);
2422 gObjectList.shiftObjects(shift_vector);
2423
2424 if (gAgent.getAvatarObject())
2425 {
2426 gAgent.getAvatarObject()->clearChatText();
2427 gAgent.slamLookAt(look_at);
2428 }
2429 gAgent.setPositionAgent(pos);
2430 gAssetStorage->setUpstream(sim);
2431 gCacheName->setUpstream(sim);
2432*/
2433
2434 // now, use the circuit info to tell simulator about us!
2435 llinfos << "process_teleport_finish() Enabling "
2436 << sim_host << " with code " << msg->mOurCircuitCode << llendl;
2437 msg->newMessageFast(_PREHASH_UseCircuitCode);
2438 msg->nextBlockFast(_PREHASH_CircuitCode);
2439 msg->addU32Fast(_PREHASH_Code, msg->getOurCircuitCode());
2440 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
2441 msg->addUUIDFast(_PREHASH_ID, gAgent.getID());
2442 msg->sendReliable(sim_host);
2443
2444 send_complete_agent_movement(sim_host);
2445 gAgent.setTeleportState( LLAgent::TELEPORT_MOVING );
2446 gAgent.setTeleportMessage("Contacting New Region...");
2447
2448 regionp->setSeedCapability(std::string(seedCap));
2449
2450 // Don't send camera updates to the new region until we're
2451 // actually there...
2452
2453
2454 // Now do teleport effect for where you're going.
2455 // VEFFECT: TeleportEnd
2456 effectp = (LLHUDEffectSpiral *)gHUDManager->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE);
2457 effectp->setPositionGlobal(gAgent.getPositionGlobal());
2458
2459 effectp->setColor(LLColor4U(gAgent.getEffectColor()));
2460 gHUDManager->sendEffects();
2461
2462// gTeleportDisplay = TRUE;
2463// gTeleportDisplayTimer.reset();
2464// gViewerWindow->setShowProgress(TRUE);
2465
2466 // This could be first use of teleport, so test for that
2467 LLFirstUse::useTeleport();
2468}
2469
2470// stuff we have to do every time we get an AvatarInitComplete from a sim
2471/*
2472void process_avatar_init_complete(LLMessageSystem* msg, void**)
2473{
2474 LLVector3 agent_pos;
2475 msg->getVector3Fast(_PREHASH_AvatarData, _PREHASH_Position, agent_pos);
2476 agent_movement_complete(msg->getSender(), agent_pos);
2477}
2478*/
2479
2480void process_agent_movement_complete(LLMessageSystem* msg, void**)
2481{
2482 LLUUID agent_id;
2483 msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
2484 LLUUID session_id;
2485 msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id);
2486 if((gAgent.getID() != agent_id) || (gAgent.getSessionID() != session_id))
2487 {
2488 llwarns << "Incorrect id in process_agent_movement_complete()"
2489 << llendl;
2490 return;
2491 }
2492
2493 llinfos << "process_agent_movement_complete()" << llendl;
2494
2495 // *TODO: check timestamp to make sure the movement compleation
2496 // makes sense.
2497 LLVector3 agent_pos;
2498 msg->getVector3Fast(_PREHASH_Data, _PREHASH_Position, agent_pos);
2499 LLVector3 look_at;
2500 msg->getVector3Fast(_PREHASH_Data, _PREHASH_LookAt, look_at);
2501 U64 region_handle;
2502 msg->getU64Fast(_PREHASH_Data, _PREHASH_RegionHandle, region_handle);
2503
2504 LLVOAvatar* avatarp = gAgent.getAvatarObject();
2505 if (!avatarp)
2506 {
2507 // Could happen if you were immediately god-teleported away on login,
2508 // maybe other cases. Continue, but warn. JC
2509 llwarns << "agent_movement_complete() with NULL avatarp." << llendl;
2510 }
2511
2512 F32 x, y;
2513 from_region_handle(region_handle, &x, &y);
2514 LLViewerRegion* regionp = gWorldp->getRegionFromHandle(region_handle);
2515 if (!regionp)
2516 {
2517 if (gAgent.getRegion())
2518 {
2519 llwarns << "current region " << gAgent.getRegion()->getOriginGlobal() << llendl;
2520 }
2521
2522 llwarns << "Agent being sent to invalid home region: "
2523 << x << ":" << y
2524 << " current pos " << gAgent.getPositionGlobal()
2525 << llendl;
2526 do_disconnect("You were sent to an invalid region.");
2527 return;
2528
2529 }
2530
2531 llinfos << "Changing home region to " << x << ":" << y << llendl;
2532
2533 // set our upstream host the new simulator and shuffle things as
2534 // appropriate.
2535 LLVector3 shift_vector = regionp->getPosRegionFromGlobal(
2536 gAgent.getRegion()->getOriginGlobal());
2537 gAgent.setRegion(regionp);
2538 gObjectList.shiftObjects(shift_vector);
2539 gAssetStorage->setUpstream(msg->getSender());
2540 gCacheName->setUpstream(msg->getSender());
2541 gViewerThrottle.sendToSim();
2542 gViewerWindow->sendShapeToSim();
2543
2544 bool is_teleport = false;
2545
2546 if( gAgent.getTeleportState() == LLAgent::TELEPORT_MOVING )
2547 {
2548 // Force the camera back onto the agent, don't animate. JC
2549 gAgent.setFocusOnAvatar(TRUE, FALSE);
2550 gAgent.slamLookAt(look_at);
2551 gAgent.updateCamera();
2552
2553 gAgent.setTeleportState( LLAgent::TELEPORT_START_ARRIVAL );
2554
2555 // set the appearance on teleport since the new sim does not
2556 // know what you look like.
2557 gAgent.sendAgentSetAppearance();
2558
2559 if (avatarp)
2560 {
2561 avatarp->setPositionAgent(agent_pos);
2562 avatarp->clearChat();
2563 avatarp->slamPosition();
2564 }
2565
2566 is_teleport = true;
2567 }
2568 else
2569 {
2570 gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
2571 }
2572
2573 if ( LLTracker::isTracking(NULL) )
2574 {
2575 // Check distance to beacon, if < 5m, remove beacon
2576 LLVector3d beacon_pos = LLTracker::getTrackedPositionGlobal();
2577 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);
2578 if (beacon_dir.magVecSquared() < 25.f)
2579 {
2580 LLTracker::stopTracking(NULL);
2581 }
2582 else if ( is_teleport )
2583 {
2584 //look at the beacon
2585 LLVector3 global_agent_pos = agent_pos;
2586 global_agent_pos[0] += x;
2587 global_agent_pos[1] += y;
2588 look_at = (LLVector3)beacon_pos - global_agent_pos;
2589 look_at.normVec();
2590 gAgent.slamLookAt(look_at);
2591 }
2592 }
2593
2594 // TODO: Put back a check for flying status! DK 12/19/05
2595 // Sim tells us whether the new position is off the ground
2596 /*
2597 if (teleport_flags & TELEPORT_FLAGS_IS_FLYING)
2598 {
2599 gAgent.setFlying(TRUE);
2600 }
2601 else
2602 {
2603 gAgent.setFlying(FALSE);
2604 }
2605 */
2606
2607 send_agent_update(TRUE, TRUE);
2608
2609 if (gAgent.getRegion()->getBlockFly())
2610 {
2611 gAgent.setFlying(gAgent.canFly());
2612 }
2613
2614 // force simulator to recognize busy state
2615 if (gAgent.getBusy())
2616 {
2617 gAgent.setBusy();
2618 }
2619 else
2620 {
2621 gAgent.clearBusy();
2622 }
2623
2624 if (avatarp)
2625 {
2626 avatarp->mFootPlane.clearVec();
2627 }
2628
2629 // reset always run status
2630 msg->newMessageFast(_PREHASH_SetAlwaysRun);
2631 msg->nextBlockFast(_PREHASH_AgentData);
2632 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
2633 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
2634 msg->addBOOLFast(_PREHASH_AlwaysRun, gAgent.getAlwaysRun());
2635 gAgent.sendReliableMessage();
2636}
2637
2638void process_crossed_region(LLMessageSystem* msg, void**)
2639{
2640 LLUUID agent_id;
2641 msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
2642 LLUUID session_id;
2643 msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id);
2644 if((gAgent.getID() != agent_id) || (gAgent.getSessionID() != session_id))
2645 {
2646 llwarns << "Incorrect id in process_crossed_region()"
2647 << llendl;
2648 return;
2649 }
2650 llinfos << "process_crossed_region()" << llendl;
2651
2652 U32 sim_ip;
2653 msg->getIPAddrFast(_PREHASH_RegionData, _PREHASH_SimIP, sim_ip);
2654 U16 sim_port;
2655 msg->getIPPortFast(_PREHASH_RegionData, _PREHASH_SimPort, sim_port);
2656 LLHost sim_host(sim_ip, sim_port);
2657 U64 region_handle;
2658 msg->getU64Fast(_PREHASH_RegionData, _PREHASH_RegionHandle, region_handle);
2659
2660 char seedCap[STD_STRING_BUF_SIZE];
2661 msg->getStringFast(_PREHASH_RegionData, _PREHASH_SeedCapability, STD_STRING_BUF_SIZE, seedCap);
2662
2663 send_complete_agent_movement(sim_host);
2664
2665 LLViewerRegion* regionp = gWorldp->addRegion(region_handle, sim_host);
2666 regionp->setSeedCapability(std::string(seedCap));
2667}
2668
2669
2670
2671// Sends avatar and camera information to simulator.
2672// Sent roughly once per frame, or 20 times per second, whichever is less often
2673
2674const F32 THRESHOLD_HEAD_ROT_QDOT = 0.9997f; // ~= 2.5 degrees -- if its less than this we need to update head_rot
2675const F32 MAX_HEAD_ROT_QDOT = 0.99999f; // ~= 0.5 degrees -- if its greater than this then no need to update head_rot
2676 // between these values we delay the updates (but no more than one second)
2677
2678
2679void send_agent_update(BOOL force_send, BOOL send_reliable)
2680{
2681 if (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE)
2682 {
2683 // We don't care if they want to send an agent update, they're not allowed to until the simulator
2684 // that's the target is ready to receive them (after avatar_init_complete is received)
2685 return;
2686 }
2687
2688 // We have already requested to log out. Don't send agent updates.
2689 if(gLogoutRequestSent)
2690 {
2691 return;
2692 }
2693
2694 const F32 TRANSLATE_THRESHOLD = 0.01f;
2695
2696 // NOTA BENE: This is (intentionally?) using the small angle sine approximation to test for rotation
2697 // Plus, there is an extra 0.5 in the mix since the perpendicular between last_camera_at and getAtAxis() bisects cam_rot_change
2698 // Thus, we're actually testing against 0.2 degrees
2699 const F32 ROTATION_THRESHOLD = 0.1f * 2.f*F_PI/360.f; // Rotation thresh 0.2 deg, see note above
2700
2701 const U8 DUP_MSGS = 1; // HACK! number of times to repeat data on motionless agent
2702
2703 // Store data on last sent update so that if no changes, no send
2704 static LLVector3 last_camera_pos_agent,
2705 last_camera_at,
2706 last_camera_left,
2707 last_camera_up;
2708
2709 static LLVector3 cam_center_chg,
2710 cam_rot_chg;
2711
2712 static LLQuaternion last_head_rot;
2713 static U32 last_control_flags = 0;
2714 static U8 last_render_state;
2715 static U8 duplicate_count = 0;
2716 static F32 head_rot_chg = 1.0;
2717 static U8 last_flags;
2718
2719 LLMessageSystem *msg = gMessageSystem;
2720 LLVector3 camera_pos_agent; // local to avatar's region
2721 U8 render_state;
2722
2723 LLQuaternion body_rotation = gAgent.getFrameAgent().getQuaternion();
2724 LLQuaternion head_rotation = gAgent.getHeadRotation();
2725
2726 camera_pos_agent = gAgent.getCameraPositionAgent();
2727
2728 render_state = gAgent.getRenderState();
2729
2730 U32 control_flag_change = 0;
2731 U8 flag_change = 0;
2732
2733 cam_center_chg = last_camera_pos_agent - camera_pos_agent;
2734 cam_rot_chg = last_camera_at - gCamera->getAtAxis();
2735
2736 // If a modifier key is held down, turn off
2737 // LBUTTON and ML_LBUTTON so that using the camera (alt-key) doesn't
2738 // trigger a control event.
2739 U32 control_flags = gAgent.getControlFlags();
2740 MASK key_mask = gKeyboard->currentMask(TRUE);
2741 if (key_mask & MASK_ALT || key_mask & MASK_CONTROL)
2742 {
2743 control_flags &= ~( AGENT_CONTROL_LBUTTON_DOWN |
2744 AGENT_CONTROL_ML_LBUTTON_DOWN );
2745 control_flags |= AGENT_CONTROL_LBUTTON_UP |
2746 AGENT_CONTROL_ML_LBUTTON_UP ;
2747 }
2748
2749 control_flag_change = last_control_flags ^ control_flags;
2750
2751 U8 flags = AU_FLAGS_NONE;
2752 if (gAgent.isGroupTitleHidden())
2753 {
2754 flags |= AU_FLAGS_HIDETITLE;
2755 }
2756
2757 flag_change = last_flags ^ flags;
2758
2759 head_rot_chg = dot(last_head_rot, head_rotation);
2760
2761 if (force_send ||
2762 (cam_center_chg.magVec() > TRANSLATE_THRESHOLD) ||
2763 (head_rot_chg < THRESHOLD_HEAD_ROT_QDOT) ||
2764 (last_render_state != render_state) ||
2765 (cam_rot_chg.magVec() > ROTATION_THRESHOLD) ||
2766 control_flag_change != 0 ||
2767 flag_change != 0)
2768 {
2769/*
2770 if (head_rot_chg < THRESHOLD_HEAD_ROT_QDOT)
2771 {
2772 //llinfos << "head rot " << head_rotation << llendl;
2773 llinfos << "head_rot_chg = " << head_rot_chg << llendl;
2774 }
2775 if (cam_rot_chg.magVec() > ROTATION_THRESHOLD)
2776 {
2777 llinfos << "cam rot " << cam_rot_chg.magVec() << llendl;
2778 }
2779 if (cam_center_chg.magVec() > TRANSLATE_THRESHOLD)
2780 {
2781 llinfos << "cam center " << cam_center_chg.magVec() << llendl;
2782 }
2783// if (drag_delta_chg.magVec() > TRANSLATE_THRESHOLD)
2784// {
2785// llinfos << "drag delta " << drag_delta_chg.magVec() << llendl;
2786// }
2787 if (control_flag_change)
2788 {
2789 llinfos << "dcf = " << control_flag_change << llendl;
2790 }
2791*/
2792
2793 duplicate_count = 0;
2794 }
2795 else
2796 {
2797 duplicate_count++;
2798
2799 if (head_rot_chg < MAX_HEAD_ROT_QDOT && duplicate_count < AGENT_UPDATES_PER_SECOND)
2800 {
2801 // The head_rotation is sent for updating things like attached guns.
2802 // We only trigger a new update when head_rotation deviates beyond
2803 // some threshold from the last update, however this can break fine
2804 // adjustments when trying to aim an attached gun, so what we do here
2805 // (where we would normally skip sending an update when nothing has changed)
2806 // is gradually reduce the threshold to allow a better update to
2807 // eventually get sent... should update to within 0.5 degrees in less
2808 // than a second.
2809 if (head_rot_chg < THRESHOLD_HEAD_ROT_QDOT + (MAX_HEAD_ROT_QDOT - THRESHOLD_HEAD_ROT_QDOT) * duplicate_count / AGENT_UPDATES_PER_SECOND)
2810 {
2811 duplicate_count = 0;
2812 }
2813 else
2814 {
2815 return;
2816 }
2817 }
2818 else
2819 {
2820 return;
2821 }
2822 }
2823
2824 if (duplicate_count < DUP_MSGS && !gDisconnected)
2825 {
2826 // Build the message
2827 msg->newMessageFast(_PREHASH_AgentUpdate);
2828 msg->nextBlockFast(_PREHASH_AgentData);
2829 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
2830 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
2831 msg->addQuatFast(_PREHASH_BodyRotation, body_rotation);
2832 msg->addQuatFast(_PREHASH_HeadRotation, head_rotation);
2833 msg->addU8Fast(_PREHASH_State, render_state);
2834 msg->addU8Fast(_PREHASH_Flags, flags);
2835
2836// if (camera_pos_agent.mV[VY] > 255.f)
2837// {
2838// llinfos << "Sending camera center " << camera_pos_agent << llendl;
2839// }
2840
2841 msg->addVector3Fast(_PREHASH_CameraCenter, camera_pos_agent);
2842 msg->addVector3Fast(_PREHASH_CameraAtAxis, gCamera->getAtAxis());
2843 msg->addVector3Fast(_PREHASH_CameraLeftAxis, gCamera->getLeftAxis());
2844 msg->addVector3Fast(_PREHASH_CameraUpAxis, gCamera->getUpAxis());
2845 msg->addF32Fast(_PREHASH_Far, gAgent.mDrawDistance);
2846
2847 msg->addU32Fast(_PREHASH_ControlFlags, control_flags);
2848
2849 if (gDebugClicks)
2850 {
2851 if (control_flags & AGENT_CONTROL_LBUTTON_DOWN)
2852 {
2853 llinfos << "AgentUpdate left button down" << llendl;
2854 }
2855
2856 if (control_flags & AGENT_CONTROL_LBUTTON_UP)
2857 {
2858 llinfos << "AgentUpdate left button up" << llendl;
2859 }
2860 }
2861
2862 gAgent.enableControlFlagReset();
2863
2864 if (!send_reliable)
2865 {
2866 gAgent.sendMessage();
2867 }
2868 else
2869 {
2870 gAgent.sendReliableMessage();
2871 }
2872
2873 //llinfos << "agent " << avatar_pos_agent << " cam " << camera_pos_agent << llendl;
2874
2875 // Copy the old data
2876 last_head_rot = head_rotation;
2877 last_render_state = render_state;
2878 last_camera_pos_agent = camera_pos_agent;
2879 last_camera_at = gCamera->getAtAxis();
2880 last_camera_left = gCamera->getLeftAxis();
2881 last_camera_up = gCamera->getUpAxis();
2882 last_control_flags = control_flags;
2883 last_flags = flags;
2884 }
2885}
2886
2887
2888
2889// *TODO: Remove this dependency, or figure out a better way to handle
2890// this hack.
2891extern U32 gObjectBits;
2892
2893void process_object_update(LLMessageSystem *mesgsys, void **user_data)
2894{
2895 // Update the data counters
2896 if (mesgsys->getReceiveCompressedSize())
2897 {
2898 gObjectBits += mesgsys->getReceiveCompressedSize() * 8;
2899 }
2900 else
2901 {
2902 gObjectBits += mesgsys->getReceiveSize() * 8;
2903 }
2904
2905 // Update the object...
2906 gObjectList.processObjectUpdate(mesgsys, user_data, OUT_FULL);
2907 stop_glerror();
2908}
2909
2910void process_compressed_object_update(LLMessageSystem *mesgsys, void **user_data)
2911{
2912 // Update the data counters
2913 if (mesgsys->getReceiveCompressedSize())
2914 {
2915 gObjectBits += mesgsys->getReceiveCompressedSize() * 8;
2916 }
2917 else
2918 {
2919 gObjectBits += mesgsys->getReceiveSize() * 8;
2920 }
2921
2922 // Update the object...
2923 gObjectList.processCompressedObjectUpdate(mesgsys, user_data, OUT_FULL_COMPRESSED);
2924 stop_glerror();
2925}
2926
2927void process_cached_object_update(LLMessageSystem *mesgsys, void **user_data)
2928{
2929 // Update the data counters
2930 if (mesgsys->getReceiveCompressedSize())
2931 {
2932 gObjectBits += mesgsys->getReceiveCompressedSize() * 8;
2933 }
2934 else
2935 {
2936 gObjectBits += mesgsys->getReceiveSize() * 8;
2937 }
2938
2939 // Update the object...
2940 gObjectList.processCachedObjectUpdate(mesgsys, user_data, OUT_FULL_CACHED);
2941 stop_glerror();
2942}
2943
2944
2945void process_terse_object_update_improved(LLMessageSystem *mesgsys, void **user_data)
2946{
2947 if (mesgsys->getReceiveCompressedSize())
2948 {
2949 gObjectBits += mesgsys->getReceiveCompressedSize() * 8;
2950 }
2951 else
2952 {
2953 gObjectBits += mesgsys->getReceiveSize() * 8;
2954 }
2955
2956 gObjectList.processCompressedObjectUpdate(mesgsys, user_data, OUT_TERSE_IMPROVED);
2957}
2958
2959
2960
2961void process_kill_object(LLMessageSystem *mesgsys, void **user_data)
2962{
2963 LLFastTimer t(LLFastTimer::FTM_PROCESS_OBJECTS);
2964
2965 LLUUID id;
2966 U32 local_id;
2967 S32 i;
2968 S32 num_objects;
2969
2970 num_objects = mesgsys->getNumberOfBlocksFast(_PREHASH_ObjectData);
2971
2972 for (i = 0; i < num_objects; i++)
2973 {
2974 mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i);
2975
2976 LLViewerObjectList::getUUIDFromLocal(id,
2977 local_id,
2978 gMessageSystem->getSenderIP(),
2979 gMessageSystem->getSenderPort());
2980 if (id == LLUUID::null)
2981 {
2982 //llinfos << "Unknown kill for local " << local_id << llendl;
2983 gObjectList.mNumUnknownKills++;
2984 continue;
2985 }
2986 else
2987 {
2988 //llinfos << "Kill message for local " << local_id << llendl;
2989 }
2990
2991 gSelectMgr->selectionRemoveObject(id);
2992
2993 // ...don't kill the avatar
2994 if (!(id == gAgentID))
2995 {
2996 LLViewerObject *objectp = gObjectList.findObject(id);
2997 if (objectp)
2998 {
2999 // Display green bubble on kill
3000 if ( gShowObjectUpdates )
3001 {
3002 LLViewerObject* newobject;
3003 newobject = gObjectList.createObjectViewer(LL_PCODE_LEGACY_TEXT_BUBBLE, objectp->getRegion());
3004
3005 LLVOTextBubble* bubble = (LLVOTextBubble*) newobject;
3006
3007 bubble->mColor.setVec(0.f, 1.f, 0.f, 1.f);
3008 bubble->setScale( 2.0f * bubble->getScale() );
3009 bubble->setPositionGlobal(objectp->getPositionGlobal());
3010 gPipeline.addObject(bubble);
3011 }
3012
3013 // Do the kill
3014 gObjectList.killObject(objectp);
3015 }
3016 else
3017 {
3018 llwarns << "Object in UUID lookup, but not on object list in kill!" << llendl;
3019 gObjectList.mNumUnknownKills++;
3020 }
3021 }
3022 }
3023}
3024
3025void process_time_synch(LLMessageSystem *mesgsys, void **user_data)
3026{
3027 LLVector3 sun_direction;
3028 LLVector3 sun_ang_velocity;
3029 F32 phase;
3030 U64 space_time_usec;
3031
3032 // "SimulatorViewerTimeMessage"
3033 mesgsys->getU64Fast(_PREHASH_TimeInfo, _PREHASH_UsecSinceStart, space_time_usec);
3034 mesgsys->getU32Fast(_PREHASH_TimeInfo, _PREHASH_SecPerDay, gSecondsPerDay);
3035 mesgsys->getU32Fast(_PREHASH_TimeInfo, _PREHASH_SecPerYear, gSecondsPerYear);
3036
3037 // This should eventually be moved to an "UpdateHeavenlyBodies" message
3038 mesgsys->getF32Fast(_PREHASH_TimeInfo, _PREHASH_SunPhase, phase);
3039 mesgsys->getVector3Fast(_PREHASH_TimeInfo, _PREHASH_SunDirection, sun_direction);
3040 mesgsys->getVector3Fast(_PREHASH_TimeInfo, _PREHASH_SunAngVelocity, sun_ang_velocity);
3041
3042 gWorldp->setSpaceTimeUSec(space_time_usec);
3043
3044 //lldebugs << "time_synch() - " << sun_direction << ", " << sun_ang_velocity
3045 // << ", " << phase << llendl;
3046
3047 gSky.setSunPhase(phase);
3048 gSky.setSunTargetDirection(sun_direction, sun_ang_velocity);
3049 if (!gNoRender && !(gSavedSettings.getBOOL("SkyOverrideSimSunPosition") || gSky.getOverrideSun()))
3050 {
3051 gSky.setSunDirection(sun_direction, sun_ang_velocity);
3052 }
3053}
3054
3055void process_sound_trigger(LLMessageSystem *msg, void **)
3056{
3057 if (!gAudiop) return;
3058 if (!gParcelMgr) return;
3059 if (!gMuteListp) return;
3060
3061 U64 region_handle = 0;
3062 F32 gain = 0;
3063 LLUUID sound_id;
3064 LLUUID owner_id;
3065 LLUUID object_id;
3066 LLUUID parent_id;
3067 LLVector3 pos_local;
3068
3069 msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_SoundID, sound_id);
3070 msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_OwnerID, owner_id);
3071 msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_ObjectID, object_id);
3072 msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_ParentID, parent_id);
3073 msg->getU64Fast(_PREHASH_SoundData, _PREHASH_Handle, region_handle);
3074 msg->getVector3Fast(_PREHASH_SoundData, _PREHASH_Position, pos_local);
3075 msg->getF32Fast(_PREHASH_SoundData, _PREHASH_Gain, gain);
3076
3077 // adjust sound location to true global coords
3078 LLVector3d pos_global = from_region_handle(region_handle);
3079 pos_global.mdV[VX] += pos_local.mV[VX];
3080 pos_global.mdV[VY] += pos_local.mV[VY];
3081 pos_global.mdV[VZ] += pos_local.mV[VZ];
3082
3083 // Don't play a trigger sound if you can't hear it due
3084 // to parcel "local audio only" settings.
3085 if (!gParcelMgr->canHearSound(pos_global)) return;
3086
3087 // Don't play sounds triggered by someone you muted.
3088 if (gMuteListp->isMuted(owner_id)) return;
3089
3090 // Don't play sounds from an object you muted
3091 if (gMuteListp->isMuted(object_id)) return;
3092
3093 // Don't play sounds from an object whose parent you muted
3094 if (parent_id.notNull()
3095 && gMuteListp->isMuted(parent_id))
3096 {
3097 return;
3098 }
3099
3100 gAudiop->triggerSound(sound_id, owner_id, gain, pos_global);
3101}
3102
3103void process_preload_sound(LLMessageSystem *msg, void **user_data)
3104{
3105 if (!gAudiop)
3106 {
3107 return;
3108 }
3109
3110 LLUUID sound_id;
3111 LLUUID object_id;
3112 LLUUID owner_id;
3113
3114 msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_SoundID, sound_id);
3115 msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_ObjectID, object_id);
3116 msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_OwnerID, owner_id);
3117
3118 LLViewerObject *objectp = gObjectList.findObject(object_id);
3119 if (!objectp) return;
3120
3121 if (gMuteListp->isMuted(object_id)) return;
3122 if (gMuteListp->isMuted(owner_id)) return;
3123
3124 LLAudioSource *sourcep = objectp->getAudioSource(owner_id);
3125 if (!sourcep) return;
3126
3127 LLAudioData *datap = gAudiop->getAudioData(sound_id);
3128
3129 // Note that I don't actually do any loading of the
3130 // audio data into a buffer at this point, as it won't actually
3131 // help us out.
3132
3133 // Add audioData starts a transfer internally.
3134 sourcep->addAudioData(datap, FALSE);
3135}
3136
3137void process_attached_sound(LLMessageSystem *msg, void **user_data)
3138{
3139 F32 gain = 0;
3140 LLUUID sound_id;
3141 LLUUID object_id;
3142 LLUUID owner_id;
3143 U8 flags;
3144
3145 msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_SoundID, sound_id);
3146 msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_ObjectID, object_id);
3147 msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_OwnerID, owner_id);
3148 msg->getF32Fast(_PREHASH_DataBlock, _PREHASH_Gain, gain);
3149 msg->getU8Fast(_PREHASH_DataBlock, _PREHASH_Flags, flags);
3150
3151 LLViewerObject *objectp = gObjectList.findObject(object_id);
3152 if (!objectp)
3153 {
3154 // we don't know about this object, just bail
3155 return;
3156 }
3157
3158 if (gMuteListp->isMuted(object_id)) return;
3159
3160 if (gMuteListp->isMuted(owner_id)) return;
3161
3162 objectp->setAttachedSound(sound_id, owner_id, gain, flags);
3163}
3164
3165
3166void process_attached_sound_gain_change(LLMessageSystem *mesgsys, void **user_data)
3167{
3168 F32 gain = 0;
3169 LLUUID object_guid;
3170 LLViewerObject *objectp = NULL;
3171
3172 mesgsys->getUUIDFast(_PREHASH_DataBlock, _PREHASH_ObjectID, object_guid);
3173
3174 if (!((objectp = gObjectList.findObject(object_guid))))
3175 {
3176 // we don't know about this object, just bail
3177 return;
3178 }
3179
3180 mesgsys->getF32Fast(_PREHASH_DataBlock, _PREHASH_Gain, gain);
3181
3182 objectp->adjustAudioGain(gain);
3183}
3184
3185/* Unused July 2006
3186void process_attached_sound_cutoff_radius(LLMessageSystem *mesgsys, void **user_data)
3187{
3188 F32 radius = 0;
3189 LLUUID object_guid;
3190 LLViewerObject *objectp = NULL;
3191
3192 mesgsys->getUUIDFast(_PREHASH_DataBlock, _PREHASH_ObjectID, object_guid);
3193
3194 if (!((objectp = gObjectList.findObject(object_guid))))
3195 {
3196 // we don't know about this object, just bail
3197 return;
3198 }
3199
3200 mesgsys->getF32Fast(_PREHASH_DataBlock, _PREHASH_Radius, radius);
3201
3202 if (gAudiop)
3203 {
3204// gAudiop->attachToObject(sound_guid, object_guid, gain, priority, flags);
3205 }
3206}
3207*/
3208
3209void process_health_message(LLMessageSystem *mesgsys, void **user_data)
3210{
3211 F32 health;
3212
3213 mesgsys->getF32Fast(_PREHASH_HealthData, _PREHASH_Health, health);
3214
3215 if (gStatusBar)
3216 {
3217 gStatusBar->setHealth((S32)health);
3218 }
3219}
3220
3221
3222void process_sim_stats(LLMessageSystem *msg, void **user_data)
3223{
3224 S32 count = msg->getNumberOfBlocks("Stat");
3225 for (S32 i = 0; i < count; ++i)
3226 {
3227 U32 stat_id;
3228 F32 stat_value;
3229 msg->getU32("Stat", "StatID", stat_id, i);
3230 msg->getF32("Stat", "StatValue", stat_value, i);
3231 switch (stat_id)
3232 {
3233 case LL_SIM_STAT_TIME_DILATION:
3234 gViewerStats->mSimTimeDilation.addValue(stat_value);
3235 break;
3236 case LL_SIM_STAT_FPS:
3237 gViewerStats->mSimFPS.addValue(stat_value);
3238 break;
3239 case LL_SIM_STAT_PHYSFPS:
3240 gViewerStats->mSimPhysicsFPS.addValue(stat_value);
3241 break;
3242 case LL_SIM_STAT_AGENTUPS:
3243 gViewerStats->mSimAgentUPS.addValue(stat_value);
3244 break;
3245 case LL_SIM_STAT_FRAMEMS:
3246 gViewerStats->mSimFrameMsec.addValue(stat_value);
3247 break;
3248 case LL_SIM_STAT_NETMS:
3249 gViewerStats->mSimNetMsec.addValue(stat_value);
3250 break;
3251 case LL_SIM_STAT_SIMOTHERMS:
3252 gViewerStats->mSimSimOtherMsec.addValue(stat_value);
3253 break;
3254 case LL_SIM_STAT_SIMPHYSICSMS:
3255 gViewerStats->mSimSimPhysicsMsec.addValue(stat_value);
3256 break;
3257 case LL_SIM_STAT_AGENTMS:
3258 gViewerStats->mSimAgentMsec.addValue(stat_value);
3259 break;
3260 case LL_SIM_STAT_IMAGESMS:
3261 gViewerStats->mSimImagesMsec.addValue(stat_value);
3262 break;
3263 case LL_SIM_STAT_SCRIPTMS:
3264 gViewerStats->mSimScriptMsec.addValue(stat_value);
3265 break;
3266 case LL_SIM_STAT_NUMTASKS:
3267 gViewerStats->mSimObjects.addValue(stat_value);
3268 break;
3269 case LL_SIM_STAT_NUMTASKSACTIVE:
3270 gViewerStats->mSimActiveObjects.addValue(stat_value);
3271 break;
3272 case LL_SIM_STAT_NUMAGENTMAIN:
3273 gViewerStats->mSimMainAgents.addValue(stat_value);
3274 break;
3275 case LL_SIM_STAT_NUMAGENTCHILD:
3276 gViewerStats->mSimChildAgents.addValue(stat_value);
3277 break;
3278 case LL_SIM_STAT_NUMSCRIPTSACTIVE:
3279 gViewerStats->mSimActiveScripts.addValue(stat_value);
3280 break;
3281 case LL_SIM_STAT_LSLIPS:
3282 gViewerStats->mSimLSLIPS.addValue(stat_value);
3283 break;
3284 case LL_SIM_STAT_INPPS:
3285 gViewerStats->mSimInPPS.addValue(stat_value);
3286 break;
3287 case LL_SIM_STAT_OUTPPS:
3288 gViewerStats->mSimOutPPS.addValue(stat_value);
3289 break;
3290 case LL_SIM_STAT_PENDING_DOWNLOADS:
3291 gViewerStats->mSimPendingDownloads.addValue(stat_value);
3292 break;
3293 case LL_SIM_STAT_PENDING_UPLOADS:
3294 gViewerStats->mSimPendingUploads.addValue(stat_value);
3295 break;
3296 case LL_SIM_STAT_PENDING_LOCAL_UPLOADS:
3297 gViewerStats->mSimPendingLocalUploads.addValue(stat_value);
3298 break;
3299 case LL_SIM_STAT_TOTAL_UNACKED_BYTES:
3300 gViewerStats->mSimTotalUnackedBytes.addValue(stat_value / 1024.f);
3301 break;
3302 default:
3303 llwarns << "Unknown stat id" << stat_id << llendl;
3304 }
3305 }
3306
3307 /*
3308 msg->getF32Fast(_PREHASH_Statistics, _PREHASH_PhysicsTimeDilation, time_dilation);
3309 gViewerStats->mSimTDStat.addValue(time_dilation);
3310
3311 // Process information
3312 // { CpuUsage F32 }
3313 // { SimMemTotal F32 }
3314 // { SimMemRSS F32 }
3315 // { ProcessUptime F32 }
3316 F32 cpu_usage;
3317 F32 sim_mem_total;
3318 F32 sim_mem_rss;
3319 F32 process_uptime;
3320 msg->getF32Fast(_PREHASH_Statistics, _PREHASH_CpuUsage, cpu_usage);
3321 msg->getF32Fast(_PREHASH_Statistics, _PREHASH_SimMemTotal, sim_mem_total);
3322 msg->getF32Fast(_PREHASH_Statistics, _PREHASH_SimMemRSS, sim_mem_rss);
3323 msg->getF32Fast(_PREHASH_Statistics, _PREHASH_ProcessUptime, process_uptime);
3324 gViewerStats->mSimCPUUsageStat.addValue(cpu_usage);
3325 gViewerStats->mSimMemTotalStat.addValue(sim_mem_total);
3326 gViewerStats->mSimMemRSSStat.addValue(sim_mem_rss);
3327 */
3328
3329 //
3330 // Various hacks that aren't statistics, but are being handled here.
3331 //
3332 U32 max_tasks_per_region;
3333 U32 region_flags;
3334 msg->getU32("Region", "ObjectCapacity", max_tasks_per_region);
3335 msg->getU32("Region", "RegionFlags", region_flags);
3336
3337 LLViewerRegion* regionp = gAgent.getRegion();
3338 if (regionp)
3339 {
3340 BOOL was_flying = gAgent.getFlying();
3341 regionp->setRegionFlags(region_flags);
3342 regionp->setMaxTasks(max_tasks_per_region);
3343 // HACK: This makes agents drop from the sky if the region is
3344 // set to no fly while people are still in the sim.
3345 if (was_flying && regionp->getBlockFly())
3346 {
3347 gAgent.setFlying(gAgent.canFly());
3348 }
3349 }
3350}
3351
3352
3353// This info is requested by the simulator when the agent first logs in
3354// or when it moves into a simulator in which it did not already have
3355// a child agent.
3356void process_avatar_info_request(LLMessageSystem *mesgsys, void **user_data)
3357{
3358 llinfos << "process_avatar_info_request()" << llendl;
3359
3360 // Send the avatar appearance (parameters and texture entry UUIDs)
3361 gAgent.sendAgentSetAppearance();
3362 send_agent_update(TRUE, TRUE);
3363}
3364
3365
3366void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data)
3367{
3368 LLUUID animation_id;
3369 LLUUID uuid;
3370 S32 anim_sequence_id;
3371 LLVOAvatar *avatarp;
3372
3373 mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid);
3374
3375 //clear animation flags
3376 avatarp = (LLVOAvatar *)gObjectList.findObject(uuid);
3377
3378 if (!avatarp)
3379 {
3380 // no agent by this ID...error?
3381 llwarns << "Received animation state for unknown avatar" << uuid << llendl;
3382 return;
3383 }
3384
3385 S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationList);
3386 S32 num_source_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationSourceList);
3387
3388 avatarp->mSignaledAnimations.clear();
3389
3390 if (avatarp->mIsSelf)
3391 {
3392 LLUUID object_id;
3393
3394 for( S32 i = 0; i < num_blocks; i++ )
3395 {
3396 mesgsys->getUUIDFast(_PREHASH_AnimationList, _PREHASH_AnimID, animation_id, i);
3397 mesgsys->getS32Fast(_PREHASH_AnimationList, _PREHASH_AnimSequenceID, anim_sequence_id, i);
3398
3399 //llinfos << "Anim sequence ID: " << anim_sequence_id << llendl;
3400
3401 avatarp->mSignaledAnimations[animation_id] = anim_sequence_id;
3402
3403 if (i < num_source_blocks)
3404 {
3405 mesgsys->getUUIDFast(_PREHASH_AnimationSourceList, _PREHASH_ObjectID, object_id, i);
3406
3407 LLViewerObject* object = gObjectList.findObject(object_id);
3408 if (object)
3409 {
3410 object->mFlags |= FLAGS_ANIM_SOURCE;
3411
3412 BOOL anim_found = FALSE;
3413 LLVOAvatar::AnimSourceIterator anim_it = avatarp->mAnimationSources.find(object_id);
3414 for (;anim_it != avatarp->mAnimationSources.end(); ++anim_it)
3415 {
3416 if (anim_it->second == animation_id)
3417 {
3418 anim_found = TRUE;
3419 break;
3420 }
3421 }
3422
3423 if (!anim_found)
3424 {
3425 avatarp->mAnimationSources.insert(LLVOAvatar::AnimationSourceMap::value_type(object_id, animation_id));
3426 }
3427 }
3428 }
3429 }
3430 }
3431 else
3432 {
3433 for( S32 i = 0; i < num_blocks; i++ )
3434 {
3435 mesgsys->getUUIDFast(_PREHASH_AnimationList, _PREHASH_AnimID, animation_id, i);
3436 mesgsys->getS32Fast(_PREHASH_AnimationList, _PREHASH_AnimSequenceID, anim_sequence_id, i);
3437 avatarp->mSignaledAnimations[animation_id] = anim_sequence_id;
3438 }
3439 }
3440
3441 if (num_blocks)
3442 {
3443 avatarp->processAnimationStateChanges();
3444 }
3445}
3446
3447void process_avatar_appearance(LLMessageSystem *mesgsys, void **user_data)
3448{
3449 LLUUID uuid;
3450 mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid);
3451
3452 LLVOAvatar* avatarp = (LLVOAvatar *)gObjectList.findObject(uuid);
3453 if( avatarp )
3454 {
3455 avatarp->processAvatarAppearance( mesgsys );
3456 }
3457 else
3458 {
3459 llwarns << "avatar_appearance sent for unknown avatar " << uuid << llendl;
3460 }
3461}
3462
3463void process_camera_constraint(LLMessageSystem *mesgsys, void **user_data)
3464{
3465 LLVector4 cameraCollidePlane;
3466 mesgsys->getVector4Fast(_PREHASH_CameraCollidePlane, _PREHASH_Plane, cameraCollidePlane);
3467
3468 gAgent.setCameraCollidePlane(cameraCollidePlane);
3469}
3470
3471void near_sit_object(BOOL success, void *data)
3472{
3473 // Send message to sit on object
3474 gMessageSystem->newMessageFast(_PREHASH_AgentSit);
3475 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
3476 gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
3477 gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
3478 gAgent.sendReliableMessage();
3479}
3480
3481void process_avatar_sit_response(LLMessageSystem *mesgsys, void **user_data)
3482{
3483 LLVector3 sitPosition;
3484 LLQuaternion sitRotation;
3485 LLUUID sitObjectID;
3486 BOOL use_autopilot;
3487 mesgsys->getUUIDFast(_PREHASH_SitObject, _PREHASH_ID, sitObjectID);
3488 mesgsys->getBOOLFast(_PREHASH_SitTransform, _PREHASH_AutoPilot, use_autopilot);
3489 mesgsys->getVector3Fast(_PREHASH_SitTransform, _PREHASH_SitPosition, sitPosition);
3490 mesgsys->getQuatFast(_PREHASH_SitTransform, _PREHASH_SitRotation, sitRotation);
3491 LLVector3 camera_eye;
3492 mesgsys->getVector3Fast(_PREHASH_SitTransform, _PREHASH_CameraEyeOffset, camera_eye);
3493 LLVector3 camera_at;
3494 mesgsys->getVector3Fast(_PREHASH_SitTransform, _PREHASH_CameraAtOffset, camera_at);
3495 BOOL force_mouselook;
3496 mesgsys->getBOOLFast(_PREHASH_SitTransform, _PREHASH_ForceMouselook, force_mouselook);
3497
3498 LLVOAvatar* avatar = gAgent.getAvatarObject();
3499
3500 if (avatar && dist_vec_squared(camera_eye, camera_at) > 0.0001f)
3501 {
3502 gAgent.setSitCamera(sitObjectID, camera_eye, camera_at);
3503 }
3504
3505 gAgent.mForceMouselook = force_mouselook;
3506
3507 LLViewerObject* object = gObjectList.findObject(sitObjectID);
3508 if (object)
3509 {
3510 LLVector3 sit_spot = object->getPositionAgent() + (sitPosition * object->getRotation());
3511 if (!use_autopilot || (avatar->mIsSitting && avatar->getRoot() == object->getRoot()))
3512 {
3513 //we're already sitting on this object, so don't autopilot
3514 }
3515 else
3516 {
3517 gAgent.startAutoPilotGlobal(gAgent.getPosGlobalFromAgent(sit_spot), "Sit", &sitRotation, near_sit_object, NULL, 0.5f);
3518 }
3519
3520 // deselect transient selections (pie menu) when sitting
3521 gSelectMgr->deselectTransient();
3522 }
3523 else
3524 {
3525 llwarns << "Received sit approval for unknown object " << sitObjectID << llendl;
3526 }
3527}
3528
3529void process_clear_follow_cam_properties(LLMessageSystem *mesgsys, void **user_data)
3530{
3531 LLUUID source_id;
3532
3533 mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_ObjectID, source_id);
3534
3535 LLFollowCamMgr::removeFollowCamParams(source_id);
3536}
3537
3538void process_set_follow_cam_properties(LLMessageSystem *mesgsys, void **user_data)
3539{
3540 S32 type;
3541 F32 value;
3542 bool settingPosition = false;
3543 bool settingFocus = false;
3544 bool settingFocusOffset = false;
3545 LLVector3 position;
3546 LLVector3 focus;
3547 LLVector3 focus_offset;
3548
3549 LLUUID source_id;
3550
3551 mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_ObjectID, source_id);
3552
3553 LLViewerObject* objectp = gObjectList.findObject(source_id);
3554 if (objectp)
3555 {
3556 objectp->mFlags |= FLAGS_CAMERA_SOURCE;
3557 }
3558
3559 S32 num_objects = mesgsys->getNumberOfBlocks("CameraProperty");
3560 for (S32 block_index = 0; block_index < num_objects; block_index++)
3561 {
3562 mesgsys->getS32("CameraProperty", "Type", type, block_index);
3563 mesgsys->getF32("CameraProperty", "Value", value, block_index);
3564 switch(type)
3565 {
3566 case FOLLOWCAM_PITCH:
3567 LLFollowCamMgr::setPitch(source_id, value);
3568 break;
3569 case FOLLOWCAM_FOCUS_OFFSET_X:
3570 focus_offset.mV[VX] = value;
3571 settingFocusOffset = true;
3572 break;
3573 case FOLLOWCAM_FOCUS_OFFSET_Y:
3574 focus_offset.mV[VY] = value;
3575 settingFocusOffset = true;
3576 break;
3577 case FOLLOWCAM_FOCUS_OFFSET_Z:
3578 focus_offset.mV[VZ] = value;
3579 settingFocusOffset = true;
3580 break;
3581 case FOLLOWCAM_POSITION_LAG:
3582 LLFollowCamMgr::setPositionLag(source_id, value);
3583 break;
3584 case FOLLOWCAM_FOCUS_LAG:
3585 LLFollowCamMgr::setFocusLag(source_id, value);
3586 break;
3587 case FOLLOWCAM_DISTANCE:
3588 LLFollowCamMgr::setDistance(source_id, value);
3589 break;
3590 case FOLLOWCAM_BEHINDNESS_ANGLE:
3591 LLFollowCamMgr::setBehindnessAngle(source_id, value);
3592 break;
3593 case FOLLOWCAM_BEHINDNESS_LAG:
3594 LLFollowCamMgr::setBehindnessLag(source_id, value);
3595 break;
3596 case FOLLOWCAM_POSITION_THRESHOLD:
3597 LLFollowCamMgr::setPositionThreshold(source_id, value);
3598 break;
3599 case FOLLOWCAM_FOCUS_THRESHOLD:
3600 LLFollowCamMgr::setFocusThreshold(source_id, value);
3601 break;
3602 case FOLLOWCAM_ACTIVE:
3603 //if 1, set using followcam,.
3604 LLFollowCamMgr::setCameraActive(source_id, value != 0.f);
3605 break;
3606 case FOLLOWCAM_POSITION_X:
3607 settingPosition = true;
3608 position.mV[ 0 ] = value;
3609 break;
3610 case FOLLOWCAM_POSITION_Y:
3611 settingPosition = true;
3612 position.mV[ 1 ] = value;
3613 break;
3614 case FOLLOWCAM_POSITION_Z:
3615 settingPosition = true;
3616 position.mV[ 2 ] = value;
3617 break;
3618 case FOLLOWCAM_FOCUS_X:
3619 settingFocus = true;
3620 focus.mV[ 0 ] = value;
3621 break;
3622 case FOLLOWCAM_FOCUS_Y:
3623 settingFocus = true;
3624 focus.mV[ 1 ] = value;
3625 break;
3626 case FOLLOWCAM_FOCUS_Z:
3627 settingFocus = true;
3628 focus.mV[ 2 ] = value;
3629 break;
3630 case FOLLOWCAM_POSITION_LOCKED:
3631 LLFollowCamMgr::setPositionLocked(source_id, value != 0.f);
3632 break;
3633 case FOLLOWCAM_FOCUS_LOCKED:
3634 LLFollowCamMgr::setFocusLocked(source_id, value != 0.f);
3635 break;
3636
3637 default:
3638 break;
3639 }
3640 }
3641
3642 if ( settingPosition )
3643 {
3644 LLFollowCamMgr::setPosition(source_id, position);
3645 }
3646 if ( settingFocus )
3647 {
3648 LLFollowCamMgr::setFocus(source_id, focus);
3649 }
3650 if ( settingFocusOffset )
3651 {
3652 LLFollowCamMgr::setFocusOffset(source_id, focus_offset);
3653 }
3654}
3655//end Ventrella
3656
3657
3658// Culled from newsim lltask.cpp
3659void process_name_value(LLMessageSystem *mesgsys, void **user_data)
3660{
3661 char temp_str[NAME_VALUE_BUF_SIZE];
3662 LLUUID id;
3663 S32 i, num_blocks;
3664
3665 mesgsys->getUUIDFast(_PREHASH_TaskData, _PREHASH_ID, id);
3666
3667 LLViewerObject* object = gObjectList.findObject(id);
3668
3669 if (object)
3670 {
3671 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_NameValueData);
3672 for (i = 0; i < num_blocks; i++)
3673 {
3674 mesgsys->getStringFast(_PREHASH_NameValueData, _PREHASH_NVPair, NAME_VALUE_BUF_SIZE, temp_str, i);
3675 llinfos << "Added to object Name Value: " << temp_str << llendl;
3676 object->addNVPair(temp_str);
3677 }
3678 }
3679 else
3680 {
3681 llinfos << "Can't find object " << id << " to add name value pair" << llendl;
3682 }
3683}
3684
3685void process_remove_name_value(LLMessageSystem *mesgsys, void **user_data)
3686{
3687 char temp_str[NAME_VALUE_BUF_SIZE];
3688 LLUUID id;
3689 S32 i, num_blocks;
3690
3691 mesgsys->getUUIDFast(_PREHASH_TaskData, _PREHASH_ID, id);
3692
3693 LLViewerObject* object = gObjectList.findObject(id);
3694
3695 if (object)
3696 {
3697 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_NameValueData);
3698 for (i = 0; i < num_blocks; i++)
3699 {
3700 mesgsys->getStringFast(_PREHASH_NameValueData, _PREHASH_NVPair, NAME_VALUE_BUF_SIZE, temp_str, i);
3701 llinfos << "Removed from object Name Value: " << temp_str << llendl;
3702 object->removeNVPair(temp_str);
3703 }
3704 }
3705 else
3706 {
3707 llinfos << "Can't find object " << id << " to remove name value pair" << llendl;
3708 }
3709}
3710
3711void process_kick_user(LLMessageSystem *msg, void** /*user_data*/)
3712{
3713 char message[2048];
3714 message[0] = '\0';
3715
3716 msg->getStringFast(_PREHASH_UserInfo, _PREHASH_Reason, 2048, message);
3717
3718 do_disconnect(message);
3719}
3720
3721
3722/*
3723void process_user_list_reply(LLMessageSystem *msg, void **user_data)
3724{
3725 LLUserList::processUserListReply(msg, user_data);
3726 return;
3727 char firstname[MAX_STRING+1];
3728 char lastname[MAX_STRING+1];
3729 U8 status;
3730 S32 user_count;
3731
3732 user_count = msg->getNumberOfBlocks("UserBlock");
3733
3734 for (S32 i = 0; i < user_count; i++)
3735 {
3736 msg->getData("UserBlock", i, "FirstName", firstname);
3737 msg->getData("UserBlock", i, "LastName", lastname);
3738 msg->getData("UserBlock", i, "Status", &status);
3739
3740 if (status & 0x01)
3741 {
3742 dialog_friends_add_friend(buffer, TRUE);
3743 }
3744 else
3745 {
3746 dialog_friends_add_friend(buffer, FALSE);
3747 }
3748 }
3749
3750 dialog_friends_done_adding();
3751}
3752*/
3753
3754// this is not handled in processUpdateMessage
3755/*
3756void process_time_dilation(LLMessageSystem *msg, void **user_data)
3757{
3758 // get the time_dilation
3759 U16 foo;
3760 msg->getData("TimeDilation", "TimeDilation", &foo);
3761 F32 time_dilation = ((F32) foo) / 65535.f;
3762
3763 // get the pointer to the right region
3764 U32 ip = msg->getSenderIP();
3765 U32 port = msg->getSenderPort();
3766 LLViewerRegion *regionp = gWorldp->getRegion(ip, port);
3767 if (regionp)
3768 {
3769 regionp->setTimeDilation(time_dilation);
3770 }
3771}
3772*/
3773
3774
3775
3776void process_money_balance_reply( LLMessageSystem* msg, void** )
3777{
3778 S32 balance = 0;
3779 S32 credit = 0;
3780 S32 committed = 0;
3781 char desc[STD_STRING_BUF_SIZE] = "";
3782
3783 msg->getS32("MoneyData", "MoneyBalance", balance);
3784 msg->getS32("MoneyData", "SquareMetersCredit", credit);
3785 msg->getS32("MoneyData", "SquareMetersCommitted", committed);
3786 msg->getStringFast(_PREHASH_MoneyData, _PREHASH_Description, STD_STRING_BUF_SIZE, desc);
3787 llinfos << "money, credit, committed: " << balance << " " << credit << " "
3788 << committed << llendl;
3789
3790 if (gStatusBar)
3791 {
3792 S32 old_balance = gStatusBar->getBalance();
3793
3794 // This is an update, not the first transmission of balance
3795 if (old_balance != 0)
3796 {
3797 // this is actually an update
3798 if (balance > old_balance)
3799 {
3800 LLFirstUse::useBalanceIncrease(balance - old_balance);
3801 }
3802 else if (balance < old_balance)
3803 {
3804 LLFirstUse::useBalanceDecrease(balance - old_balance);
3805 }
3806 }
3807
3808 gStatusBar->setBalance(balance);
3809 gStatusBar->setLandCredit(credit);
3810 gStatusBar->setLandCommitted(committed);
3811 }
3812
3813 LLUUID tid;
3814 msg->getUUID("MoneyData", "TransactionID", tid);
3815 static std::deque<LLUUID> recent;
3816 if(desc[0] && gSavedSettings.getBOOL("NotifyMoneyChange")
3817 && (std::find(recent.rbegin(), recent.rend(), tid) == recent.rend()))
3818 {
3819 // Make the user confirm the transaction, since they might
3820 // have missed something during an event.
3821 // XUI:translate
3822 LLString::format_map_t args;
3823 args["[MESSAGE]"] = desc;
3824 LLNotifyBox::showXml("SystemMessage", args);
3825
3826 // Once the 'recent' container gets large enough, chop some
3827 // off the beginning.
3828 const U32 MAX_LOOKBACK = 30;
3829 const S32 POP_FRONT_SIZE = 12;
3830 if(recent.size() > MAX_LOOKBACK)
3831 {
3832 lldebugs << "Removing oldest transaction records" << llendl;
3833 recent.erase(recent.begin(), recent.begin() + POP_FRONT_SIZE);
3834 }
3835 //lldebugs << "Pushing back transaction " << tid << llendl;
3836 recent.push_back(tid);
3837 }
3838}
3839
3840void process_agent_alert_message(LLMessageSystem* msgsystem, void** user_data)
3841{
3842 char buffer[MAX_STRING];
3843 msgsystem->getStringFast(_PREHASH_AlertData, _PREHASH_Message, MAX_STRING, buffer);
3844 BOOL modal = FALSE;
3845 msgsystem->getBOOL("AlertData", "Modal", modal);
3846 process_alert_core(buffer, modal);
3847}
3848
3849void process_alert_message(LLMessageSystem *msgsystem, void **user_data)
3850{
3851 char buffer[MAX_STRING];
3852 msgsystem->getStringFast(_PREHASH_AlertData, _PREHASH_Message, MAX_STRING, buffer);
3853 BOOL modal = FALSE;
3854 process_alert_core(buffer, modal);
3855}
3856
3857void process_alert_core(const char* buffer, BOOL modal)
3858{
3859 // make sure the cursor is back to the usual default since the
3860 // alert is probably due to some kind of error.
3861 gViewerWindow->getWindow()->resetBusyCount();
3862
3863 // HACK -- handle callbacks for specific alerts
3864 if( !strcmp( buffer, "You died and have been teleported to your home location" ) )
3865 {
3866 gViewerStats->incStat(LLViewerStats::ST_KILLED_COUNT);
3867 }
3868 else if( !strcmp( buffer, "Home position set." ) )
3869 {
3870 // save the home location image to disk
3871 char temp_str[LL_MAX_PATH];
3872 strcpy(temp_str, gDirUtilp->getLindenUserDir().c_str());
3873 strcat(temp_str, "/");
3874 strcat(temp_str,SCREEN_HOME_FILENAME);
3875 gViewerWindow->saveSnapshot(temp_str, gViewerWindow->getWindowWidth(), gViewerWindow->getWindowHeight(), FALSE, FALSE);
3876 }
3877
3878 // Translate system messages here.
3879 if (buffer[0] == '/')
3880 {
3881 // System message is important, show in upper-right box not tip
3882 LLString text(buffer+1);
3883 LLString::format_map_t args;
3884 if (text.substr(0,17) == "RESTART_X_MINUTES")
3885 {
3886 S32 mins = 0;
3887 LLString::convertToS32(text.substr(18), mins);
3888 args["[MINUTES]"] = llformat("%d",mins);
3889 LLNotifyBox::showXml("RegionRestartMinutes", args);
3890 }
3891 else if (text.substr(0,17) == "RESTART_X_SECONDS")
3892 {
3893 S32 secs = 0;
3894 LLString::convertToS32(text.substr(18), secs);
3895 args["[SECONDS]"] = llformat("%d",secs);
3896 LLNotifyBox::showXml("RegionRestartSeconds", args);
3897 }
3898 else
3899 {
3900 //XUI:translate
3901 args["[MESSAGE]"] = text;
3902 LLNotifyBox::showXml("SystemMessage", args);
3903 }
3904 }
3905 else if (modal)
3906 {
3907 //XUI:translate
3908 LLString::format_map_t args;
3909 args["[BUFFER]"] = buffer;
3910 gViewerWindow->alertXml("ErrorMessage", args);
3911 }
3912 else
3913 {
3914 //XUI:translate
3915 LLString::format_map_t args;
3916 args["[MESSAGE]"] = buffer;
3917 LLNotifyBox::showXml("SystemMessageTip", args);
3918 }
3919}
3920
3921LLLinkedList<LLMeanCollisionData> gMeanCollisionList;
3922time_t gLastDisplayedTime = 0;
3923
3924void handle_show_mean_events(void *)
3925{
3926 if (gNoRender)
3927 {
3928 return;
3929 }
3930
3931 LLFloaterBump::show(NULL);
3932}
3933
3934void mean_name_callback(const LLUUID &id, const char *first, const char *last, BOOL always_false, void* data)
3935{
3936 if (gNoRender)
3937 {
3938 return;
3939 }
3940
3941 while(gMeanCollisionList.getLength() > 20)
3942 {
3943 gMeanCollisionList.getLastData();
3944 gMeanCollisionList.deleteCurrentData();
3945 }
3946
3947 LLMeanCollisionData *mcd;
3948 for (mcd = gMeanCollisionList.getFirstData(); mcd; mcd = gMeanCollisionList.getNextData())
3949 {
3950 if (mcd->mPerp == id)
3951 {
3952 strcpy(mcd->mFirstName, first);
3953 strcpy(mcd->mLastName, last);
3954 }
3955 }
3956}
3957
3958void process_mean_collision_alert_message(LLMessageSystem *msgsystem, void **user_data)
3959{
3960 if (gAgent.inPrelude())
3961 {
3962 // JC: In prelude, bumping is OK. This dialog is rather confusing to
3963 // newbies, so we don't show it. Drop the packet on the floor.
3964 return;
3965 }
3966
3967 // make sure the cursor is back to the usual default since the
3968 // alert is probably due to some kind of error.
3969 gViewerWindow->getWindow()->resetBusyCount();
3970
3971 LLUUID perp;
3972 U32 time;
3973 U8 u8type;
3974 EMeanCollisionType type;
3975 F32 mag;
3976
3977 S32 i, num = msgsystem->getNumberOfBlocks(_PREHASH_MeanCollision);
3978
3979 for (i = 0; i < num; i++)
3980 {
3981 msgsystem->getUUIDFast(_PREHASH_MeanCollision, _PREHASH_Perp, perp);
3982 msgsystem->getU32Fast(_PREHASH_MeanCollision, _PREHASH_Time, time);
3983 msgsystem->getF32Fast(_PREHASH_MeanCollision, _PREHASH_Mag, mag);
3984 msgsystem->getU8Fast(_PREHASH_MeanCollision, _PREHASH_Type, u8type);
3985
3986 type = (EMeanCollisionType)u8type;
3987
3988 LLMeanCollisionData *mcd;
3989
3990 BOOL b_found = FALSE;
3991
3992 for (mcd = gMeanCollisionList.getFirstData(); mcd; mcd = gMeanCollisionList.getNextData())
3993 {
3994 if ((mcd->mPerp == perp) && (mcd->mType == type))
3995 {
3996 mcd->mTime = time;
3997 mcd->mMag = mag;
3998 b_found = TRUE;
3999 break;
4000 }
4001 }
4002
4003 if (!b_found)
4004 {
4005 LLMeanCollisionData *mcd = new LLMeanCollisionData(gAgentID, perp, time, type, mag);
4006 gMeanCollisionList.addData(mcd);
4007 const BOOL is_group = FALSE;
4008 gCacheName->get(perp, is_group, mean_name_callback);
4009 }
4010 }
4011}
4012
4013void process_frozen_message(LLMessageSystem *msgsystem, void **user_data)
4014{
4015 // make sure the cursor is back to the usual default since the
4016 // alert is probably due to some kind of error.
4017 gViewerWindow->getWindow()->resetBusyCount();
4018 BOOL b_frozen;
4019
4020 msgsystem->getBOOL("FrozenData", "Data", b_frozen);
4021
4022 // TODO: make being frozen change view
4023 if (b_frozen)
4024 {
4025 }
4026 else
4027 {
4028 }
4029}
4030
4031// do some extra stuff once we get our economy data
4032void process_economy_data(LLMessageSystem *msg, void** /*user_data*/)
4033{
4034 LLGlobalEconomy::processEconomyData(msg, (void**)gGlobalEconomy);
4035
4036 S32 upload_cost = gGlobalEconomy->getPriceUpload();
4037 LLFloaterImagePreview::setUploadAmount(upload_cost);
4038
4039 gMenuHolder->childSetLabelArg("Upload Image", "[COST]", llformat("%d", upload_cost));
4040 gMenuHolder->childSetLabelArg("Upload Sound", "[COST]", llformat("%d", upload_cost));
4041 gMenuHolder->childSetLabelArg("Upload Animation", "[COST]", llformat("%d", upload_cost));
4042 gMenuHolder->childSetLabelArg("Bulk Upload", "[COST]", llformat("%d", upload_cost));
4043}
4044
4045class LLScriptQuestionCBData
4046{
4047public:
4048 LLScriptQuestionCBData(const LLUUID &taskid, const LLUUID &itemid, const LLHost &sender, S32 questions)
4049 : mTaskID(taskid), mItemID(itemid), mSender(sender), mQuestions(questions)
4050 {
4051 }
4052
4053 LLUUID mTaskID;
4054 LLUUID mItemID;
4055 LLHost mSender;
4056 S32 mQuestions;
4057};
4058
4059
4060void script_question_cb(S32 option, void* user_data)
4061{
4062 LLMessageSystem *msg = gMessageSystem;
4063 LLScriptQuestionCBData *cbdata = (LLScriptQuestionCBData *)user_data;
4064 if (option != 0)
4065 {
4066 cbdata->mQuestions = 0;
4067 }
4068 msg->newMessageFast(_PREHASH_ScriptAnswerYes);
4069 msg->nextBlockFast(_PREHASH_AgentData);
4070 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
4071 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
4072 msg->nextBlockFast(_PREHASH_Data);
4073 msg->addUUIDFast(_PREHASH_TaskID, cbdata->mTaskID);
4074 msg->addUUIDFast(_PREHASH_ItemID, cbdata->mItemID);
4075 msg->addS32Fast(_PREHASH_Questions, cbdata->mQuestions);
4076 msg->sendReliable(cbdata->mSender);
4077 delete cbdata;
4078}
4079
4080
4081void process_script_question(LLMessageSystem *msg, void **user_data)
4082{
4083 // XUI:translate owner name -> [FIRST] [LAST]
4084 const LLString script_questions[SCRIPT_PERMISSION_EOF] =
4085 {
4086 "ScriptTakeMoney",
4087 "ActOnControlInputs",
4088 "RemapControlInputs",
4089 "AnimateYourAvatar",
4090 "AttachToYourAvatar",
4091 "ReleaseOwnership",
4092 "LinkAndDelink",
4093 "AddAndRemoveJoints",
4094 "ChangePermissions",
4095 "TrackYourCamera",
4096 "ControlYourCamera"
4097 };
4098
4099 LLHost sender = msg->getSender();
4100
4101 LLUUID taskid;
4102 LLUUID itemid;
4103 S32 questions;
4104 char object_name[255];
4105 char owner_name[DB_FULL_NAME_BUF_SIZE];
4106
4107 msg->getUUIDFast(_PREHASH_Data, _PREHASH_TaskID, taskid );
4108 msg->getUUIDFast(_PREHASH_Data, _PREHASH_ItemID, itemid );
4109 msg->getStringFast(_PREHASH_Data, _PREHASH_ObjectName, 255, object_name);
4110 msg->getStringFast(_PREHASH_Data, _PREHASH_ObjectOwner, DB_FULL_NAME_BUF_SIZE, owner_name);
4111 msg->getS32Fast(_PREHASH_Data, _PREHASH_Questions, questions );
4112
4113 LLString script_question;
4114 if (questions)
4115 {
4116 S32 count = 0;
4117 LLString::format_map_t args;
4118 args["[OBJECTNAME]"] = object_name;
4119 args["[NAME]"] = owner_name;
4120 for (S32 i = 0; i < SCRIPT_PERMISSION_EOF; i++)
4121 {
4122 if (questions & LSCRIPTRunTimePermissionBits[i])
4123 {
4124 count++;
4125 script_question += " " + LLNotifyBox::getTemplateMessage(script_questions[i]) + "\n";
4126 }
4127 }
4128 args["[QUESTIONS]"] = script_question;
4129
4130 LLScriptQuestionCBData *cbdata = new LLScriptQuestionCBData(taskid, itemid, sender, questions);
4131
4132 LLNotifyBox::showXml("ScriptQuestion", args, script_question_cb, cbdata);
4133 }
4134}
4135
4136
4137void process_derez_container(LLMessageSystem *msg, void**)
4138{
4139 llwarns << "call to deprecated process_derez_container" << llendl;
4140}
4141
4142void container_inventory_arrived(LLViewerObject* object,
4143 InventoryObjectList* inventory,
4144 S32 serial_num,
4145 void* data)
4146{
4147 llinfos << "container_inventory_arrived()" << llendl;
4148 if( gAgent.cameraMouselook() )
4149 {
4150 gAgent.changeCameraToDefault();
4151 }
4152
4153 LLInventoryView* view = LLInventoryView::getActiveInventory();
4154
4155 if (inventory->size() > 2)
4156 {
4157 // create a new inventory category to put this in
4158 LLUUID cat_id;
4159 cat_id = gInventory.createNewCategory(gAgent.getInventoryRootID(),
4160 LLAssetType::AT_NONE,
4161 "Acquired Items");
4162
4163 InventoryObjectList::const_iterator it = inventory->begin();
4164 InventoryObjectList::const_iterator end = inventory->end();
4165 for ( ; it != end; ++it)
4166 {
4167 if ((*it)->getType() != LLAssetType::AT_CATEGORY &&
4168 (*it)->getType() != LLAssetType::AT_ROOT_CATEGORY)
4169 {
4170 LLInventoryObject* obj = (LLInventoryObject*)(*it);
4171 LLInventoryItem* item = (LLInventoryItem*)(obj);
4172 LLUUID item_id;
4173 item_id.generate();
4174 S32 creation_date_utc = time_corrected();
4175 LLPointer<LLViewerInventoryItem> new_item
4176 = new LLViewerInventoryItem(item_id,
4177 cat_id,
4178 item->getPermissions(),
4179 item->getAssetUUID(),
4180 item->getType(),
4181 item->getInventoryType(),
4182 item->getName(),
4183 item->getDescription(),
4184 LLSaleInfo::DEFAULT,
4185 item->getFlags(),
4186 creation_date_utc);
4187 new_item->updateServer(TRUE);
4188 gInventory.updateItem(new_item);
4189 }
4190 }
4191 gInventory.notifyObservers();
4192 if(view)
4193 {
4194 view->getPanel()->setSelection(cat_id, TAKE_FOCUS_NO);
4195 }
4196 }
4197 else if (inventory->size() == 2)
4198 {
4199 // we're going to get one fake root category as well as the
4200 // one actual object
4201 InventoryObjectList::iterator it = inventory->begin();
4202
4203 if ((*it)->getType() == LLAssetType::AT_CATEGORY ||
4204 (*it)->getType() == LLAssetType::AT_ROOT_CATEGORY)
4205 {
4206 ++it;
4207 }
4208
4209 LLInventoryItem* item = (LLInventoryItem*)((LLInventoryObject*)(*it));
4210 LLUUID category = gInventory.findCategoryUUIDForType(item->getType());
4211
4212 LLUUID item_id;
4213 item_id.generate();
4214 S32 creation_date_utc = time_corrected();
4215 LLPointer<LLViewerInventoryItem> new_item
4216 = new LLViewerInventoryItem(item_id, category,
4217 item->getPermissions(),
4218 item->getAssetUUID(),
4219 item->getType(),
4220 item->getInventoryType(),
4221 item->getName(),
4222 item->getDescription(),
4223 LLSaleInfo::DEFAULT,
4224 item->getFlags(),
4225 creation_date_utc);
4226 new_item->updateServer(TRUE);
4227 gInventory.updateItem(new_item);
4228 gInventory.notifyObservers();
4229 if(view)
4230 {
4231 view->getPanel()->setSelection(item_id, TAKE_FOCUS_NO);
4232 }
4233 }
4234
4235 // we've got the inventory, now delete this object if this was a take
4236 BOOL delete_object = (BOOL)(intptr_t)data;
4237 LLViewerRegion *region = gAgent.getRegion();
4238 if (delete_object && region)
4239 {
4240 gMessageSystem->newMessageFast(_PREHASH_ObjectDelete);
4241 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
4242 gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
4243 gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
4244 const U8 NO_FORCE = 0;
4245 gMessageSystem->addU8Fast(_PREHASH_Force, NO_FORCE);
4246 gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
4247 gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID());
4248 gMessageSystem->sendReliable(region->getHost());
4249 }
4250}
4251
4252// method to format the time. Buffer should be at least
4253// TIME_STR_LENGTH long, and the function returns buffer (for use in
4254// sprintf and the like)
4255char* formatted_time(const time_t& the_time, char* buffer)
4256{
4257 LLString::copy(buffer, ctime(&the_time), TIME_STR_LENGTH);
4258 buffer[24] = '\0';
4259 return buffer;
4260}
4261
4262
4263void process_teleport_failed(LLMessageSystem *msg, void**)
4264{
4265 char reason[STD_STRING_BUF_SIZE];
4266 msg->getStringFast(_PREHASH_Info, _PREHASH_Reason, STD_STRING_BUF_SIZE, reason);
4267
4268 LLStringBase<char>::format_map_t args;
4269 args["[REASON]"] = reason;
4270 gViewerWindow->alertXml("CouldNotTeleportReason", args);
4271
4272 if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE )
4273 {
4274 gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
4275 }
4276}
4277
4278void process_teleport_local(LLMessageSystem *msg,void**)
4279{
4280 LLUUID agent_id;
4281 msg->getUUIDFast(_PREHASH_Info, _PREHASH_AgentID, agent_id);
4282 if (agent_id != gAgent.getID())
4283 {
4284 llwarns << "Got teleport notification for wrong agent!" << llendl;
4285 return;
4286 }
4287
4288 U32 location_id;
4289 LLVector3 pos, look_at;
4290 U32 teleport_flags;
4291 msg->getU32Fast(_PREHASH_Info, _PREHASH_LocationID, location_id);
4292 msg->getVector3Fast(_PREHASH_Info, _PREHASH_Position, pos);
4293 msg->getVector3Fast(_PREHASH_Info, _PREHASH_LookAt, look_at);
4294 msg->getU32Fast(_PREHASH_Info, _PREHASH_TeleportFlags, teleport_flags);
4295
4296 if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE )
4297 {
4298 gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
4299 }
4300
4301 // Sim tells us whether the new position is off the ground
4302 if (teleport_flags & TELEPORT_FLAGS_IS_FLYING)
4303 {
4304 gAgent.setFlying(TRUE);
4305 }
4306 else
4307 {
4308 gAgent.setFlying(FALSE);
4309 }
4310
4311 gAgent.setPositionAgent(pos);
4312 gAgent.slamLookAt(look_at);
4313
4314 // likewise make sure the camera is behind the avatar
4315 gAgent.resetView(TRUE);
4316
4317 // send camera update to new region
4318 gAgent.updateCamera();
4319
4320 send_agent_update(TRUE, TRUE);
4321}
4322
4323void send_simple_im(const LLUUID& to_id,
4324 const char* message,
4325 EInstantMessage dialog,
4326 const LLUUID& id)
4327{
4328 std::string my_name;
4329 gAgent.buildFullname(my_name);
4330 send_improved_im(to_id,
4331 my_name.c_str(),
4332 message,
4333 IM_ONLINE,
4334 dialog,
4335 id,
4336 NO_TIMESTAMP,
4337 (U8*)EMPTY_BINARY_BUCKET,
4338 EMPTY_BINARY_BUCKET_SIZE);
4339}
4340
4341void send_group_notice(const LLUUID& group_id,
4342 const char* subject,
4343 const char* message,
4344 const LLInventoryItem* item)
4345{
4346 // Put this notice into an instant message form.
4347 // This will mean converting the item to a binary bucket,
4348 // and the subject/message into a single field.
4349 std::string my_name;
4350 gAgent.buildFullname(my_name);
4351
4352 // Combine subject + message into a single string.
4353 std::ostringstream subject_and_message;
4354 // TODO: turn all existing |'s into ||'s in subject and message.
4355 subject_and_message << subject << "|" << message;
4356
4357 // Create an empty binary bucket.
4358 U8 bin_bucket[MAX_INVENTORY_BUFFER_SIZE];
4359 U8* bucket_to_send = bin_bucket;
4360 bin_bucket[0] = '\0';
4361 S32 bin_bucket_size = EMPTY_BINARY_BUCKET_SIZE;
4362 // If there is an item being sent, pack it into the binary bucket.
4363 if (item)
4364 {
4365 LLSD item_def;
4366 item_def["item_id"] = item->getUUID();
4367 item_def["owner_id"] = item->getPermissions().getOwner();
4368 std::ostringstream ostr;
4369 LLSDSerialize::serialize(item_def, ostr, LLSDSerialize::LLSD_XML);
4370 bin_bucket_size = ostr.str().copy(
4371 (char*)bin_bucket, ostr.str().size());
4372 bin_bucket[bin_bucket_size] = '\0';
4373 }
4374 else
4375 {
4376 bucket_to_send = (U8*) EMPTY_BINARY_BUCKET;
4377 }
4378
4379
4380 send_improved_im(
4381 group_id,
4382 my_name.c_str(),
4383 subject_and_message.str().c_str(),
4384 IM_ONLINE,
4385 IM_GROUP_NOTICE,
4386 LLUUID::null,
4387 NO_TIMESTAMP,
4388 bucket_to_send,
4389 bin_bucket_size);
4390}
4391
4392void handle_lure_callback(S32 option, const LLString& text, void* userdata)
4393{
4394 LLDynamicArray<LLUUID>* invitees = (LLDynamicArray<LLUUID>*)userdata;
4395
4396 if(0 == option)
4397 {
4398 LLMessageSystem* msg = gMessageSystem;
4399 msg->newMessageFast(_PREHASH_StartLure);
4400 msg->nextBlockFast(_PREHASH_AgentData);
4401 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
4402 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
4403 msg->nextBlockFast(_PREHASH_Info);
4404 msg->addU8Fast(_PREHASH_LureType, (U8)0); // sim will fill this in.
4405 msg->addStringFast(_PREHASH_Message, text.c_str());
4406 for(LLDynamicArray<LLUUID>::iterator itr = invitees->begin(); itr != invitees->end(); ++itr)
4407 {
4408 msg->nextBlockFast(_PREHASH_TargetData);
4409 msg->addUUIDFast(_PREHASH_TargetID, *itr);
4410 }
4411 gAgent.sendReliableMessage();
4412 }
4413
4414 delete invitees;
4415 invitees = NULL;
4416}
4417
4418void handle_lure_callback_godlike(S32 option, void* userdata)
4419{
4420 handle_lure_callback(option, LLString::null, userdata);
4421}
4422
4423void send_lure_911(void** user_data, S32 result)
4424{
4425 LLUUID im_session_id(*((LLUUID*)user_data));
4426 LLString name;
4427 gAgent.getName(name);
4428 LLString text = name + " needs help"; // this text is ignored for 911 lures
4429 LLMessageSystem* msg = gMessageSystem;
4430 msg->newMessageFast(_PREHASH_StartLure);
4431 msg->nextBlockFast(_PREHASH_AgentData);
4432 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
4433 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
4434 msg->nextBlockFast(_PREHASH_Info);
4435 msg->addU8Fast(_PREHASH_LureType, (U8)IM_LURE_911);
4436 msg->addStringFast(_PREHASH_Message, text.c_str());
4437 msg->nextBlockFast(_PREHASH_TargetData);
4438 msg->addUUIDFast(_PREHASH_TargetID, im_session_id);
4439 gAgent.sendReliableMessage();
4440}
4441
4442void handle_lure(const LLUUID& invitee)
4443{
4444 LLDynamicArray<LLUUID> ids;
4445 ids.push_back(invitee);
4446 handle_lure(ids);
4447}
4448
4449// Prompt for a message to the invited user.
4450void handle_lure(LLDynamicArray<LLUUID>& ids)
4451{
4452 LLDynamicArray<LLUUID>* userdata = new LLDynamicArray<LLUUID>(ids);
4453
4454 LLString::format_map_t edit_args;
4455 edit_args["[REGION]"] = gAgent.getRegion()->getName();
4456 if (gAgent.isGodlike())
4457 {
4458 gViewerWindow->alertXmlEditText("OfferTeleportFromGod", edit_args,
4459 &handle_lure_callback_godlike, userdata,
4460 NULL, NULL, edit_args);
4461 }
4462 else
4463 {
4464 gViewerWindow->alertXmlEditText("OfferTeleport", edit_args,
4465 NULL, NULL,
4466 handle_lure_callback, userdata, edit_args);
4467 }
4468}
4469
4470
4471void send_improved_im(const LLUUID& to_id,
4472 const char* name,
4473 const char* message,
4474 U8 offline,
4475 EInstantMessage dialog,
4476 const LLUUID& id,
4477 U32 timestamp,
4478 const U8* binary_bucket,
4479 S32 binary_bucket_size)
4480{
4481 pack_instant_message(
4482 gMessageSystem,
4483 gAgent.getID(),
4484 FALSE,
4485 gAgent.getSessionID(),
4486 to_id,
4487 name,
4488 message,
4489 offline,
4490 dialog,
4491 id,
4492 0,
4493 LLUUID::null,
4494 gAgent.getPositionAgent(),
4495 timestamp,
4496 binary_bucket,
4497 binary_bucket_size);
4498 gAgent.sendReliableMessage();
4499}
4500
4501
4502void send_places_query(const LLUUID& query_id,
4503 const LLUUID& trans_id,
4504 const char* query_text,
4505 U32 query_flags,
4506 S32 category,
4507 const char* sim_name)
4508{
4509 LLMessageSystem* msg = gMessageSystem;
4510
4511 msg->newMessage("PlacesQuery");
4512 msg->nextBlock("AgentData");
4513 msg->addUUID("AgentID", gAgent.getID());
4514 msg->addUUID("SessionID", gAgent.getSessionID());
4515 msg->addUUID("QueryID", query_id);
4516 msg->nextBlock("TransactionData");
4517 msg->addUUID("TransactionID", trans_id);
4518 msg->nextBlock("QueryData");
4519 msg->addString("QueryText", query_text);
4520 msg->addU32("QueryFlags", query_flags);
4521 msg->addS8("Category", (S8)category);
4522 msg->addString("SimName", sim_name);
4523 gAgent.sendReliableMessage();
4524}
4525
4526
4527void process_user_info_reply(LLMessageSystem* msg, void**)
4528{
4529 LLUUID agent_id;
4530 msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
4531 if(agent_id != gAgent.getID())
4532 {
4533 llwarns << "process_user_info_reply - "
4534 << "wrong agent id." << llendl;
4535 }
4536
4537 BOOL im_via_email;
4538 msg->getBOOLFast(_PREHASH_UserData, _PREHASH_IMViaEMail, im_via_email);
4539 char email[DB_USER_EMAIL_ADDR_BUF_SIZE];
4540 msg->getStringFast(_PREHASH_UserData, _PREHASH_EMail, DB_USER_EMAIL_ADDR_BUF_SIZE,
4541 email);
4542 char dir_visibility[MAX_STRING];
4543 msg->getString(
4544 "UserData", "DirectoryVisibility", MAX_STRING, dir_visibility);
4545
4546 LLFloaterPreference::updateUserInfo(dir_visibility, im_via_email, email);
4547 LLFloaterPostcard::updateUserInfo(email);
4548}
4549
4550
4551//---------------------------------------------------------------------------
4552// Script Dialog
4553//---------------------------------------------------------------------------
4554
4555const S32 SCRIPT_DIALOG_MAX_BUTTONS = 12;
4556const S32 SCRIPT_DIALOG_BUTTON_STR_SIZE = 24;
4557const S32 SCRIPT_DIALOG_MAX_MESSAGE_SIZE = 512;
4558const char* SCRIPT_DIALOG_HEADER = "Script Dialog:\n";
4559
4560struct ScriptDialogInfo
4561{
4562 LLHost mSender;
4563 LLUUID mObjectID;
4564 S32 mChatChannel;
4565 std::vector<LLString> mButtons;
4566};
4567
4568void callback_script_dialog(S32 option, void* data)
4569{
4570 ScriptDialogInfo* info = (ScriptDialogInfo*)data;
4571 if (!info) return;
4572
4573 // Didn't click "Ignore"
4574 if (0 != option)
4575 {
4576 LLMessageSystem* msg = gMessageSystem;
4577 msg->newMessage("ScriptDialogReply");
4578 msg->nextBlock("AgentData");
4579 msg->addUUID("AgentID", gAgent.getID());
4580 msg->addUUID("SessionID", gAgent.getSessionID());
4581 msg->nextBlock("Data");
4582 msg->addUUID("ObjectID", info->mObjectID);
4583 msg->addS32("ChatChannel", info->mChatChannel);
4584 msg->addS32("ButtonIndex", option);
4585 msg->addString("ButtonLabel", info->mButtons[option-1]);
4586 msg->sendReliable(info->mSender);
4587 }
4588
4589 delete info;
4590}
4591
4592void process_script_dialog(LLMessageSystem* msg, void**)
4593{
4594 S32 i;
4595
4596 ScriptDialogInfo* info = new ScriptDialogInfo;
4597
4598 const S32 messageLength = SCRIPT_DIALOG_MAX_MESSAGE_SIZE + sizeof(SCRIPT_DIALOG_HEADER);
4599 char message[messageLength]; // Account for size of "Script Dialog:\n"
4600
4601 char first_name[DB_FIRST_NAME_BUF_SIZE];
4602 char last_name[DB_GROUP_NAME_BUF_SIZE];
4603 char title[DB_INV_ITEM_NAME_BUF_SIZE];
4604 info->mSender = msg->getSender();
4605
4606 msg->getUUID("Data", "ObjectID", info->mObjectID);
4607 msg->getString("Data", "FirstName", DB_FIRST_NAME_BUF_SIZE, first_name);
4608 msg->getString("Data", "LastName", DB_LAST_NAME_BUF_SIZE, last_name);
4609 msg->getString("Data", "ObjectName", DB_INV_ITEM_NAME_BUF_SIZE, title);
4610 msg->getString("Data", "Message", SCRIPT_DIALOG_MAX_MESSAGE_SIZE, message);
4611 msg->getS32("Data", "ChatChannel", info->mChatChannel);
4612
4613 // unused for now
4614 LLUUID image_id;
4615 msg->getUUID("Data", "ImageID", image_id);
4616
4617 S32 button_count = msg->getNumberOfBlocks("Buttons");
4618 if (button_count > SCRIPT_DIALOG_MAX_BUTTONS)
4619 {
4620 button_count = SCRIPT_DIALOG_MAX_BUTTONS;
4621 }
4622
4623 for (i = 0; i < button_count; i++)
4624 {
4625 char tdesc[SCRIPT_DIALOG_BUTTON_STR_SIZE+1];
4626 msg->getString("Buttons", "ButtonLabel", SCRIPT_DIALOG_BUTTON_STR_SIZE + 1, tdesc, i);
4627 info->mButtons.push_back(LLString(tdesc));
4628 }
4629
4630 LLStringBase<char>::format_map_t args;
4631 args["[TITLE]"] = title;
4632 args["[MESSAGE]"] = message;
4633 if (strlen(first_name) > 0)
4634 {
4635 args["[FIRST]"] = first_name;
4636 args["[LAST]"] = last_name;
4637 LLNotifyBox::showXml("ScriptDialog", args,
4638 callback_script_dialog, info,
4639 info->mButtons,
4640 TRUE);
4641 }
4642 else
4643 {
4644 args["[GROUPNAME]"] = last_name;
4645 LLNotifyBox::showXml("ScriptDialogGroup", args,
4646 callback_script_dialog, info,
4647 info->mButtons,
4648 TRUE);
4649 }
4650}
4651
4652//---------------------------------------------------------------------------
4653
4654struct LoadUrlInfo
4655{
4656 LLUUID mObjectID;
4657 LLUUID mOwnerID;
4658 BOOL mOwnerIsGroup;
4659 char mObjectName[256];
4660 char mMessage[256];
4661 char mUrl[256];
4662};
4663
4664std::vector<LoadUrlInfo*> gLoadUrlList;
4665
4666void callback_load_url(S32 option, void* data)
4667{
4668 LoadUrlInfo* infop = (LoadUrlInfo*)data;
4669 if (!infop) return;
4670
4671 if (0 == option)
4672 {
4673 LLWeb::loadURL(infop->mUrl);
4674 }
4675
4676 delete infop;
4677 infop = NULL;
4678}
4679
4680
4681// We've got the name of the person who owns the object hurling the url.
4682// Display confirmation dialog.
4683void callback_load_url_name(const LLUUID& id, const char* first, const char* last, BOOL is_group, void* data)
4684{
4685 std::vector<LoadUrlInfo*>::iterator it;
4686 for (it = gLoadUrlList.begin(); it != gLoadUrlList.end(); )
4687 {
4688 LoadUrlInfo* infop = *it;
4689 if (infop->mOwnerID == id)
4690 {
4691 it = gLoadUrlList.erase(it);
4692
4693 std::string owner_name(first);
4694 if (is_group)
4695 {
4696 owner_name += " (group)";
4697 }
4698 else
4699 {
4700 owner_name += " ";
4701 owner_name += last;
4702 }
4703
4704 // TODO: Talk to james about using an id instead of a name for this.
4705 if (gMuteListp->isMuted(LLUUID::null, owner_name))
4706 {
4707 delete infop;
4708 infop = NULL;
4709 continue;
4710 }
4711 LLString::format_map_t args;
4712 args["[URL]"] = infop->mUrl;
4713 args["[MESSAGE]"] = infop->mMessage;
4714 args["[OBJECTNAME]"] = infop->mObjectName;
4715 args["[NAME]"] = owner_name;
4716 LLNotifyBox::showXml("LoadWebPage", args, callback_load_url, infop);
4717 }
4718 else
4719 {
4720 ++it;
4721 }
4722 }
4723}
4724
4725void process_load_url(LLMessageSystem* msg, void**)
4726{
4727 LoadUrlInfo* infop = new LoadUrlInfo;
4728
4729 msg->getString("Data", "ObjectName", 256, infop->mObjectName);
4730 msg->getUUID( "Data", "ObjectID", infop->mObjectID);
4731 msg->getUUID( "Data", "OwnerID", infop->mOwnerID);
4732 msg->getBOOL( "Data", "OwnerIsGroup", infop->mOwnerIsGroup);
4733 msg->getString("Data", "Message", 256, infop->mMessage);
4734 msg->getString("Data", "URL", 256, infop->mUrl);
4735
4736 // URL is safety checked in load_url above
4737
4738 // Check if object or owner is muted
4739 if (gMuteListp->isMuted(infop->mObjectID, infop->mObjectName))
4740 {
4741 delete infop;
4742 infop = NULL;
4743 return;
4744 }
4745
4746 // Add to list of pending name lookups
4747 gLoadUrlList.push_back(infop);
4748
4749 gCacheName->get(infop->mOwnerID, infop->mOwnerIsGroup, callback_load_url_name);
4750}
4751
4752
4753void callback_download_complete(void** data, S32 result)
4754{
4755 LLString* filepath = (LLString*)data;
4756 LLString::format_map_t args;
4757 args["[DOWNLOAD_PATH]"] = *filepath;
4758 gViewerWindow->alertXml("FinishedRawDownload", args);
4759 delete filepath;
4760}
4761
4762
4763void process_initiate_download(LLMessageSystem* msg, void**)
4764{
4765 LLUUID agent_id;
4766 msg->getUUID("AgentData", "AgentID", agent_id);
4767 if (agent_id != gAgent.getID())
4768 {
4769 llwarns << "Initiate download for wrong agent" << llendl;
4770 return;
4771 }
4772
4773 char sim_filename[MAX_PATH];
4774 char viewer_filename[MAX_PATH];
4775 msg->getString("FileData", "SimFilename", MAX_PATH, sim_filename);
4776 msg->getString("FileData", "ViewerFilename", MAX_PATH, viewer_filename);
4777
4778 gXferManager->requestFile(viewer_filename,
4779 sim_filename,
4780 LL_PATH_NONE,
4781 msg->getSender(),
4782 FALSE, // don't delete remote
4783 callback_download_complete,
4784 (void**)new LLString(viewer_filename));
4785}
4786
4787
4788void process_script_teleport_request(LLMessageSystem* msg, void**)
4789{
4790 char object_name[256];
4791 char sim_name[256];
4792 LLVector3 pos;
4793 LLVector3 look_at;
4794
4795 msg->getString("Data", "ObjectName", 255, object_name);
4796 msg->getString( "Data", "SimName", 255, sim_name);
4797 msg->getVector3("Data", "SimPosition", pos);
4798 msg->getVector3("Data", "LookAt", look_at);
4799
4800 gFloaterWorldMap->trackURL(sim_name, (U32)pos.mV[VX], (U32)pos.mV[VY], (U32)pos.mV[VZ]);
4801 LLFloaterWorldMap::show(NULL, TRUE);
4802}
4803
4804void process_covenant_reply(LLMessageSystem* msg, void**)
4805{
4806 LLUUID covenant_id, estate_owner_id;
4807 char estate_name[MAX_STRING];
4808 U32 covenant_timestamp;
4809 msg->getUUID("Data", "CovenantID", covenant_id);
4810 msg->getU32("Data", "CovenantTimestamp", covenant_timestamp);
4811 msg->getString("Data", "EstateName", MAX_STRING, estate_name);
4812 msg->getUUID("Data", "EstateOwnerID", estate_owner_id);
4813
4814 LLPanelEstateCovenant::updateEstateName(estate_name);
4815 LLPanelLandCovenant::updateEstateName(estate_name);
4816 LLFloaterBuyLand::updateEstateName(estate_name);
4817
4818 // standard message, not from system
4819 char last_modified[MAX_STRING];
4820 last_modified[0] = '\0';
4821 char time_buf[TIME_STR_LENGTH];
4822 sprintf(last_modified, "Last Modified %s",
4823 formatted_time((time_t)covenant_timestamp, time_buf));
4824
4825 LLPanelEstateCovenant::updateLastModified(last_modified);
4826 LLPanelLandCovenant::updateLastModified(last_modified);
4827 LLFloaterBuyLand::updateLastModified(last_modified);
4828
4829 gCacheName->getName(estate_owner_id, callbackCacheEstateOwnerName);
4830
4831 // load the actual covenant asset data
4832 const BOOL high_priority = TRUE;
4833 if (covenant_id.notNull())
4834 {
4835 gAssetStorage->getEstateAsset(gAgent.getRegionHost(),
4836 gAgent.getID(),
4837 gAgent.getSessionID(),
4838 covenant_id,
4839 LLAssetType::AT_NOTECARD,
4840 ET_Covenant,
4841 onCovenantLoadComplete,
4842 NULL,
4843 high_priority);
4844 }
4845 else
4846 {
4847 std::string covenant_text;
4848 if (estate_owner_id.isNull())
4849 {
4850 // mainland
4851 covenant_text = "There is no Covenant provided for this Estate.";
4852 }
4853 else
4854 {
4855 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.";
4856 }
4857 LLPanelEstateCovenant::updateCovenantText(covenant_text, covenant_id);
4858 LLPanelLandCovenant::updateCovenantText(covenant_text);
4859 LLFloaterBuyLand::updateCovenantText(covenant_text, covenant_id);
4860 }
4861}
4862
4863void callbackCacheEstateOwnerName(
4864 const LLUUID& id,
4865 const char* first,
4866 const char* last,
4867 BOOL is_group,
4868 void*)
4869{
4870 std::string name;
4871
4872 if (id.isNull())
4873 {
4874 name = "(none)";
4875 }
4876 else
4877 {
4878 name = first;
4879 name += " ";
4880 name += last;
4881 }
4882 LLPanelEstateCovenant::updateEstateOwnerName(name);
4883 LLPanelLandCovenant::updateEstateOwnerName(name);
4884 LLFloaterBuyLand::updateEstateOwnerName(name);
4885}
4886
4887void onCovenantLoadComplete(LLVFS *vfs,
4888 const LLUUID& asset_uuid,
4889 LLAssetType::EType type,
4890 void* user_data, S32 status)
4891{
4892 llinfos << "onCovenantLoadComplete()" << llendl;
4893 std::string covenant_text;
4894 if(0 == status)
4895 {
4896 LLVFile file(vfs, asset_uuid, type, LLVFile::READ);
4897
4898 S32 file_length = file.getSize();
4899
4900 char* buffer = new char[file_length+1];
4901 file.read((U8*)buffer, file_length);
4902
4903 // put a EOS at the end
4904 buffer[file_length] = 0;
4905
4906 if( (file_length > 19) && !strncmp( buffer, "Linden text version", 19 ) )
4907 {
4908 LLViewerTextEditor* editor = new LLViewerTextEditor("temp",
4909 LLRect(0,0,0,0),
4910 file_length+1);
4911 if( !editor->importBuffer( buffer ) )
4912 {
4913 llwarns << "Problem importing estate covenant." << llendl;
4914 covenant_text = "Problem importing estate covenant.";
4915 }
4916 else
4917 {
4918 // Version 0 (just text, doesn't include version number)
4919 covenant_text = editor->getText();
4920 }
4921 delete[] buffer;
4922 delete editor;
4923 }
4924 else
4925 {
4926 if( gViewerStats )
4927 {
4928 gViewerStats->incStat( LLViewerStats::ST_DOWNLOAD_FAILED );
4929 }
4930
4931 if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status ||
4932 LL_ERR_FILE_EMPTY == status)
4933 {
4934 covenant_text = "Estate covenant notecard is missing from database.";
4935 }
4936 else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status)
4937 {
4938 covenant_text = "Insufficient permissions to view estate covenant.";
4939 }
4940 else
4941 {
4942 covenant_text = "Unable to load estate covenant at this time.";
4943 }
4944
4945 llwarns << "Problem loading notecard: " << status << llendl;
4946 }
4947 }
4948 LLPanelEstateCovenant::updateCovenantText(covenant_text, asset_uuid);
4949 LLPanelLandCovenant::updateCovenantText(covenant_text);
4950 LLFloaterBuyLand::updateCovenantText(covenant_text, asset_uuid);
4951}
4952
4953void send_generic_message(const char* method,
4954 const std::vector<std::string>& strings,
4955 const LLUUID& invoice)
4956{
4957 LLMessageSystem* msg = gMessageSystem;
4958 msg->newMessage("GenericMessage");
4959 msg->nextBlockFast(_PREHASH_AgentData);
4960 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
4961 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
4962 msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); //not used
4963 msg->nextBlock("MethodData");
4964 msg->addString("Method", method);
4965 msg->addUUID("Invoice", invoice);
4966 if(strings.empty())
4967 {
4968 msg->nextBlock("ParamList");
4969 msg->addString("Parameter", NULL);
4970 }
4971 else
4972 {
4973 std::vector<std::string>::const_iterator it = strings.begin();
4974 std::vector<std::string>::const_iterator end = strings.end();
4975 for(; it != end; ++it)
4976 {
4977 msg->nextBlock("ParamList");
4978 msg->addString("Parameter", (*it).c_str());
4979 }
4980 }
4981 gAgent.sendReliableMessage();
4982}
4983
4984
4985void process_generic_message(LLMessageSystem* msg, void**)
4986{
4987 LLUUID agent_id;
4988 msg->getUUID("AgentData", "AgentID", agent_id);
4989 if (agent_id != gAgent.getID())
4990 {
4991 llwarns << "GenericMessage for wrong agent" << llendl;
4992 return;
4993 }
4994
4995 std::string request;
4996 LLUUID invoice;
4997 LLDispatcher::sparam_t strings;
4998 LLDispatcher::unpackMessage(msg, request, invoice, strings);
4999
5000 if(!gGenericDispatcher.dispatch(request, invoice, strings))
5001 {
5002 llwarns << "GenericMessage " << request << " failed to dispatch"
5003 << llendl;
5004 }
5005}
5006
5007void process_feature_disabled_message(LLMessageSystem* msg, void**)
5008{
5009 // Handle Blacklisted feature simulator response...
5010 LLUUID agentID;
5011 LLUUID transactionID;
5012 char messageText[MAX_STRING];
5013 msg->getStringFast(_PREHASH_FailureInfo,_PREHASH_ErrorMessage,MAX_STRING,&messageText[0],0);
5014 msg->getUUIDFast(_PREHASH_FailureInfo,_PREHASH_AgentID,agentID);
5015 msg->getUUIDFast(_PREHASH_FailureInfo,_PREHASH_TransactionID,transactionID);
5016
5017 llwarns << "Blacklisted Feature Response:" << &messageText[0] << llendl;
5018}
5019
5020// ------------------------------------------------------------
5021// Message system exception callbacks
5022// ------------------------------------------------------------
5023
5024void invalid_message_callback(LLMessageSystem* msg,
5025 void*,
5026 EMessageException exception)
5027{
5028 bad_network_handler();
5029}