llfloateravatarlist.cpp

Go to the documentation of this file.
00001 
00008 #include "llviewerprecompiledheaders.h" // must be first include
00009 
00010 #include "llavatarconstants.h"
00011 #include "llfloateravatarlist.h"
00012 
00013 #include "llvieweruictrlfactory.h" // builds floaters from XML
00014 #include "llviewerwindow.h"
00015 #include "llscrolllistctrl.h"
00016 
00017 #include "llvoavatar.h"
00018 #include "llimview.h"
00019 #include "llfloateravatarinfo.h"
00020 #include "llregionflags.h"
00021 #include "llfloaterreporter.h"
00022 #include "llagent.h"
00023 #include "llviewerregion.h"
00024 #include "lltracker.h"
00025 #include "llviewercontrol.h"
00026 #include "llviewerstats.h"
00027 #include "llerror.h"
00028 #include "llchat.h"
00029 #include "llviewermessage.h"
00030 #include "llweb.h"
00031 #include "llviewerobjectlist.h"
00032 #include "llmutelist.h"
00033 
00034 #include <time.h>
00035 #include <string.h>
00036 
00037 #include <map>
00038 
00039 
00040 // Timeouts
00044 const F32 ACTIVITY_TIMEOUT = 1.0f;
00045 
00046 
00052 const F32 MIN_REQUEST_INTERVAL   = 1.0f;
00053 
00057 const F32 FIRST_REQUEST_TIMEOUT  = 16.0f;
00058 
00062 const F32 MAX_REQUEST_TIMEOUT    = 2048.0f;
00063  
00069 const F32 REQUEST_FAIL_TIMEOUT   = 15.0f;
00070 
00076 const F32 DEAD_KEEP_TIME = 10.0f;
00077 
00083 const F32 CLEANUP_TIMEOUT = 3600.0f;
00084 
00085 
00090 const S32 TRUSTNET_CHANNEL = 0x44470002;
00091 
00092 
00093 extern U32 gFrameCount;
00094 
00095 
00096 LLAvListTrustNetScore::LLAvListTrustNetScore(LLString type, F32 score)
00097 {
00098         Score = score;
00099         Type = type;    
00100 }
00101 
00102 
00103 LLAvatarInfo::LLAvatarInfo()
00104 {
00105 }
00106 
00107 LLAvatarInfo::LLAvatarInfo(PAYMENT_TYPE payment, ACCOUNT_TYPE account, struct tm birth)
00108 {
00109         Payment = payment;
00110         Account = account;
00111         BirthDate = birth;
00112 }
00113 
00114 S32 LLAvatarInfo::getAge()
00115 {
00116         time_t birth = mktime(&BirthDate);
00117         time_t now = time(NULL);
00118         return(S32)(difftime(now,birth) / (60*60*24));
00119 }
00120 
00121 void LLAvatarListEntry::setPosition(LLVector3d position)
00122 {
00123         if ( mPosition != position )
00124         {
00125                 setActivity(ACTIVITY_MOVING);
00126         }
00127         
00128         mPosition = position;
00129         mFrame = gFrameCount;
00130         mUpdateTimer.start();
00131 }
00132 
00133 LLVector3d LLAvatarListEntry::getPosition()
00134 {
00135         return mPosition;
00136 }
00137 
00138 U32 LLAvatarListEntry::getEntryAgeFrames()
00139 {
00140         return (gFrameCount - mFrame);
00141 }
00142 
00143 F32 LLAvatarListEntry::getEntryAgeSeconds()
00144 {
00145         return mUpdateTimer.getElapsedTimeF32();
00146 }
00147 
00148 void LLAvatarListEntry::setName(LLString name)
00149 {
00150         if ( name.empty() || (name.compare(" ") == 0))
00151         {
00152                 llwarns << "Trying to set empty name" << llendl;
00153         }
00154         mName = name;
00155 }
00156 
00157 LLString LLAvatarListEntry::getName()
00158 {
00159         return mName;
00160 }
00161 
00162 LLUUID LLAvatarListEntry::getID()
00163 {
00164         return mID;
00165 }
00166 
00167 void LLAvatarListEntry::setID(LLUUID id)
00168 {
00169         if ( id.isNull() )
00170         {
00171                 llwarns << "Trying to set null id" << llendl;
00172         }
00173         mID = id;
00174 }
00175 
00176 BOOL LLAvatarListEntry::getIsLinden()
00177 {
00178         // Are there any employees that are not a Linden?
00179         // I suppose this is a bit redundant.
00180         return ( mIsLinden || ( mAvatarInfo.getValue().Account == ACCOUNT_EMPLOYEE ) );
00181 }
00182 
00183 void LLAvatarListEntry::setAccountCustomTitle(LLString &title)
00184 {
00185         mAccountTitle = title;
00186         mAvatarInfo.getValue().Account = ACCOUNT_CUSTOM;
00187 }
00188 
00189 LLString LLAvatarListEntry::getAccountCustomTitle()
00190 {
00191         return mAccountTitle;
00192 }
00193 
00194 
00195 
00196 void LLAvatarListEntry::setActivity(ACTIVITY_TYPE activity)
00197 {
00198         if ( activity >= mActivityType || mActivityTimer.getElapsedTimeF32() > ACTIVITY_TIMEOUT )
00199         {
00200                 mActivityType = activity;
00201                 mActivityTimer.start();
00202         }
00203 }
00204 
00205 ACTIVITY_TYPE LLAvatarListEntry::getActivity()
00206 {
00207         if ( mActivityTimer.getElapsedTimeF32() > ACTIVITY_TIMEOUT )
00208         {
00209                 mActivityType = ACTIVITY_NONE;
00210         }
00211         
00212         return mActivityType;
00213 }
00214 
00215 void LLAvatarListEntry::toggleMark()
00216 {
00217         mMarked = !mMarked;
00218 }
00219 
00220 BOOL LLAvatarListEntry::isMarked()
00221 {
00222         return mMarked;
00223 }
00224 
00225 BOOL LLAvatarListEntry::isDead()
00226 {
00227         return getEntryAgeSeconds() > DEAD_KEEP_TIME;
00228 }
00229 
00230 // Avatar list is global
00231 LLFloaterAvatarList* gFloaterAvatarList = NULL;
00232 
00233 
00234 
00235 
00236 LLFloaterAvatarList::LLFloaterAvatarList() :  LLFloater("avatar list")
00237 {
00238 
00239         // Default values
00240         mTracking = FALSE;
00241         mTrackByLocation = FALSE;
00242         mARLastFrame = 0;
00243 
00244         // Create interface from XML
00245         gUICtrlFactory->buildFloater(this, "floater_avatar_scanner.xml");
00246 
00247         // Floater starts hidden        
00248         setVisible(FALSE);
00249 
00250         // Set callbacks
00251         //childSetAction("refresh_btn", onClickRefresh, this);
00252         childSetAction("profile_btn", onClickProfile, this);
00253         childSetAction("im_btn", onClickIM, this);
00254         childSetAction("track_btn", onClickTrack, this);
00255         childSetAction("mark_btn", onClickMark, this);
00256 
00257         childSetAction("gowarn_btn", onClickGohomerWarn, this);
00258         childSetAction("goeject_btn", onClickGohomerEject, this);
00259         childSetAction("goaway_btn", onClickGohomerSendAway, this);
00260         childSetAction("gohome_btn", onClickGohomerSendHome, this);
00261         childSetAction("gohomeoff_btn", onClickGohomerOff, this);
00262         childSetAction("gokey_btn", onClickGohomerSendHomeByKey, this);
00263 
00264         childSetAction("prev_in_list_btn", onClickPrevInList, this);
00265         childSetAction("next_in_list_btn", onClickNextInList, this);
00266         childSetAction("prev_marked_btn", onClickPrevMarked, this);
00267         childSetAction("next_marked_btn", onClickNextMarked, this);
00268         
00269         childSetAction("get_key_btn", onClickGetKey, this);
00270 
00271         childSetAction("tn_rate_btn", onClickTrustNetRate, this);
00272         childSetAction("tn_explain_btn", onClickTrustNetExplain, this);
00273         childSetAction("tn_website_btn", onClickTrustNetWebsite, this);
00274         childSetAction("tn_password_btn", onClickTrustNetGetPassword, this);
00275         childSetAction("tn_renew_btn", onClickTrustNetRenew, this);
00276 
00277         childSetAction("freeze_btn", onClickFreeze, this);
00278         childSetAction("eject_btn", onClickEject, this);
00279 //      childSetAction("ban_btn", onClickBan, this);
00280 //      childSetAction("unban_btn", onClickUnban, this);
00281         childSetAction("mute_btn", onClickMute, this);
00282 //      childSetAction("unmute_btn", onClickUnmute, this);
00283         childSetAction("ar_btn", onClickAR, this);
00284         childSetAction("teleport_btn", onClickTeleport, this);
00285         childSetAction("estate_eject_btn", onClickEjectFromEstate, this);
00286 
00287         setDefaultBtn("refresh_btn");
00288 
00289         // Get a pointer to the scroll list from the interface
00290         mAvatarList = LLUICtrlFactory::getScrollListByName(this, "avatar_list");
00291 
00292         mAvatarList->setCallbackUserData(this);
00293         mAvatarList->setDoubleClickCallback(onDoubleClick);
00294         mAvatarList->sortByColumn("distance", TRUE);
00295         mDataRequestTimer.start();
00296         refreshAvatarList();
00297 
00298         LLMessageSystem *msg = gMessageSystem;
00299         msg->addHandlerFunc("AvatarPropertiesReply", processAvatarPropertiesReply);
00300 }
00301 
00302 LLFloaterAvatarList::~LLFloaterAvatarList()
00303 {
00304         LLMessageSystem *msg = gMessageSystem;
00305         if ( msg )
00306         {
00307                 msg->delHandlerFunc("AvatarPropertiesReply", processAvatarPropertiesReply);
00308         }
00309 }
00310 
00311 
00312 void LLFloaterAvatarList::show()
00313 {
00314         // Make sure we make a noise.
00315         open();
00316 }
00317 
00318 //static
00319 void LLFloaterAvatarList::toggle(void*) {
00320         if (!gFloaterAvatarList) {
00321                 llinfos << "No avatar list!" << llendl;
00322                 return;
00323         }
00324 
00325         if (gFloaterAvatarList->getVisible())
00326         {
00327                 gFloaterAvatarList->close();
00328         }
00329         else
00330         {
00331                 gFloaterAvatarList->show();
00332         }
00333 }
00334 
00335 //static
00336 BOOL LLFloaterAvatarList::visible(void*)
00337 {
00338         return (gFloaterAvatarList && gFloaterAvatarList->getVisible());
00339 }
00340 
00341 //static
00342 void LLFloaterAvatarList::updateAvatarList()
00343 {
00344 //      LLVOAvatar *avatarp;
00345 
00346         //llinfos << "avatar list refresh: updating map" << llendl;
00347 
00348         // Check whether updates are enabled
00349         LLCheckboxCtrl* check;
00350         check = LLUICtrlFactory::getCheckBoxByName(this, "update_enabled_cb");
00351 
00352         if ( !check->getValue() )
00353         {
00354                 return;
00355         }
00356 
00357         /*
00358          * Iterate over all the avatars known at the time
00359          * NOTE: Is this the right way to do that? It does appear that LLVOAvatar::isInstances contains
00360          * the list of avatars known to the client. This seems to do the task of tracking avatars without
00361          * any additional requests.
00362          *
00363          * BUG: It looks like avatars sometimes get stuck in this list, and keep perpetually
00364          * moving in the same direction. My current guess is that somewhere else the client
00365          * doesn't notice an avatar disappeared, and keeps updating its position. This should
00366          * be solved at the source of the problem.
00367          */
00368         for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
00369                 iter != LLCharacter::sInstances.end(); ++iter)
00370         {
00371                 LLVOAvatar* avatarp = (LLVOAvatar*) *iter;
00372 
00373                 // Skip if avatar is dead(what's that?)
00374                 // or if the avatar is ourselves.
00375                 if (avatarp->isDead() || avatarp->isSelf())
00376                 {
00377                         continue;
00378                 }
00379 
00380                 // Get avatar data
00381                 LLVector3d position = gAgent.getPosGlobalFromAgent(avatarp->getCharacterPosition());
00382                 LLUUID avid = avatarp->getID();
00383                 LLString name = avatarp->getFullname();
00384 
00385                 // Apparently, sometimes the name comes out empty, with a " " name. This is because
00386                 // getFullname concatenates first and last name with a " " in the middle.
00387                 // This code will avoid adding a nameless entry to the list until it acquires a name.
00388                 if (name.empty() || (name.compare(" ") == 0))
00389                 {
00390                         llinfos << "Name empty for avatar " << avid << llendl;
00391                         continue;
00392                 }
00393 
00394                 if (avid.isNull())
00395                 {
00396                         llinfos << "Key empty for avatar " << name << llendl;
00397                         continue;
00398                 }
00399 
00400                 if ( mAvatars.count( avid ) > 0 )
00401                 {
00402                         // Avatar already in list, update position
00403                         mAvatars[avid].setPosition(position);
00404                 }
00405                 else
00406                 {
00407                         // Avatar not there yet, add it
00408                         BOOL isLinden = ( avatarp->getNVPair("LastName")->getString() == "Linden" );
00409 
00410                         LLAvatarListEntry entry(avid, name, position, isLinden);
00411                         mAvatars[avid] = entry;
00412 
00413                         //sendAvatarPropertiesRequest(avid);
00414                         llinfos << "avatar list refresh: adding " << name << llendl;
00415 
00416                 }
00417 
00418         }
00419 
00420 //      llinfos << "avatar list refresh: done" << llendl;
00421 
00422         expireAvatarList();
00423         refreshAvatarList();
00424         checkTrackingStatus();
00425         processARQueue();
00426 }
00427 
00428 void LLFloaterAvatarList::processARQueue()
00429 {
00430         if ( mARQueue.empty() ) return;
00431 
00432         LLUUID avatar_id = mARQueue.front();
00433 
00434         if ( 0 == mARLastFrame )
00435         {
00436                 // Start of the process: Move the camera to the avatar. This happens gradually,
00437                 // so we'll give it a few frames
00438                 gAgent.lookAtObject(avatar_id, CAMERA_POSITION_OBJECT);
00439                 mARLastFrame = gFrameCount;
00440                 return;
00441         }
00442 
00443         if ( gFrameCount - mARLastFrame >= 10 )
00444         {
00445                 // Camera should be in position, show AR screen now
00446                 LLFloaterReporter *report = LLFloaterReporter::showFromObject(avatar_id, false);
00447                 report->setMinimized(TRUE);
00448 
00449                 mARReporterQueue.push(report);
00450 
00451                 mARQueue.pop();
00452                 mARLastFrame = 0;
00453 
00454                 if ( mARQueue.empty() )
00455                 {
00456                         // Now that all reports are taken, open them.
00457 
00458                         while( !mARReporterQueue.empty() )
00459                         {
00460                                 LLFloaterReporter *r = mARReporterQueue.front();
00461                                 mARReporterQueue.pop();
00462 
00463                                 r->open();
00464                                 r->setMinimized(FALSE);
00465                         }
00466                 }
00467         }
00468 }
00469 
00470 void LLFloaterAvatarList::expireAvatarList()
00471 {
00472 //      llinfos << "avatar list: expiring" << llendl;
00473         std::map<LLUUID, LLAvatarListEntry>::iterator iter;
00474         std::queue<LLUUID> delete_queue;
00475 
00476         for(iter = mAvatars.begin(); iter != mAvatars.end(); iter++)
00477         {
00478                 LLAvatarListEntry *ent = &iter->second;
00479                 
00480                 if ( ent->getEntryAgeFrames() >= 2 )
00481                 {
00482                         ent->setActivity(ACTIVITY_DEAD);
00483                 }
00484 
00485 
00486                 if ( ent->getEntryAgeSeconds() > CLEANUP_TIMEOUT )
00487                 {
00488                         llinfos << "avatar list: expiring avatar " << ent->getName() << llendl;
00489                         LLUUID av_id = ent->getID();
00490                         delete_queue.push(av_id);
00491                 }
00492         }
00493 
00494         while(!delete_queue.empty())
00495         {
00496                 mAvatars.erase(delete_queue.front());
00497                 delete_queue.pop();
00498         }
00499 }
00500 
00506 void LLFloaterAvatarList::refreshAvatarList() 
00507 {
00508 
00509 
00510 
00511         // Don't update list when interface is hidden
00512         if (!LLFloaterAvatarList::visible(NULL))
00513         {
00514                 return;
00515         }
00516 
00517 
00518         LLCheckboxCtrl* fetch_data;
00519         fetch_data = LLUICtrlFactory::getCheckBoxByName(this, "fetch_avdata_enabled_cb");
00520 
00521         BOOL db_enabled = gSavedSettings.getBOOL("DBEnabled");
00522         LLString db_avatar = gSavedPerAccountSettings.getString("DBAvatarName");
00523         if ( db_avatar.empty() )
00524         {
00525                 db_enabled = FALSE;
00526         }
00527 
00528 
00529 
00530         // We rebuild the list fully each time it's refreshed
00531         // The assumption is that it's faster to refill it and sort than
00532         // to rebuild the whole list.
00533         LLDynamicArray<LLUUID> selected = mAvatarList->getSelectedIDs();
00534         S32 scrollpos = mAvatarList->getScrollPos();
00535 
00536         mAvatarList->deleteAllItems();
00537 
00538         LLVector3d mypos = gAgent.getPositionGlobal();
00539 
00540 
00541         std::map<LLUUID, LLAvatarListEntry>::iterator iter;
00542         for(iter = mAvatars.begin(); iter != mAvatars.end(); iter++)
00543         {
00544                 LLSD element;
00545                 LLUUID av_id;
00546 
00547                 
00548                 LLAvatarListEntry *ent = &iter->second;
00549 
00550                 // Skip if avatar hasn't been around
00551                 if ( ent->isDead() )
00552                 {
00553                         continue;
00554                 }
00555 
00556                 av_id = ent->getID();
00557 
00558                 // Get avatar name, position
00559                 LLAvatarInfo avinfo = ent->mAvatarInfo.getValue();
00560                 LLAvListTrustNetScore avscore = ent->mTrustNetScore.getValue();
00561 
00562                 DATA_STATUS avinfo_status = ent->mAvatarInfo.getStatus();
00563                 DATA_STATUS avscore_status = ent->mTrustNetScore.getStatus();
00564 
00565                 LLVector3d position = ent->getPosition();
00566                 LLVector3d delta = position - mypos;
00567                 F32 distance = (F32)delta.magVec();
00568 
00569                 LLString icon = "";
00570 
00571                 // HACK: Workaround for an apparent bug:
00572                 // sometimes avatar entries get stuck, and are registered
00573                 // by the client as perpetually moving in the same direction.
00574                 // this makes sure they get removed from the visible list eventually
00575                 if ( distance > 1024 )
00576                 {
00577                         continue;
00578                 }
00579 
00580                 if ( av_id.isNull() )
00581                 {
00582                         llwarns << "Avatar with null key somehow got into the list!" << llendl;
00583                         continue;
00584                 }
00585 
00586 
00587 
00588 
00589 
00590                 element["id"] = av_id;
00591 
00592                 element["columns"][LIST_AVATAR_ICON]["column"] = "avatar_icon";
00593                 element["columns"][LIST_AVATAR_ICON]["type"] = "text";
00594                 if ( ent->isMarked() )
00595                 {
00596                         element["columns"][LIST_AVATAR_ICON]["type"] = "icon";
00597                         element["columns"][LIST_AVATAR_ICON]["value"] = gViewerArt.getString("flag_blue.tga");
00598                 }
00599 
00600 
00601                 if ( ent->getIsLinden() )
00602                 {
00603                         element["columns"][LIST_AVATAR_NAME]["font-style"] = "BOLD";
00604                 }
00605 
00606                 if ( ent->isFocused() )
00607                 {
00608                         element["columns"][LIST_AVATAR_NAME]["color"] = LLColor4::cyan.getValue();
00609                 }
00610 
00611                 //element["columns"][LIST_AVATAR_NAME]["font-color"] = getAvatarColor(ent, distance).getValue();
00612                 element["columns"][LIST_AVATAR_NAME]["column"] = "avatar_name";
00613                 element["columns"][LIST_AVATAR_NAME]["type"] = "text";
00614                 element["columns"][LIST_AVATAR_NAME]["value"] = ent->getName().c_str();
00615 
00616                 char temp[32];
00617                 snprintf(temp, sizeof(temp), "%.2f", distance);
00618 
00619                 element["columns"][LIST_DISTANCE]["column"] = "distance";
00620                 element["columns"][LIST_DISTANCE]["type"] = "text";
00621                 element["columns"][LIST_DISTANCE]["value"] = temp;
00622                 element["columns"][LIST_DISTANCE]["color"] = getAvatarColor(ent, distance, CT_DISTANCE).getValue();
00623 
00624                 
00625                 if ( avinfo_status == DATA_RETRIEVED )
00626                 {
00627                         element["columns"][LIST_AGE]["column"] = "age";
00628                         element["columns"][LIST_AGE]["type"] = "text";
00629                         element["columns"][LIST_AGE]["value"] = avinfo.getAge();
00630                         element["columns"][LIST_AGE]["color"] = getAvatarColor(ent, distance, CT_AGE).getValue();
00631                 }
00632 
00633                 element["columns"][LIST_SCORE]["column"] = "score";
00634                 element["columns"][LIST_SCORE]["type"] = "text";
00635 
00636                 icon = "";
00637                 switch(avscore_status)
00638                 {
00639                         case DATA_UNKNOWN:
00640                                 icon = gViewerArt.getString("info_unknown.tga");
00641                                 break;
00642                         case DATA_REQUESTING:
00643                                 icon = gViewerArt.getString("info_fetching.tga");
00644                                 break;
00645                         case DATA_ERROR:
00646                                 icon =  gViewerArt.getString("info_error.tga");
00647                         case DATA_RETRIEVED:
00648                                 element["columns"][LIST_SCORE]["value"] = avscore.Score;
00649                                 element["columns"][LIST_SCORE]["color"] = getAvatarColor(ent, distance, CT_SCORE).getValue();
00650                                 break;
00651                 }
00652                 
00653                 if (!icon.empty() )
00654                 {       
00655                         element["columns"][LIST_SCORE].erase("color");
00656                         element["columns"][LIST_SCORE]["type"] = "icon";
00657                         element["columns"][LIST_SCORE]["value"] = icon;
00658                 }
00659         
00660 
00661                 // Get an icon for the payment data
00662                 // These should be replaced with something proper instead of reusing whatever
00663                 // LL-provided images happened to fit
00664                 icon = "";
00665 
00666                 switch(avinfo_status)
00667                 {
00668                         case DATA_UNKNOWN:
00669                                 icon = gViewerArt.getString("info_unknown.tga");
00670                                 break;
00671                         case DATA_REQUESTING:
00672                                 icon = gViewerArt.getString("info_fetching.tga");
00673                                 break;
00674                         case DATA_ERROR:
00675                                 icon =  gViewerArt.getString("info_error.tga");
00676                                 break;
00677                         case DATA_RETRIEVED:
00678                                 switch(avinfo.Payment)
00679                                 {
00680                                         case PAYMENT_NONE:
00681                                                 break;
00682                                         case PAYMENT_ON_FILE:
00683                                                 icon =  gViewerArt.getString("payment_info_filled.tga");
00684                                                 break;
00685                                         case PAYMENT_USED:
00686                                                 icon =  gViewerArt.getString("payment_info_used.tga");
00687                                                 break;
00688                                         case PAYMENT_LINDEN:
00689                                                 // confusingly named icon, maybe use something else
00690                                                 icon =  gViewerArt.getString("icon_top_pick.tga");
00691                                                 break;
00692                                 }
00693                                 break;
00694                 }
00695 
00696                 element["columns"][LIST_PAYMENT]["column"] = "payment_data";
00697                 element["columns"][LIST_PAYMENT]["type"] = "text";
00698 
00699                 // TODO: Add icon for "unknown" status
00700                 //if ( PAYMENT_NONE != avinfo.Payment && DATA_UNKNOWN != avinfo_status )
00701                 if ( !icon.empty() )
00702                 {
00703                         element["columns"][LIST_PAYMENT].erase("color");
00704                         element["columns"][LIST_PAYMENT]["type"] = "icon";
00705                         element["columns"][LIST_PAYMENT]["value"] =  icon;
00706                         //llinfos << "Payment icon: " << payment_icon << llendl;
00707                 }
00708 
00709                 
00710                 ACTIVITY_TYPE activity = ent->getActivity();
00711                 icon = "";
00712                 switch( activity )
00713                 {
00714                         case ACTIVITY_NONE:
00715                                 break;
00716                         case ACTIVITY_MOVING:
00717                                 icon = gViewerArt.getString("inv_item_animation.tga");
00718                                 break;
00719                         case ACTIVITY_GESTURING:
00720                                 icon = gViewerArt.getString("inv_item_gesture.tga");
00721                                 break;
00722                         case ACTIVITY_SOUND:
00723                                 icon = gViewerArt.getString("inv_item_sound.tga");
00724                                 break;
00725                         case ACTIVITY_REZZING:
00726                                 icon = gViewerArt.getString("ff_edit_theirs.tga");
00727                                 break;
00728                         case ACTIVITY_PARTICLES:
00729                                 // TODO: Replace with something better
00730                                 icon = gViewerArt.getString("account_id_blue.tga");
00731                                 break;
00732                         case ACTIVITY_NEW:
00733                                 icon = gViewerArt.getString("avatar_new.tga");
00734                                 break;
00735                         case ACTIVITY_TYPING:
00736                                 icon = gViewerArt.getString("avatar_typing.tga");
00737                                 break;
00738                         case ACTIVITY_DEAD:
00739                                 // TODO: Replace, icon is quite inappropiate
00740                                 icon = gViewerArt.getString("avatar_gone.tga");
00741                                 break;
00742                 }
00743 
00744                 element["columns"][LIST_ACTIVITY]["column"] = "activity";
00745                 element["columns"][LIST_ACTIVITY]["type"] = "text";
00746 
00747                 if (!icon.empty() )
00748                 {       
00749                         element["columns"][LIST_ACTIVITY]["type"] = "icon";
00750                         element["columns"][LIST_ACTIVITY]["value"] = icon;
00751                         //llinfos << "Activity icon: " << activity_icon << llendl;
00752                 }
00753                 
00754 
00755                 // Add to list
00756                 mAvatarList->addElement(element, ADD_BOTTOM);
00757 
00758                 // Request data only if fetching avatar data is enabled
00759                 if ( fetch_data->getValue() && ent->mAvatarInfo.requestIfNeeded() )
00760                 {
00761                         sendAvatarPropertiesRequest(av_id);
00762                         llinfos << "Data for avatar " << ent->getName() << " didn't arrive yet, retrying" << llendl;
00763                 }
00764 
00765                 if ( ent->mTrustNetScore.requestIfNeeded() )
00766                 {
00767                         requestTrustNetScore(av_id, ent->getName(), "behavior");
00768                         llinfos << "Requesting TrustNet score for " << ent->getName() << llendl;
00769                 }
00770                 
00771                 if ( db_enabled && ent->mMiscInfo.requestIfNeeded() )
00772                 {
00773                         requestMiscInfo(av_id, ent->getName());
00774                         llinfos << "Requesting misc info for " << ent->getName() << llendl;
00775                 }
00776         }
00777 
00778         // finish
00779         mAvatarList->sort();
00780         mAvatarList->selectMultiple(selected);
00781         mAvatarList->setScrollPos(scrollpos);
00782 
00783 //      llinfos << "avatar list refresh: done" << llendl;
00784 
00785 }
00786 
00787 // static
00788 void LLFloaterAvatarList::onClickIM(void* userdata)
00789 {
00790         //llinfos << "LLFloaterFriends::onClickIM()" << llendl;
00791         LLFloaterAvatarList *avlist = (LLFloaterAvatarList*)userdata;
00792 
00793         LLDynamicArray<LLUUID> ids = avlist->mAvatarList->getSelectedIDs();
00794         if(ids.size() > 0)
00795         {
00796                 if(ids.size() == 1)
00797                 {
00798                         // Single avatar
00799                         LLUUID agent_id = ids[0];
00800 
00801                         char buffer[MAX_STRING];
00802                         snprintf(buffer, MAX_STRING, "%s", avlist->mAvatars[agent_id].getName().c_str());
00803                         gIMMgr->setFloaterOpen(TRUE);
00804                         gIMMgr->addSession(
00805                                 buffer,
00806                                 IM_NOTHING_SPECIAL,
00807                                 agent_id);
00808                 }
00809                 else
00810                 {
00811                         // Group IM
00812                         LLUUID session_id;
00813                         session_id.generate();
00814                         gIMMgr->setFloaterOpen(TRUE);
00815                         gIMMgr->addSession("Avatars Conference", IM_SESSION_CONFERENCE_START, ids[0], ids);
00816                 }
00817         }
00818 }
00819 
00820 void LLFloaterAvatarList::onClickTrack(void *userdata)
00821 {
00822         LLFloaterAvatarList *avlist = (LLFloaterAvatarList*)userdata;
00823         
00824         LLScrollListItem *item =   avlist->mAvatarList->getFirstSelected();
00825         if (!item) return;
00826 
00827         LLUUID agent_id = item->getUUID();
00828 
00829         if ( avlist->mTracking && avlist->mTrackedAvatar == agent_id ) {
00830                 LLTracker::stopTracking(NULL);
00831                 avlist->mTracking = FALSE;
00832         }
00833         else
00834         {
00835                 avlist->mTracking = TRUE;
00836                 avlist->mTrackByLocation = FALSE;
00837                 avlist->mTrackedAvatar = agent_id;
00838                 LLTracker::trackAvatar(agent_id, avlist->mAvatars[agent_id].getName());
00839         }
00840 }
00841 
00842 void LLFloaterAvatarList::sendAvatarPropertiesRequest(LLUUID avid)
00843 {
00844         
00845 
00846         lldebugs << "LLPanelAvatar::sendAvatarPropertiesRequest()" << llendl; 
00847         LLMessageSystem *msg = gMessageSystem;
00848 
00849         msg->newMessageFast(_PREHASH_AvatarPropertiesRequest);
00850         msg->nextBlockFast( _PREHASH_AgentData);
00851         msg->addUUIDFast(   _PREHASH_AgentID, gAgent.getID() );
00852         msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
00853         msg->addUUIDFast(   _PREHASH_AvatarID, avid);
00854         gAgent.sendReliableMessage();
00855 
00856         mAvatars[avid].mAvatarInfo.requestStarted();
00857 }
00858 
00859 // static
00860 void LLFloaterAvatarList::processAvatarPropertiesReply(LLMessageSystem *msg, void**)
00861 {
00862 
00863         
00864         LLFloaterAvatarList* self = NULL;
00865         LLAvatarInfo avinfo;
00866 
00867         BOOL    identified = FALSE;
00868         BOOL    transacted = FALSE;
00869 
00870         LLUUID  agent_id;       // your id
00871         LLUUID  avatar_id;      // target of this panel
00872         U32     flags = 0x0;
00873         char    born_on[DB_BORN_BUF_SIZE];
00874         S32     charter_member_size = 0;
00875 
00876         msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
00877         msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AvatarID, avatar_id );
00878 
00879         
00880         self = gFloaterAvatarList;
00881 
00882         // Verify that the avatar is in the list, if not, ignore.
00883         if ( self->mAvatarList->getItemIndex(avatar_id) < 0 )
00884         {
00885                 return;
00886         }
00887 
00888         LLAvatarListEntry *entry = &self->mAvatars[avatar_id];
00889 
00890         msg->getStringFast(_PREHASH_PropertiesData, _PREHASH_BornOn, DB_BORN_BUF_SIZE, born_on);
00891         msg->getU32Fast(_PREHASH_PropertiesData, _PREHASH_Flags, flags);
00892 
00893         identified = (flags & AVATAR_IDENTIFIED);
00894         transacted = (flags & AVATAR_TRANSACTED);
00895 
00896         // What's this?
00897         // Let's see if I understand correctly: CharterMember property is dual purpose:
00898         // it either contains a number indicating an account type (usual value), or 
00899         // it contains a string with a custom title. Probably that's where Philip Linden's
00900         // "El Presidente" title comes from. Heh.
00901         U8 caption_index = 0;
00902         LLString caption_text;
00903         charter_member_size = msg->getSize("PropertiesData", "CharterMember");
00904 
00905         if(1 == charter_member_size)
00906         {
00907                 msg->getBinaryData("PropertiesData", "CharterMember", &caption_index, 1);
00908         }
00909         else if(1 < charter_member_size)
00910         {
00911                 char caption[MAX_STRING];
00912                 msg->getString("PropertiesData", "CharterMember", MAX_STRING, caption);
00913 
00914                 caption_text = caption;
00915                 entry->setAccountCustomTitle(caption_text);
00916         }
00917                 
00918 
00919         if(caption_text.empty())
00920         {
00921                 
00922                 const enum ACCOUNT_TYPE ACCT_TYPE[] = {
00923                         ACCOUNT_RESIDENT,
00924                         ACCOUNT_TRIAL,
00925                         ACCOUNT_CHARTER_MEMBER,
00926                         ACCOUNT_EMPLOYEE
00927                 };
00928 
00929                 //enum ACCOUNT_TYPE acct =
00930                 avinfo.Account =  ACCT_TYPE[llclamp(caption_index, (U8)0, (U8)(sizeof(ACCT_TYPE)/sizeof(ACCT_TYPE[0])-1))];
00931                 //entry->setAccountType(acct);
00932 
00933                 
00934                 if ( avinfo.Account != ACCOUNT_EMPLOYEE )
00935                 {
00936                         if ( transacted )
00937                         {
00938                                 avinfo.Payment = PAYMENT_USED;
00939                         }
00940                         else if ( identified )
00941                         {
00942                                 avinfo.Payment = PAYMENT_ON_FILE;
00943                         }
00944                         else
00945                         {
00946                                 avinfo.Payment = PAYMENT_NONE;
00947                         }
00948                 }
00949                 else
00950                 {
00951                         avinfo.Payment = PAYMENT_LINDEN;
00952                 }
00953         }
00954         
00955         // Structure must be zeroed to have sane results, as we
00956         // have an incomplete string for input
00957         memset(&avinfo.BirthDate, 0, sizeof(avinfo.BirthDate));
00958 
00959         int num_read = sscanf(born_on, "%d/%d/%d", &avinfo.BirthDate.tm_mon,
00960                                                    &avinfo.BirthDate.tm_mday,
00961                                                    &avinfo.BirthDate.tm_year);
00962 
00963         if ( num_read == 3 && avinfo.BirthDate.tm_mon <= 12 )
00964         {
00965                 avinfo.BirthDate.tm_year -= 1900;
00966                 avinfo.BirthDate.tm_mon--;
00967         }
00968         else
00969         {
00970                 // Zero again to remove any partially read data
00971                 memset(&avinfo.BirthDate, 0, sizeof(avinfo.BirthDate));
00972                 llwarns << "Error parsing birth date: " << born_on << llendl;
00973         }
00974 
00975         entry->mAvatarInfo.setValue(avinfo);
00976 }
00977 
00978 void LLFloaterAvatarList::checkTrackingStatus()
00979 {
00980 
00981         if ( mTracking && LLTracker::getTrackedPositionGlobal().isExactlyZero() )
00982         {
00983                 // trying to track an avatar, but tracker stopped tracking              
00984                 if ( mAvatars.count( mTrackedAvatar ) > 0 && !mTrackByLocation )
00985                 {
00986                         llinfos << "Switching to location-based tracking" << llendl;
00987                         mTrackByLocation = TRUE;
00988                 }
00989                 else
00990                 {
00991                         // not found
00992                         llinfos << "Stopping tracking avatar, server-side didn't work, and not in list anymore." << llendl;
00993                         LLTracker::stopTracking(NULL);
00994                         mTracking = FALSE;
00995                 }
00996         }
00997 
00998         if ( mTracking && mTrackByLocation )
00999         {
01000                 LLString name = mAvatars[mTrackedAvatar].getName();
01001                 LLString tooltip = "Tracking last known position";
01002                 name += " (near)";
01003                 LLTracker::trackLocation(mAvatars[mTrackedAvatar].getPosition(), name, tooltip);
01004         }
01005 
01006         //llinfos << "Tracking position: " << LLTracker::getTrackedPositionGlobal() << llendl;
01007         
01008 }
01009 
01010 
01011 BOOL  LLFloaterAvatarList::avatarIsInList(LLUUID avatar)
01012 {
01013         return ( mAvatars.count( avatar ) > 0 );
01014 }
01015 
01016 LLAvatarListEntry * LLFloaterAvatarList::getAvatarEntry(LLUUID avatar)
01017 {
01018         if ( avatar.isNull() )
01019         {
01020                 return NULL;
01021         }
01022 
01023         std::map<LLUUID, LLAvatarListEntry>::iterator iter;
01024 
01025         iter = mAvatars.find(avatar);
01026         if ( iter == mAvatars.end() )
01027         {
01028                 return NULL;
01029         }
01030 
01031         return &iter->second;   
01032         
01033         //if ( mAvatars.count( avatar ) < 0 )
01034         //{
01035                 //return NULL;
01036         //}
01037 
01038         //return &mAvatars[avatar];
01039 }
01040 
01041 void LLFloaterAvatarList::speakText(S32 channel, EChatType type, LLString text)
01042 {
01043         LLMessageSystem* msg = gMessageSystem;
01044 
01045         msg->newMessageFast(_PREHASH_ChatFromViewer);
01046         msg->nextBlockFast(_PREHASH_AgentData);
01047         msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
01048         msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
01049         msg->nextBlockFast(_PREHASH_ChatData);
01050         msg->addStringFast(_PREHASH_Message, text);
01051         msg->addU8Fast(_PREHASH_Type, type);
01052         msg->addS32("Channel", channel);
01053 
01054         gAgent.sendReliableMessage();
01055 
01056         gViewerStats->incStat(LLViewerStats::ST_CHAT_COUNT);
01057 }
01058 
01059 
01060 void LLFloaterAvatarList::requestTrustNetScore(LLUUID avatar, const LLString name, const LLString type)
01061 {
01062         char *temp = new char[UUID_STR_LENGTH];
01063         avatar.toString(temp);
01064 
01065         LLString text = "GetScore|" + name + "|" + temp + "|" + type;
01066         speakText(TRUSTNET_CHANNEL, CHAT_TYPE_WHISPER, text);
01067 }
01068 
01069 //static
01070 void LLFloaterAvatarList::replaceVars(LLString &str, LLUUID avatar, const LLString& name)
01071 {
01072         char *temp = new char[UUID_STR_LENGTH];
01073         avatar.toString(temp);
01074 
01075         LLString vars[][2] = {
01076                 {"$NAME", name},
01077                 {"$KEY",  temp},
01078         };
01079 
01080         BOOL replaced = TRUE;
01081 
01082         while( replaced )
01083         {
01084                 replaced = FALSE;
01085                 for(U32 i=0;i<sizeof(vars)/sizeof(vars[0]);i++)
01086                 {
01087                         U32 pos = str.find(vars[i][0]);
01088                         if ( pos != std::string::npos )
01089                         {
01090                                 str.replace(pos, vars[i][0].size(), vars[i][1]);
01091                                 replaced = TRUE;
01092                         }
01093                 }
01094         }
01095 
01096 }
01097 
01098 void LLFloaterAvatarList::requestMiscInfo(LLUUID avatar, const LLString name)
01099 {
01100         LLUUID   db_av_key;
01101 
01102         LLString message      = gSavedPerAccountSettings.getString("DBSendPattern");
01103         LLString db_av_name   = gSavedPerAccountSettings.getString("DBAvatarName");
01104         db_av_key.set(gSavedPerAccountSettings.getString("DBAvatarKey"));
01105 
01106         
01107         llinfos << "Requesting info " << llendl;
01108         replaceVars(message, avatar, name);
01109 
01110         llinfos << "Request string: " << message << llendl;
01111         send_simple_im(db_av_key, message.c_str());
01112  }
01113 
01114 //static
01115 BOOL LLFloaterAvatarList::handleIM(LLUUID from_id, const LLString message)
01116 {
01117         LLUUID   db_av_key;
01118         db_av_key.set(gSavedPerAccountSettings.getString("DBAvatarKey"));
01119 
01120         if ( db_av_key == from_id )
01121         {
01122                 std::map<LLUUID, LLAvatarListEntry>::iterator iter;
01123 
01124                 for(iter = gFloaterAvatarList->mAvatars.begin(); iter != gFloaterAvatarList->mAvatars.end(); iter++)
01125                 {
01126                         LLAvatarListEntry *ent = &iter->second;
01127                 
01128                         // Check if the key, or the name are found in the reply.
01129                         // Name is only accepted if it's in the beginning of the message.
01130                         if ( message.find(ent->getID().asString()) != std::string::npos
01131                              || message.find(ent->getName().c_str()) == 0 )
01132                         {
01133                                 LLMiscDBInfo info;
01134                                 info.data = message;
01135 
01136                                 llinfos << "Database reply arrived for avatar " << ent->getName() << llendl;
01137                                 ent->mMiscInfo.setValue(info);
01138                         }
01139                 }
01140 
01141                 return TRUE;
01142         }
01143         return FALSE;
01144 }
01145 
01146 //static
01147 void LLFloaterAvatarList::processTrustNetReply(char *reply)
01148 {
01149         char *tokens[10];
01150         char *tmp = &reply[0];
01151         U32 count = 0;
01152 
01153         llinfos << "TrustNet reply: " << reply << llendl;
01154         
01155 
01156         // Split into tokens
01157         while( (NULL != (tmp = strtok(tmp, "|"))) && count < (sizeof(tokens)/sizeof(tokens[0])) )
01158         {
01159                 tokens[count++] = tmp;
01160                 llinfos << "token: " << tmp << llendl;
01161                 tmp = NULL;
01162         }
01163 
01164         llinfos << "Got " << count << " tokens" << llendl;
01165 
01166         if ( count >= 1 )
01167         {
01168                 if (!strcmp(tokens[0], "Score") && count >= 4)
01169                 {
01170                         //format: key|type|score
01171                         LLUUID avatar(tokens[1]);
01172                         LLString type = tokens[2];
01173                         F32 score = (F32)strtod(tokens[3], NULL);
01174                         
01175                         LLAvatarListEntry *ent = gFloaterAvatarList->getAvatarEntry(avatar);
01176                         if ( ent != NULL )
01177                         {
01178                                 LLAvListTrustNetScore s(type, score);
01179                                 ent->mTrustNetScore.setValue(s);
01180                                 llinfos << "Score arrived for avatar " << avatar << ": " << score << llendl;
01181                         }
01182                         else
01183                         {
01184                                 llinfos << "Score arrived for avatar " << avatar << ", but it wasn't in the list anymore" << llendl;
01185                         }
01186                 }
01187                 else if (!strcmp(tokens[0], "WebAuthToken") && count >= 2)
01188                 {
01189                         LLString URL = LLWeb::escapeURL(llformat("http://trustnet.daleglass.net/?session=%s", tokens[1]));
01190                         LLWeb::loadURL(URL);
01191                 }
01192                 else if (!strcmp(tokens[0], "WebPassword") && count >= 2)
01193                 {
01194                         LLString password = tokens[1];
01195                         gViewerWindow->mWindow->copyTextToClipboard(utf8str_to_wstring(password));
01196                 }
01197                 else
01198                 {
01199                         llwarns << "Unrecognized TrustNet reply " << tokens[0] << llendl;
01200                 }
01201         }
01202 }
01203 
01204 void LLFloaterAvatarList::luskwoodCommand(LLString cmd)
01205 {
01206         LLDynamicArray<LLUUID> ids = mAvatarList->getSelectedIDs();
01207 
01208         for(LLDynamicArray<LLUUID>::iterator itr = ids.begin(); itr != ids.end(); ++itr)
01209         {
01210                 LLUUID avid = *itr;
01211                 LLAvatarListEntry *ent = getAvatarEntry(avid);
01212                 if ( ent != NULL )
01213                 {
01214                         //llinfos << "Would say: " << cmd << " " << ent->getName() << llendl;
01215                         // Use key got gokey, name for everything else
01216                         speakText(0, CHAT_TYPE_SHOUT, cmd + " " + ( cmd == "gokey" ? ent->getID().asString() :  ent->getName() ) );
01217                 }
01218         }
01219 }
01220 
01221 //static
01222 void LLFloaterAvatarList::onClickMark(void *userdata)
01223 {
01224         LLFloaterAvatarList *avlist = (LLFloaterAvatarList*)userdata;
01225         LLDynamicArray<LLUUID> ids = avlist->mAvatarList->getSelectedIDs();
01226 
01227         for(LLDynamicArray<LLUUID>::iterator itr = ids.begin(); itr != ids.end(); ++itr)
01228         {
01229                 LLUUID avid = *itr;
01230                 LLAvatarListEntry *ent = avlist->getAvatarEntry(avid);
01231                 if ( ent != NULL )
01232                 {
01233                         ent->toggleMark();
01234                 }
01235         }
01236 }
01237 
01238 void LLFloaterAvatarList::handleLuskwoodDialog(S32 option, void* data)
01239 {
01240         LLFloaterAvatarList *self = (LLFloaterAvatarList*)data;
01241         if ( 0 == option )
01242         {
01243                 self->luskwoodCommand(self->mLuskwoodCommand);
01244         }
01245 }
01246 
01247 void LLFloaterAvatarList::handleLuskwoodGohomerOffDialog(S32 option, void* data)
01248 {
01249         LLFloaterAvatarList *self = (LLFloaterAvatarList*)data;
01250         if ( 0 == option )
01251         {
01252                 self->speakText(0, CHAT_TYPE_SHOUT, "gohome off");
01253         }
01254 }
01255 
01256 //static
01257 void LLFloaterAvatarList::onClickGohomerWarn(void *data)
01258 {
01259         LLFloaterAvatarList *self = (LLFloaterAvatarList*)data;
01260 
01261         self->mLuskwoodCommand = "gowarn";
01262         gViewerWindow->alertXml("LuskwoodGohomerWarn", handleLuskwoodDialog, self);
01263 
01264 }
01265 
01266 //static
01267 void LLFloaterAvatarList::onClickGohomerEject(void *data)
01268 {
01269         LLFloaterAvatarList *self = (LLFloaterAvatarList*)data;
01270 
01271         self->mLuskwoodCommand = "goeject";
01272         gViewerWindow->alertXml("LuskwoodGohomerEject", handleLuskwoodDialog, self);
01273 }
01274 
01275 //static
01276 void LLFloaterAvatarList::onClickGohomerSendAway(void *data)
01277 {
01278         LLFloaterAvatarList *self = (LLFloaterAvatarList*)data;
01279 
01280         self->mLuskwoodCommand = "goaway";
01281         gViewerWindow->alertXml("LuskwoodGohomerKeepAway", handleLuskwoodDialog, self);
01282 }
01283 
01284 //static
01285 void LLFloaterAvatarList::onClickGohomerSendHome(void *data)
01286 {
01287         LLFloaterAvatarList *self = (LLFloaterAvatarList*)data;
01288 
01289         self->mLuskwoodCommand = "gohome";
01290         gViewerWindow->alertXml("LuskwoodGohomerSendHome", handleLuskwoodDialog, self);
01291 }
01292 
01293 //static
01294 void LLFloaterAvatarList::onClickGohomerSendHomeByKey(void *data)
01295 {
01296         LLFloaterAvatarList *self = (LLFloaterAvatarList*)data;
01297 
01298         self->mLuskwoodCommand = "gokey";
01299         gViewerWindow->alertXml("LuskwoodGohomerSendHome", handleLuskwoodDialog, self);
01300 }
01301 
01302 
01303 //static
01304 void LLFloaterAvatarList::onClickGohomerOff(void *data)
01305 {
01306         LLFloaterAvatarList *self = (LLFloaterAvatarList*)data;
01307 
01308         gViewerWindow->alertXml("LuskwoodGohomerOff", handleLuskwoodGohomerOffDialog, self);
01309 }
01310 
01311 LLColor4 LLFloaterAvatarList::getAvatarColor(LLAvatarListEntry *ent, F32 distance, e_coloring_type type)
01312 {
01313         F32 r = 0.0f, g = 0.0f, b = 0.0f, a = 1.0f;
01314 
01315         switch(type)
01316         {
01317                 case CT_NONE:
01318                         return LLColor4::black;
01319                         break;
01320                 case CT_DISTANCE:
01321                         if ( distance <= 10.0f )
01322                         {
01323                                 // whisper range
01324                                 g = 0.7f - ( distance / 20.0f );
01325                         }
01326                         else if ( distance > 10.0f && distance <= 20.0f )
01327                         {
01328                                 // talk range
01329                                 g = 0.7f - ( (distance - 10.0f) / 20.0f );
01330                                 b = g;
01331                         }
01332                         else if ( distance > 20.0f && distance <= 96.0f )
01333                         {
01334                                 // shout range
01335                                 r = 0.7f - ( (distance - 20.0f) / 192.0f );
01336                                 b = r;
01337                         }
01338                         else
01339                         {
01340                                 // unreachable by chat
01341                                 r = 1.0;
01342                         }
01343                         break;
01344                 case CT_AGE:
01345                         if ( ent->mAvatarInfo.getStatus() == DATA_RETRIEVED )
01346                         {
01347                                 S32 age = ent->mAvatarInfo.getValue().getAge();
01348                                 if ( age < 14 )
01349                                 {
01350                                         r = 0.7f - ( age / 28 );
01351                                 }
01352                                 else if ( age > 14 && age <= 30 )
01353                                 {
01354                                         r = 0.7f - ( (age-14) / 32 );
01355                                         g = r;
01356                                 }
01357                                 else if ( age > 30 && age < 90 )
01358                                 {
01359                                         g = 0.7f - ( (age-30) / 120 );
01360                                 }
01361                                 else
01362                                 {
01363                                         b = 1.0f;
01364                                 }
01365                         }
01366                         break;
01367                 case CT_SCORE:
01368                         if ( ent->mTrustNetScore.getStatus() == DATA_RETRIEVED )
01369                         {
01370                                 F32 score = ent->mTrustNetScore.getValue().Score;
01371 
01372                                 if ( score == 0.0 )
01373                                 {
01374                                         b = 1.0f;
01375                                 }
01376                                 else if ( score == 10.0f )
01377                                 {
01378                                         g = 1.0f;
01379                                 }
01380                                 else if ( score == -10.0f )
01381                                 {
01382                                         r = 1.0f;
01383                                 }
01384                                 else if ( score > 0.0f )
01385                                 {
01386                                         g = 0.2f + ( score / 20.0f );
01387                                 }
01388                                 else if ( score < 0.0f )
01389                                 { 
01390                                         r = 0.2f + ( score / 20.0f );
01391                                 }
01392                         }
01393                         break;
01394                 case CT_PAYMENT:
01395                         break;
01396         }
01397 
01398         return LLColor4(r,g,b,a);
01399 }
01400 
01401 void LLFloaterAvatarList::onDoubleClick(void *userdata)
01402 {
01403         LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata;
01404         LLScrollListItem *item =   self->mAvatarList->getFirstSelected();
01405         LLUUID agent_id = item->getUUID();
01406 
01407         gAgent.lookAtObject(agent_id, CAMERA_POSITION_OBJECT);
01408 }
01409 
01410 void LLFloaterAvatarList::removeFocusFromAll()
01411 {
01412         std::map<LLUUID, LLAvatarListEntry>::iterator iter;
01413 
01414         for(iter = mAvatars.begin(); iter != mAvatars.end(); iter++)
01415         {
01416                 LLAvatarListEntry *ent = &iter->second;
01417                 ent->setFocus(FALSE);
01418         }
01419 }
01420 
01421 void LLFloaterAvatarList::focusOnPrev(BOOL marked_only)
01422 {
01423         std::map<LLUUID, LLAvatarListEntry>::iterator iter;
01424         LLAvatarListEntry *prev = NULL;
01425         LLAvatarListEntry *ent;
01426 
01427         if ( mAvatars.size() == 0 )
01428         {
01429                 return;
01430         }
01431 
01432         for(iter = mAvatars.begin(); iter != mAvatars.end(); iter++)
01433         {
01434                 ent = &iter->second;
01435 
01436                 if ( ent->isDead() )
01437                         continue;
01438 
01439                 if ( (ent->getID() == mFocusedAvatar) && (prev != NULL)  )
01440                 {
01441                         removeFocusFromAll();
01442                         prev->setFocus(TRUE);
01443                         mFocusedAvatar = prev->getID();
01444                         gAgent.lookAtObject(mFocusedAvatar, CAMERA_POSITION_OBJECT);
01445                         return;
01446                 }
01447 
01448                 if ( (!marked_only) || ent->isMarked() )
01449                 {
01450                         prev = ent;
01451                 }
01452         }
01453 
01454         if (prev != NULL && ((!marked_only) || prev->isMarked()) )
01455         {
01456                 removeFocusFromAll();
01457                 prev->setFocus(TRUE);
01458                 mFocusedAvatar = prev->getID();
01459                 gAgent.lookAtObject(mFocusedAvatar, CAMERA_POSITION_OBJECT);
01460         }
01461 }
01462 
01463 void LLFloaterAvatarList::focusOnNext(BOOL marked_only)
01464 {
01465 
01466         
01467         std::map<LLUUID, LLAvatarListEntry>::iterator iter;
01468         BOOL found = FALSE;
01469         LLAvatarListEntry *first = NULL;
01470         LLAvatarListEntry *ent;
01471 
01472         if ( mAvatars.size() == 0 )
01473         {
01474                 return;
01475         }
01476 
01477         for(iter = mAvatars.begin(); iter != mAvatars.end(); iter++)
01478         {
01479                 ent = &iter->second;
01480 
01481                 if ( ent->isDead() )
01482                         continue;
01483 
01484                 if ( NULL == first && ((!marked_only) || ent->isMarked()))
01485                 {
01486                         first = ent;
01487                 }
01488 
01489                 if ( found && ((!marked_only) || ent->isMarked()) )
01490                 {
01491                         removeFocusFromAll();
01492                         ent->setFocus(TRUE);
01493                         mFocusedAvatar = ent->getID();
01494                         gAgent.lookAtObject(mFocusedAvatar, CAMERA_POSITION_OBJECT);
01495                         return;
01496                 }
01497 
01498                 if ( ent->getID() == mFocusedAvatar )
01499                 {
01500                         found = TRUE;
01501                 } 
01502         }
01503 
01504         if (first != NULL && ((!marked_only) || first->isMarked()))
01505         {
01506                 removeFocusFromAll();
01507                 first->setFocus(TRUE);
01508                 mFocusedAvatar = first->getID();
01509                 gAgent.lookAtObject(mFocusedAvatar, CAMERA_POSITION_OBJECT);
01510         }
01511 }
01512 //static
01513 void LLFloaterAvatarList::onClickPrevInList(void *userdata)
01514 {
01515         LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata;
01516         self->focusOnPrev(FALSE);
01517 }
01518 
01519 //static
01520 void LLFloaterAvatarList::onClickNextInList(void *userdata)
01521 {
01522         LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata;
01523         self->focusOnNext(FALSE);
01524 }
01525 
01526 //static
01527 void LLFloaterAvatarList::onClickPrevMarked(void *userdata)
01528 {
01529         LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata;
01530         self->focusOnPrev(TRUE);
01531 }
01532 
01533 //static
01534 void LLFloaterAvatarList::onClickNextMarked(void *userdata)
01535 {
01536         LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata;
01537         self->focusOnNext(TRUE);
01538 }
01539 
01540 //static
01541 void LLFloaterAvatarList::onClickTrustNetRate(void *userdata)
01542 {
01543         // LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata;
01544         llinfos << "Ratings not implemented yet" << llendl;
01545 }
01546 
01547 //static
01548 void LLFloaterAvatarList::onClickTrustNetExplain(void *userdata)
01549 {
01550         LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata;
01551         LLScrollListItem *item =   self->mAvatarList->getFirstSelected();
01552 
01553         if ( item != NULL )
01554         {
01555                 LLAvatarListEntry *ent = self->getAvatarEntry(item->getUUID());
01556                 self->speakText(TRUSTNET_CHANNEL, CHAT_TYPE_WHISPER, "Explain|" + ent->getName() + "|" + ent->getID().asString());
01557         }
01558 }
01559 
01560 //static
01561 void LLFloaterAvatarList::onClickTrustNetWebsite(void *userdata)
01562 {
01563         LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata;
01564 
01565         self->speakText(TRUSTNET_CHANNEL, CHAT_TYPE_WHISPER, "GetWebAuthToken");
01566 }
01567 
01568 //static
01569 void LLFloaterAvatarList::onClickTrustNetGetPassword(void *userdata)
01570 {
01571         LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata;
01572 
01573         self->speakText(TRUSTNET_CHANNEL, CHAT_TYPE_WHISPER, "GetWebPassword");
01574 }
01575 
01576 //static
01577 void LLFloaterAvatarList::onClickTrustNetRenew(void *userdata)
01578 {
01579         LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata;
01580         self->speakText(TRUSTNET_CHANNEL, CHAT_TYPE_WHISPER, "RenewSubscription");
01581 }
01582 
01583 //static
01584 void LLFloaterAvatarList::onClickGetKey(void *userdata)
01585 {
01586         LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata;
01587         LLScrollListItem *item = self->mAvatarList->getFirstSelected();
01588 
01589         if ( NULL == item ) return;
01590 
01591         LLUUID agent_id = item->getUUID();
01592 
01593         char buffer[UUID_STR_LENGTH];           /*Flawfinder: ignore*/
01594         agent_id.toString(buffer);
01595 
01596         gViewerWindow->mWindow->copyTextToClipboard(utf8str_to_wstring(buffer));
01597 }
01598 
01599 
01600 static void send_freeze(const LLUUID& avatar_id, bool freeze)
01601 {
01602         U32 flags = 0x0;
01603         if (!freeze)
01604         {
01605                 // unfreeze
01606                 flags |= 0x1;
01607         }
01608 
01609         LLMessageSystem* msg = gMessageSystem;
01610         LLViewerObject* avatar = gObjectList.findObject(avatar_id);
01611 
01612         if (avatar)
01613         {
01614                 msg->newMessage("FreezeUser");
01615                 msg->nextBlock("AgentData");
01616                 msg->addUUID("AgentID", gAgent.getID());
01617                 msg->addUUID("SessionID", gAgent.getSessionID());
01618                 msg->nextBlock("Data");
01619                 msg->addUUID("TargetID", avatar_id );
01620                 msg->addU32("Flags", flags );
01621                 msg->sendReliable( avatar->getRegion()->getHost() );
01622         }
01623 }
01624 
01625 static void send_eject(const LLUUID& avatar_id, bool ban)
01626 {       
01627         LLMessageSystem* msg = gMessageSystem;
01628         LLViewerObject* avatar = gObjectList.findObject(avatar_id);
01629 
01630         if (avatar)
01631         {
01632                 U32 flags = 0x0;
01633                 if ( ban )
01634                 {
01635                         // eject and add to ban list
01636                         flags |= 0x1;
01637                 }
01638 
01639                 msg->newMessage("EjectUser");
01640                 msg->nextBlock("AgentData");
01641                 msg->addUUID("AgentID", gAgent.getID() );
01642                 msg->addUUID("SessionID", gAgent.getSessionID() );
01643                 msg->nextBlock("Data");
01644                 msg->addUUID("TargetID", avatar_id );
01645                 msg->addU32("Flags", flags );
01646                 msg->sendReliable( avatar->getRegion()->getHost() );
01647         }
01648 }
01649 
01650 static void send_estate_message(
01651         const char* request,
01652         const LLUUID &target)
01653 {
01654 
01655         LLMessageSystem* msg = gMessageSystem;
01656         LLUUID invoice;
01657 
01658         // This seems to provide an ID so that the sim can say which request it's
01659         // replying to. I think this can be ignored for now.
01660         invoice.generate();
01661 
01662         llinfos << "Sending estate request '" << request << "'" << llendl;
01663         msg->newMessage("EstateOwnerMessage");
01664         msg->nextBlockFast(_PREHASH_AgentData);
01665         msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
01666         msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
01667         msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); //not used
01668         msg->nextBlock("MethodData");
01669         msg->addString("Method", request);
01670         msg->addUUID("Invoice", invoice);
01671 
01672         // Agent id
01673         msg->nextBlock("ParamList");
01674         msg->addString("Parameter", gAgent.getID().asString().c_str());
01675 
01676         // Target
01677         msg->nextBlock("ParamList");
01678         msg->addString("Parameter", target.asString().c_str());
01679 
01680         msg->sendReliable(gAgent.getRegion()->getHost());
01681 }
01682 
01683 static void send_estate_ban(const LLUUID& agent)
01684 {
01685         LLUUID invoice;
01686         U32 flags = ESTATE_ACCESS_BANNED_AGENT_ADD;
01687 
01688         invoice.generate();
01689 
01690         LLMessageSystem* msg = gMessageSystem;
01691         msg->newMessage("EstateOwnerMessage");
01692         msg->nextBlockFast(_PREHASH_AgentData);
01693         msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
01694         msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
01695         msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); //not used
01696 
01697         msg->nextBlock("MethodData");
01698         msg->addString("Method", "estateaccessdelta");
01699         msg->addUUID("Invoice", invoice);
01700 
01701         char buf[MAX_STRING];           /* Flawfinder: ignore*/
01702         gAgent.getID().toString(buf);
01703         msg->nextBlock("ParamList");
01704         msg->addString("Parameter", buf);
01705 
01706         snprintf(buf, MAX_STRING, "%u", flags);                 /* Flawfinder: ignore */
01707         msg->nextBlock("ParamList");
01708         msg->addString("Parameter", buf);
01709 
01710         agent.toString(buf);
01711         msg->nextBlock("ParamList");
01712         msg->addString("Parameter", buf);
01713 
01714         gAgent.sendReliableMessage();
01715 }
01716 
01717 static void cmd_freeze(const LLUUID& avatar, const LLString &name)      { send_freeze(avatar, true); }
01718 static void cmd_unfreeze(const LLUUID& avatar, const LLString &name)    { send_freeze(avatar, false); }
01719 static void cmd_eject(const LLUUID& avatar, const LLString &name)       { send_eject(avatar, false); }
01720 static void cmd_ban(const LLUUID& avatar, const LLString &name)         { send_eject(avatar, true); }
01721 static void cmd_profile(const LLUUID& avatar, const LLString &name)     { LLFloaterAvatarInfo::showFromDirectory(avatar); }
01722 static void cmd_mute(const LLUUID&avatar, const LLString &name)         { gMuteListp->add(LLMute(avatar, name, LLMute::AGENT)); }
01723 static void cmd_unmute(const LLUUID&avatar, const LLString &name)       { gMuteListp->remove(LLMute(avatar, name, LLMute::AGENT)); }
01724 static void cmd_estate_eject(const LLUUID &avatar, const LLString &name){ send_estate_message("teleporthomeuser", avatar); }
01725 static void cmd_estate_ban(const LLUUID &avatar, const LLString &name)
01726 {
01727         send_estate_message("teleporthomeuser", avatar); // Kick first, just to be sure
01728         send_estate_ban(avatar);
01729 }
01730 
01731 void LLFloaterAvatarList::doCommand(void (*func)(const LLUUID &avatar, const LLString &name))
01732 {
01733         LLDynamicArray<LLUUID> ids = mAvatarList->getSelectedIDs();
01734 
01735         for(LLDynamicArray<LLUUID>::iterator itr = ids.begin(); itr != ids.end(); ++itr)
01736         {
01737                 LLUUID avid = *itr;
01738                 LLAvatarListEntry *ent = getAvatarEntry(avid);
01739                 if ( ent != NULL )
01740                 {
01741                         llinfos << "Executing command on " << ent->getName() << llendl;
01742                         func(avid, ent->getName());
01743                 }
01744         }
01745 }
01746 
01747 LLString LLFloaterAvatarList::getSelectedNames(const LLString& separator)
01748 {
01749         LLString ret = "";
01750         
01751         LLDynamicArray<LLUUID> ids = mAvatarList->getSelectedIDs();
01752         for(LLDynamicArray<LLUUID>::iterator itr = ids.begin(); itr != ids.end(); ++itr)
01753         {
01754                 LLUUID avid = *itr;
01755                 LLAvatarListEntry *ent = getAvatarEntry(avid);
01756                 if ( ent != NULL )
01757                 {
01758                         if (!ret.empty()) ret += separator;
01759                         ret += ent->getName();
01760                 }
01761         }
01762 
01763         return ret;
01764 }
01765 
01766 //static 
01767 void LLFloaterAvatarList::callbackFreeze(S32 option, void *userdata) { 
01768         LLFloaterAvatarList *avlist = (LLFloaterAvatarList*)userdata;
01769 
01770         if ( option == 0 )
01771         {
01772                 avlist->doCommand(cmd_freeze);
01773         }
01774         else if ( option == 1 )
01775         {
01776                 avlist->doCommand(cmd_unfreeze);
01777         }
01778 }
01779 
01780 //static 
01781 void LLFloaterAvatarList::callbackEject(S32 option, void *userdata) {
01782         LLFloaterAvatarList *avlist = (LLFloaterAvatarList*)userdata;
01783  
01784         if ( option == 0 )
01785         {
01786                 avlist->doCommand(cmd_eject);
01787         }
01788         else if ( option == 1 )
01789         {
01790                 avlist->doCommand(cmd_ban);
01791         }
01792 }
01793 
01794 //static 
01795 void LLFloaterAvatarList::callbackMute(S32 option, void *userdata) {
01796         LLFloaterAvatarList *avlist = (LLFloaterAvatarList*)userdata;
01797 
01798         if ( option == 0 )
01799         {
01800                 avlist->doCommand(cmd_mute);
01801         } 
01802         else if ( option == 1 )
01803         {
01804                 avlist->doCommand(cmd_unmute);
01805         }
01806 }
01807 
01808 //static 
01809 void LLFloaterAvatarList::callbackEjectFromEstate(S32 option, void *userdata) {
01810         LLFloaterAvatarList *avlist = (LLFloaterAvatarList*)userdata;
01811 
01812         if ( option == 0 )
01813         {
01814                 avlist->doCommand(cmd_estate_eject);
01815         } 
01816         else if ( option == 1 )
01817         {
01818                 avlist->doCommand(cmd_estate_ban);
01819         }
01820 }
01821 
01822 //static
01823 void LLFloaterAvatarList::onClickFreeze(void *userdata)
01824 {
01825         LLStringBase<char>::format_map_t args;
01826         args["[NAMES]"] = ((LLFloaterAvatarList*)userdata)->getSelectedNames();
01827         gViewerWindow->alertXml("AvatarListFreezeAvatars", args, callbackFreeze, userdata);
01828 }
01829 
01830 //static
01831 void LLFloaterAvatarList::onClickEject(void *userdata)
01832 {
01833         LLStringBase<char>::format_map_t args;
01834         args["[NAMES]"] = ((LLFloaterAvatarList*)userdata)->getSelectedNames();
01835         gViewerWindow->alertXml("AvatarListEjectAvatars", args, callbackEject, userdata);
01836 }
01837 
01838 //static
01839 void LLFloaterAvatarList::onClickMute(void *userdata)
01840 {
01841         LLStringBase<char>::format_map_t args;
01842         args["[NAMES]"] = ((LLFloaterAvatarList*)userdata)->getSelectedNames();
01843         gViewerWindow->alertXml("AvatarListMuteAvatars", args, callbackMute, userdata);
01844 }
01845 
01846 //static
01847 void LLFloaterAvatarList::onClickEjectFromEstate(void *userdata)
01848 {
01849         LLStringBase<char>::format_map_t args;
01850         args["[NAMES]"] = ((LLFloaterAvatarList*)userdata)->getSelectedNames();
01851         gViewerWindow->alertXml("AvatarListEjectAvatarsFromEstate", args, callbackEjectFromEstate, userdata);
01852 }
01853 
01854 
01855 
01856 //static
01857 void LLFloaterAvatarList::onClickAR(void *userdata)
01858 {
01859         LLFloaterAvatarList *avlist = (LLFloaterAvatarList*)userdata;
01860         LLDynamicArray<LLUUID> ids = avlist->mAvatarList->getSelectedIDs();
01861 
01862         for(LLDynamicArray<LLUUID>::iterator itr = ids.begin(); itr != ids.end(); ++itr)
01863         {
01864                 LLUUID avid = *itr;
01865                 llinfos << "Adding " << avid << " to AR queue" << llendl;
01866                 avlist->mARQueue.push( avid );
01867         }
01868 }
01869 
01870 // static
01871 void LLFloaterAvatarList::onClickProfile(void* userdata)
01872 {
01873         LLFloaterAvatarList *avlist = (LLFloaterAvatarList*)userdata;
01874         avlist->doCommand(cmd_profile);
01875 }
01876 
01877 //static
01878 void LLFloaterAvatarList::onClickTeleport(void* userdata)
01879 {
01880         LLFloaterAvatarList *avlist = (LLFloaterAvatarList*)userdata;
01881         LLScrollListItem *item =   avlist->mAvatarList->getFirstSelected();
01882 
01883         if ( item )
01884         {
01885                 LLUUID agent_id = item->getUUID();
01886                 LLAvatarListEntry *ent = avlist->getAvatarEntry(agent_id);
01887                 
01888                 if ( ent )
01889                 {
01890                         llinfos << "Trying to teleport to " << ent->getName() << " at " << ent->getPosition() << llendl;
01891                         gAgent.teleportViaLocation( ent->getPosition() );
01892                 }
01893         }
01894 }

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