User:Antony Fairport/Scripts/Last Login Tracker

From Second Life Wiki
Jump to navigation Jump to search

I wrote this when some friends were having problems with their internet connection. They run a bot and that bot's online/offline status was a good indication as to how long it was since they'd lost their connection. Since then I've found it handy for helping me get hold of customers who have different online times to me.

To use it, make a prim and drop this script in. Also drop in a notecard called Keys which has the UUID (one per line) of the avatars you want to track.

Note that the time is always recorded and displayed in UTC. Converting that to your local time is left as an exercise for the reader. ;-)

//////////////////////////////////////////////////////////////////////
// Last online scanner -- see when given avatars were last online
// By Antony Fairport.
//
// Revision history.
// =================
//
// 2011-05-07
// Initial version.

//////////////////////////////////////////////////////////////////////
// Constants.
float  REFRESH_INTERVAL = 10.0;
string KEY_FILE         = "Keys";

//////////////////////////////////////////////////////////////////////
// Globals.
integer g_iMaxTracking;
integer g_iCurrent;
list    g_lTracking;
list    g_lUserNames;
list    g_lDisplayNames;
list    g_lLastSeen;
key     g_keyRequest;
key     g_keyKey;
integer g_iKey;

//////////////////////////////////////////////////////////////////////
// Return a string that is the report of last online times.
string LastOnlineReport()
{
    string s = "";
    integer i;

    for ( i = 0; i < g_iMaxTracking; i++ )
    {
        string sUN   = llList2String( g_lUserNames, i );
        string sDN   = llList2String( g_lDisplayNames, i );
        string sName = sDN;
        
        if ( sUN != sDN )
        {
            sName = sDN + " (" + sUN + ")";
        }
    
        s += sName + " : " + llList2String( g_lLastSeen, i ) + "\n";
    }
    
    return s;
}

//////////////////////////////////////////////////////////////////////
// Format a llGetTimestamp()
string FormatTime( string sTime )
{
    list l = llParseString2List( sTime, [ "T", "." ], [] );
    
    return llList2String( l, 0 ) + " " + llList2String( l, 1 ) + " UTC";
}

//////////////////////////////////////////////////////////////////////
// Default state.
default
{
    //////////////////////////////////////////////////////////////////
    // State entry.
    state_entry()
    {
        // Simply jump to the setup state.
        state Setup;
    }
}

//////////////////////////////////////////////////////////////////////
// Setup state.
state Setup
{
    //////////////////////////////////////////////////////////////////
    // State entry.
    state_entry()
    {
        // Let the user know what's happening.
        llSetText( "Reading list of keys to track, please wait...", < 1.0, 0.0, 0.0 >, 1.0 );

        // Clear out the lists and get the tracking list length.        
        g_lTracking     = [];
        g_lUserNames    = [];
        g_lDisplayNames = [];
        g_lLastSeen     = [];
        
        // If we have the keys file...
        if ( llGetInventoryType( KEY_FILE ) == INVENTORY_NOTECARD )
        {
            // Start reading.
            g_keyKey = llGetNotecardLine( KEY_FILE, g_iKey = 0 );
        }
    }
    
    //////////////////////////////////////////////////////////////////
    // Handle data server responses.
    dataserver( key queryid, string data )
    {
        // If this is our query...
        if ( queryid == g_keyKey )
        {
            // If this isn't the end of the file...
            if ( data != EOF )
            {
                // If the data looks like a key...
                if ( ( data != "" ) && ( ( (key) data ) != NULL_KEY ) )
                {
                    // Extend the lists.
                    g_lTracking     += [ data ];
                    g_lUserNames    += [ "" ];
                    g_lDisplayNames += [ "" ];
                    g_lLastSeen     += [ "No login" ];
                }
                
                // Next key...
                g_keyKey = llGetNotecardLine( KEY_FILE, ++g_iKey );
            }
            else
            {
                // Record how many we're tracking.
                g_iMaxTracking  = llGetListLength( g_lTracking );

                // Start by getting user names...
                state SetupUserNames;        
            }
        }
    }
}

//////////////////////////////////////////////////////////////////////
// User name setup state.
state SetupUserNames
{
    //////////////////////////////////////////////////////////////////
    // State entry.
    state_entry()
    {
        // Let the user know what's happening.
        llSetText( "Getting user names, plase wait...", < 1.0, 0.0, 0.0 >, 1.0 );
        
        // Starting with the first entry in the tracking list...
        g_iCurrent = 0;
        
        // Start getting user names...
        g_keyRequest = llRequestAgentData( llList2Key( g_lTracking, g_iCurrent ), DATA_NAME );
    }
    
    //////////////////////////////////////////////////////////////////
    // Handle data server responses.
    dataserver( key queryid, string data )
    {
        // If this is our query...
        if ( queryid == g_keyRequest )
        {
            // Put the name into the list.
            g_lUserNames = llListReplaceList( g_lUserNames, [ data ], g_iCurrent, g_iCurrent );
            
            // Move on.
            g_iCurrent++;
            
            // If we've got some names left to get...
            if ( g_iCurrent < g_iMaxTracking )
            {
                // Get the next name...
                g_keyRequest = llRequestAgentData( llList2Key( g_lTracking, g_iCurrent ), DATA_NAME );
            }
            else
            {
                // Now we get display names.
                state SetupDisplayNames;
            }
        }
    }
}

//////////////////////////////////////////////////////////////////////
// Display name setup state.
state SetupDisplayNames
{
    //////////////////////////////////////////////////////////////////
    // State entry.
    state_entry()
    {
        // Let the user know what's happening.
        llSetText( "Getting display names, please wait...", < 1.0, 0.0, 0.0 >, 1.0 );
        
        // Starting with the first entry in the tracking list...
        g_iCurrent = 0;
        
        // Start getting display names...
        g_keyRequest = llRequestDisplayName( llList2Key( g_lTracking, g_iCurrent ) );
    }
    
    //////////////////////////////////////////////////////////////////
    // Handle data server responses.
    dataserver( key queryid, string data )
    {
        // If this is our query...
        if ( queryid == g_keyRequest )
        {
            // Put the name into the list.
            g_lDisplayNames = llListReplaceList( g_lDisplayNames, [ data ], g_iCurrent, g_iCurrent );
            
            // Move on.
            g_iCurrent++;
            
            // If we've got some names left to get...
            if ( g_iCurrent < g_iMaxTracking )
            {
                // Get the next name...
                g_keyRequest = llRequestDisplayName( llList2Key( g_lTracking, g_iCurrent ) );
            }
            else
            {
                llSetText( "Starting online scanner, please wait...", < 0.0, 1.0, 0.0 >, 1.0 );
                
                // Now we can start online scanning.
                state OnlineScanner;
            }
        }
    }
}

//////////////////////////////////////////////////////////////////////
// The online scanner state.
state OnlineScanner
{
    //////////////////////////////////////////////////////////////////
    // State entry.
    state_entry()
    {
        // Starting with the first entry in the tracking list...
        g_iCurrent = 0;
        
        // Start getting the online status.
        g_keyRequest = llRequestAgentData( llList2Key( g_lTracking, g_iCurrent ), DATA_ONLINE );
    }

    //////////////////////////////////////////////////////////////////
    // Handle data server responses.
    dataserver( key queryid, string data )
    {
        // If this is our query...
        if ( queryid == g_keyRequest )
        {
            // If the avatar is online...
            if ( data == "1" )
            {
                // Update their last seen value.
                g_lLastSeen = llListReplaceList( g_lLastSeen, [ FormatTime( llGetTimestamp() ) ], g_iCurrent, g_iCurrent );
            }
            
            // Move on.
            g_iCurrent++;
            
            // If we've got some avatars left to check...
            if ( g_iCurrent < g_iMaxTracking )
            {
                // Get the next status...
                g_keyRequest = llRequestAgentData( llList2Key( g_lTracking, g_iCurrent ), DATA_ONLINE );
            }
            else
            {
                // Update the display.
                llSetText( LastOnlineReport(), < 1.0, 1.0, 1.0 >, 1.0 );
                
                // Pause for a while.
                state ScannerPause;
            }
        }
    }
    
    //////////////////////////////////////////////////////////////////
    // Look for changes.
    changed( integer change )
    {
        // Did the inventory of the object change?
        if ( change & CHANGED_INVENTORY )
        {
            // Yes. Most likely the key list was changed. Start over.
            llResetScript();
        }
    }
}

//////////////////////////////////////////////////////////////////////
// Scan pause state.
state ScannerPause
{
    //////////////////////////////////////////////////////////////////
    // State entry.
    state_entry()
    {
        // Set up the timer for the pause.
        llSetTimerEvent( REFRESH_INTERVAL );
    }
    
    //////////////////////////////////////////////////////////////////
    // Timer event.
    timer()
    {
        // Kill the timer.
        llSetTimerEvent( 0.0 );
        
        // Go back and scan again.
        state OnlineScanner;
    }

    //////////////////////////////////////////////////////////////////
    // Look for changes.
    changed( integer change )
    {
        // Did the inventory of the object change?
        if ( change & CHANGED_INVENTORY )
        {
            // Yes. Most likely the key list was changed. Start over.
            llResetScript();
        }
    }
}