mirror of
https://github.com/stroggprog/os-partnership.git
synced 2026-08-14 00:57:56 +00:00
first commit
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 Philip P. Ide
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -0,0 +1,160 @@
|
||||
# os-partnership
|
||||
Make or Break Partnerships in Opensimulator
|
||||
|
||||
This repository consists of the in-world LSL/OSSL script required to initiate partnership management as well as a PHP script to interrogate and modify partnership details on user account profile records. There are a number of simple libraries accompanying the PHP script, which I culled from my own set of libraries - why invent a new wheel when the old one still works?
|
||||
|
||||
# Index
|
||||
- [OSSL Functions](#ossl-functions)
|
||||
- [General Process](#general-process)
|
||||
- [Files Not Include](#files-not-included)
|
||||
- [The Certificate](#the-certificate)
|
||||
- [The Secret](#the-secret)
|
||||
- [Debugging](#debugging)
|
||||
- [Using the Proxy Script](#using-the-proxy-script)
|
||||
|
||||
|
||||
## OSSL Functions
|
||||
[Back to Top](#os-partnership)
|
||||
|
||||
The LSL/OSSL script requires use of the following ossl functions. Default permissions are shown:
|
||||
```lsl2
|
||||
osGetAvatarList ${OSSL|osslParcelOG}ESTATE_MANAGER,ESTATE_OWNER
|
||||
osGetNotecard ${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER
|
||||
osGetGridName always allowed
|
||||
osGetGridNick always allowed
|
||||
osListSortInPlaceStrided always allowed
|
||||
osMakeNotecard ${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER
|
||||
```
|
||||
|
||||
## General Process
|
||||
[Back to Top](#os-partnership)
|
||||
|
||||
Terms (for simplification of explanations):
|
||||
- Agent = avatar proposing partnership
|
||||
- Avatar = the target of the proposal
|
||||
|
||||
A. For a Partnered agent:
|
||||
- Offer to Dissolve partnership
|
||||
- if Dissolve partnership requested, perform dissolve and inform both parties
|
||||
|
||||
B. For an unpartnered agent:
|
||||
- Present a list of (up to) 9 closest avatars to choose from
|
||||
- Send dialog to chosen avatar, asking them to Accept or Decline proposal
|
||||
- If declined, inform agent
|
||||
- If accepted, perform partnering
|
||||
- If successfully partnered, shout a congratulatory message and fire a party-popper script
|
||||
- Both agent and avatar receive a certificate
|
||||
|
||||
If the chosen partner is already partnered, the agent is informed the partnership failed (and why). The avatar is informed they must first dissolve their existing partnership.
|
||||
|
||||
Once the agent has chosen a partner, the script goes into lockdown to prevent anyone else using it while the current partnering process is taking place. A partnering process takes priority over a dissolution.
|
||||
|
||||
## Files not included
|
||||
[Back to Top](#os-partnership)
|
||||
|
||||
You can include a party-popper script, which may fire some celebratory particles, play a fanfare and perhaps firework sounds.
|
||||
|
||||
The script can be placed anywhere in the link set, and should include the following minimal code:
|
||||
```lsl2
|
||||
integer PARTY_POPPERS = -10000;
|
||||
|
||||
partyPopper(){
|
||||
// fire some particles
|
||||
// play some sounds
|
||||
}
|
||||
|
||||
default {
|
||||
link_message( integer sender, integer num, string msg, key id ){
|
||||
if( num == PARTY_POPPERS ){
|
||||
partyPopper();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then just populate the `partyPopper()` function with some appropriate code.
|
||||
|
||||
## The Certificate
|
||||
[Back to Top](#os-partnership)
|
||||
|
||||
The certificate is generated from a template, stored in the notecard `Partnership.txt` which can be edited to suit your needs. The certificate generator recognises certain tokens that are replaced at runtime:
|
||||
|
||||
- %d (date)
|
||||
- %t (time)
|
||||
- %r (region name)
|
||||
- %g (grid name)
|
||||
- %n (grid nickname)
|
||||
- %a (name of proposing avatar)
|
||||
- %b (name of target avatar)
|
||||
- %ua (uuid of proposing avatar)
|
||||
- %ub (uuid of target avatar)
|
||||
|
||||
In the default template, there are some notes on forcing an update to profiles if the partnering/dissolving doesn't show. These will be included in the certficate.
|
||||
|
||||
## The Secret
|
||||
[Back to Top](#os-partnership)
|
||||
|
||||
There is a `secret` encoded in both the LSL/OSSL script and the receiving PHP script. If the PHP script doesn't receive the correct `secret`, it will terminate and return an error code of zero (nothing happened) and three error messages. None of these will be displayed by the LSL/OSSL script unless debugging is enabled.
|
||||
|
||||
Nobody else should know your secret, so this should provide a good level of protection against tampering, especially if you use https.
|
||||
|
||||
## Debugging
|
||||
[Back to Top](#os-partnership)
|
||||
|
||||
To enable debugging, set the debugging constant in the LSL/OSSL script to TRUE:
|
||||
```lsl2
|
||||
constant __DEBUG__ = TRUE;
|
||||
```
|
||||
|
||||
You can send strings, keys and integers to the debug function:
|
||||
```lsl2
|
||||
debug( "a string" );
|
||||
debug(5); // it works, no idea why
|
||||
debug( llGetOwner() ); // output your own key
|
||||
```
|
||||
Output is sent to the owner of the task.
|
||||
|
||||
Debugging return values from the php script is as simple as adding a line straight after the `http_response()` event is triggered:
|
||||
```lsl2
|
||||
http_response( key id, integer status, list metadata, string body ){
|
||||
debug("["+status+"] "+body);
|
||||
// etc
|
||||
}
|
||||
```
|
||||
|
||||
Note the php script always returns a string in the format:
|
||||
```lsl2
|
||||
result = "count|uuid1|uuid2";
|
||||
```
|
||||
|
||||
In some cases, there may be an extra piece of information tacked onto the end:
|
||||
```lsl2
|
||||
result = "count|uuid1|uuid2|uuid3";
|
||||
```
|
||||
|
||||
- uuid1 equates to the agent initiating the task
|
||||
- uuid2 equates to the target avatar
|
||||
- uuid3 equates to uuid2's partner if they already have one
|
||||
|
||||
`count` is always zero unless records have been changed, in which case this should always be 2.
|
||||
|
||||
If the test for the `secret` key fails, the result looks like this:
|
||||
```lsl2
|
||||
result = "0|Epic Failure|Very Epic Failure|Truly Epic Failure";
|
||||
```
|
||||
|
||||
Again, the zero indicates that nothing was changed.
|
||||
|
||||
|
||||
## Using the Proxy Script
|
||||
[Back to Top](#os-partnership)
|
||||
|
||||
If you are running a grid on your home network, but have a domain elsewhere, you can place the library files and the script from the proxy folder on your website. You can then call the proxy script simply by changing the URL (the name of the proxy script is the same as the main PHP script - `partnership.php`).
|
||||
|
||||
This acts as a pass-through, calling the script on your local network (you'll need to update the url it points to).
|
||||
|
||||
This is also helpful if you have HTTPS available on your remote website, but need to use HTTP to call your local script.
|
||||
|
||||
All the potential parameters are forwarded by the proxy script, and whatever result is returned to it, it will return to your in-world script.
|
||||
|
||||
[Back to Top](#os-partnership)
|
||||
@@ -0,0 +1,14 @@
|
||||
CERTIFICATE OF PARTNERSHIP
|
||||
===================
|
||||
On %d at %t, in the region "%r", being part of grid "%g" (%n)
|
||||
|
||||
%a [%ua]
|
||||
formed a Partnership with:
|
||||
%b [%ub]
|
||||
|
||||
|
||||
|
||||
--------------------------
|
||||
NOTES:
|
||||
Your profile has been updated to reflect the partnership.
|
||||
If your profile doesn't show your partner, update your profile picture to force a refresh (a good time for some wedding snaps!)
|
||||
@@ -0,0 +1,326 @@
|
||||
//YEngine:
|
||||
yoptions;
|
||||
|
||||
constant source_version = "1.0.6";
|
||||
|
||||
constant __DEBUG__ = FALSE;
|
||||
constant secret = "0TN@Z6E7**1)U'?MH81:[)z|;nj#3N&Ayb@Ql~.4XE+eR$)Dbg-}Omp_f*2iem=";
|
||||
constant URL = "https://your_url/";
|
||||
constant URI = "partnership.php";
|
||||
constant certificate = "Certificate of Partnership";
|
||||
|
||||
constant RES_RESULT = 0;
|
||||
constant RES_USER1 = 1;
|
||||
constant RES_USER2 = 2;
|
||||
|
||||
constant PARTY_POPPERS = -10000;
|
||||
|
||||
list weekdays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
|
||||
list uuids;
|
||||
|
||||
key user1 = NULL_KEY;
|
||||
key user2 = NULL_KEY;
|
||||
|
||||
integer lhandle;
|
||||
integer busy;
|
||||
|
||||
key rqInfo;
|
||||
key rqDiv;
|
||||
key rqPair;
|
||||
|
||||
string base_cert;
|
||||
|
||||
debug( string text ){
|
||||
if( __DEBUG__ ){
|
||||
llOwnerSay( text );
|
||||
}
|
||||
}
|
||||
|
||||
string Unix2PSTorPDT(integer insecs){
|
||||
string str = ConvertPST(insecs - (3600 * 8) ); // PST is 8 hours behind GMT
|
||||
if(llGetSubString(str, -3, -1) == "PDT")
|
||||
str = ConvertPST(insecs - (3600 * 7) ); // ... Recompute at 1 hour later
|
||||
return str;
|
||||
}
|
||||
// This leap year test is correct for all years from 1901 to 2099 and hence is quite adequate for Unix Time computations
|
||||
integer LeapYear(integer year){
|
||||
return !(year & 3);
|
||||
}
|
||||
|
||||
integer DaysPerMonth(integer year, integer month){
|
||||
if (month == 2) return 28 + LeapYear(year);
|
||||
return 30 + ( (month + (month > 7) ) & 1); // Odd months up to July, and even months after July, have 31 days
|
||||
}
|
||||
|
||||
list preConvert( integer insecs ){
|
||||
// this part of the calculation is common to both GMT/BST and PST/PDT
|
||||
integer w; integer month; integer daysinyear;
|
||||
integer mins = insecs / 60;
|
||||
integer secs = insecs % 60;
|
||||
integer hours = mins / 60;
|
||||
mins = mins % 60;
|
||||
integer days = hours / 24;
|
||||
hours = hours % 24;
|
||||
integer DayOfWeek = (days + 4) % 7; // 0=Sun thru 6=Sat
|
||||
|
||||
integer years = 1970 + 4 * (days / 1461);
|
||||
days = days % 1461; // number of days into a 4-year cycle
|
||||
|
||||
@loop;
|
||||
daysinyear = 365 + LeapYear(years);
|
||||
if (days >= daysinyear){
|
||||
days -= daysinyear;
|
||||
++years;
|
||||
jump loop;
|
||||
}
|
||||
++days;
|
||||
|
||||
for (w = month = 0; days > w; ){
|
||||
days -= w;
|
||||
w = DaysPerMonth(years, ++month);
|
||||
}
|
||||
|
||||
string str = ((string) years + "-" +
|
||||
llGetSubString ("0" + (string) month, -2, -1) +
|
||||
"-" + llGetSubString ("0" + (string) days, -2, -1) +
|
||||
" " +
|
||||
llGetSubString ("0" + (string) hours, -2, -1) +
|
||||
":" +
|
||||
llGetSubString ("0" + (string) mins, -2, -1) );
|
||||
|
||||
return [days, DayOfWeek, month, years, str];
|
||||
}
|
||||
|
||||
string ConvertPST(integer insecs){
|
||||
list r = preConvert( insecs );
|
||||
integer days = llList2Integer( r, 0 );
|
||||
integer DayOfWeek = llList2Integer( r, 1 );
|
||||
integer month = llList2Integer( r, 2 );
|
||||
integer years = llList2Integer( r, 3 );
|
||||
string str = llList2String( r, 4 );
|
||||
|
||||
integer LastSunday = days - DayOfWeek;
|
||||
string PST_PDT = " PST"; // start by assuming Pacific Standard Time
|
||||
// Up to 2006, PDT is from the first Sunday in April to the last Sunday in October
|
||||
// After 2006, PDT is from the 2nd Sunday in March to the first Sunday in November
|
||||
if (years > 2006 && month == 3 && LastSunday > 7) PST_PDT = " PDT";
|
||||
if (month > 3) PST_PDT = " PDT";
|
||||
if (month > 10) PST_PDT = " PST";
|
||||
if (years < 2007 && month == 10 && LastSunday > 24) PST_PDT = " PST";
|
||||
return (llList2String(weekdays, DayOfWeek) + " " + str + PST_PDT);
|
||||
}
|
||||
|
||||
|
||||
integer random(){
|
||||
return 0x80000000 | (integer)llFrand(65536) | ((integer)llFrand(65536) << 16);
|
||||
}
|
||||
|
||||
endListen(){
|
||||
if( lhandle != 0 ){
|
||||
llListenRemove( lhandle );
|
||||
lhandle = 0;
|
||||
}
|
||||
llSetTimerEvent(0.0);
|
||||
}
|
||||
|
||||
integer startListen( key avatar ){
|
||||
endListen();
|
||||
integer chan = random();
|
||||
lhandle = llListen( chan, "", avatar, "" );
|
||||
llSetTimerEvent(120.0);
|
||||
return chan;
|
||||
}
|
||||
|
||||
menuDeclareWho( key user1, integer num ){
|
||||
busy = TRUE;
|
||||
integer chan = startListen( user1 );
|
||||
list buttons = make_ordered_buttons( num );
|
||||
string dText = "Choose your partner:";
|
||||
for( integer i = 0; i < num; i++ ){
|
||||
dText += "\n"+(string)(i+1)+" - "+llKey2Name( llList2Key( uuids, i ) );
|
||||
}
|
||||
llDialog( user1, dText, buttons, chan );
|
||||
}
|
||||
|
||||
menuPartner( key user1, key user2 ){
|
||||
integer chan = startListen( user2 );
|
||||
list buttons = ["Accept", "Decline"];
|
||||
string dText = "Partnership Proposal\n"+llKey2Name( user1 )+" wishes to partner with you";
|
||||
llDialog( user2, dText, buttons, chan );
|
||||
}
|
||||
|
||||
menuDivorce( key user1, key user2 ){
|
||||
string name = llKey2Name( user2 );
|
||||
integer chan = startListen( user1 );
|
||||
llDialog( user1, "Are you sure you wish to dissolve your partnersip with:\n"+name, ["Dissolve", "Exit"], chan );
|
||||
}
|
||||
|
||||
disclosure( key avatar, key partner ){
|
||||
list date_time = llParseStringKeepNulls( Unix2PSTorPDT( llGetUnixTime() ), [" "], [] );
|
||||
string date = llList2String( date_time, 0 )+" "+llList2String( date_time, 1 );
|
||||
string time = llList2String( date_time, 2 )+" "+llList2String( date_time, 3 );
|
||||
string contents = base_cert;
|
||||
if( contents == "" ){
|
||||
base_cert = osGetNotecard( "Partnership.txt" );
|
||||
contents = base_cert;
|
||||
}
|
||||
contents = llReplaceSubString( contents, "%a", llKey2Name( avatar ), 0 );
|
||||
contents = llReplaceSubString( contents, "%b", llKey2Name( partner ), 0 );
|
||||
contents = llReplaceSubString( contents, "%r", llGetRegionName(), 0 );
|
||||
contents = llReplaceSubString( contents, "%g", osGetGridName(), 0 );
|
||||
contents = llReplaceSubString( contents, "%n", osGetGridNick(), 0 );
|
||||
contents = llReplaceSubString( contents, "%d", date, 0 );
|
||||
contents = llReplaceSubString( contents, "%t", time, 0 );
|
||||
contents = llReplaceSubString( contents, "%ua", avatar, 0 );
|
||||
contents = llReplaceSubString( contents, "%ub", partner, 0 );
|
||||
osMakeNotecard( certificate, [contents] );
|
||||
llGiveInventory( avatar, certificate );
|
||||
llGiveInventory( partner, certificate );
|
||||
llRemoveInventory( certificate );
|
||||
}
|
||||
|
||||
key sendMessage( string action, key user1, key user2 ){
|
||||
string ext = "?pw="+llEscapeURL( secret )+"&action="+action+
|
||||
"&user1="+user1+
|
||||
"&user2="+user2;
|
||||
return llHTTPRequest(URL+URI+ext, [], "");
|
||||
}
|
||||
|
||||
list make_ordered_buttons(integer input){
|
||||
string output;
|
||||
if (input == 9) output = "7, 8, 9, 4, 5, 6, 1, 2, 3, Exit";
|
||||
else if (input == 8) output = "7, 8, -, 4, 5, 6, 1, 2, 3, Exit";
|
||||
else if (input == 7) output = "7, -, -, 4, 5, 6, 1, 2, 3, Exit";
|
||||
else if (input == 6) output = "4, 5, 6, 1, 2, 3, Exit";
|
||||
else if (input == 5) output = "4, 5, -, 1, 2, 3, Exit";
|
||||
else if (input == 4) output = "4, -, -, 1, 2, 3, Exit";
|
||||
else if (input == 3) output = "1, 2, 3, Exit";
|
||||
else if (input == 2) output = "Exit, 1, 2";
|
||||
else if (input == 1) output = "Exit, 1";
|
||||
if (output == "") return [];
|
||||
return llCSV2List(output);
|
||||
}
|
||||
|
||||
default {
|
||||
state_entry() {
|
||||
llSetText("Marriage, Partnership and Separation", <1, 0.685, 0>, 1.0 );
|
||||
debug( Unix2PSTorPDT( llGetUnixTime() ) );
|
||||
}
|
||||
touch_start(integer num){
|
||||
if( !lhandle && !busy ){
|
||||
rqInfo = sendMessage( "info", llDetectedKey(0), NULL_KEY );
|
||||
}
|
||||
else {
|
||||
llSay( 0, "Busy" );
|
||||
}
|
||||
}
|
||||
timer(){
|
||||
endListen();
|
||||
busy = FALSE; // end busy status on timeout
|
||||
}
|
||||
http_response( key id, integer status, list metadata, string body ){
|
||||
debug("["+(string)status+"] "+body);
|
||||
list data = llParseStringKeepNulls( body, ["|"], [] );
|
||||
integer result = (integer) llList2String( data, RES_RESULT );
|
||||
key user1 = (key) llList2String( data, RES_USER1 );
|
||||
key user2 = (key) llList2String( data, RES_USER2 );
|
||||
|
||||
if( id == rqInfo ){
|
||||
if( user2 == NULL_KEY ){
|
||||
// partnership required
|
||||
list avatars = osGetAvatarList();
|
||||
// owner is excluded so add owner if in region and not user1
|
||||
if( llGetAgentSize( llGetOwner() ) != ZERO_VECTOR && llGetOwner() != user1 ){
|
||||
vector pos = llList2Vector( llGetObjectDetails( llGetOwner(), [OBJECT_POS] ), 0 );
|
||||
avatars += [ llGetOwner(), pos, llKey2Name( llGetOwner() ) ];
|
||||
}
|
||||
// remove user1 from list if they're in it (not owner of task)
|
||||
integer n = llListFindList( avatars, [user1] );
|
||||
if( n > -1 ){
|
||||
avatars = llListReplaceList( avatars, [], n, n+2 );
|
||||
}
|
||||
|
||||
// convert position of avatars to distance from task
|
||||
vector pos = llGetPos();
|
||||
n = llGetListLength( avatars );
|
||||
for( integer i = 0; i < n; i+= 3 ){
|
||||
float dist = llVecDist( pos, llList2Vector( avatars, i+1 ) );
|
||||
avatars = llListReplaceList( avatars, [dist], i+1, i+1 );
|
||||
}
|
||||
// sort list, based on distance
|
||||
osListSortInPlaceStrided( avatars, 3, 1, 1 );
|
||||
if( n > 9*3 ){
|
||||
avatars = llList2List( avatars, 0, (9*3)-1 );
|
||||
}
|
||||
|
||||
// extract just the uuids of the avatars
|
||||
n = llGetListLength( avatars );
|
||||
uuids = [];
|
||||
for( integer i = 0; i < n; i += 3 ){
|
||||
uuids += llList2Key( avatars, i );
|
||||
}
|
||||
// prompt for v̶i̶c̶t̶i̶m̶ partner
|
||||
menuDeclareWho( user1, llGetListLength( uuids ) );
|
||||
}
|
||||
else {
|
||||
menuDivorce( user1, user2 );
|
||||
}
|
||||
}
|
||||
else if( id == rqPair ){
|
||||
busy = FALSE;
|
||||
if( result == 2 ){
|
||||
// paired!
|
||||
// fire some party poppers, if another script provides them
|
||||
llMessageLinked( LINK_SET, PARTY_POPPERS, "", "" );
|
||||
llShout( PUBLIC_CHANNEL, "CONGRATULATIONS!" );
|
||||
llShout( PUBLIC_CHANNEL, llKey2Name( user1 )+" has partnered with "+llKey2Name( user2 ) );
|
||||
disclosure( user1, user2 );
|
||||
}
|
||||
else {
|
||||
key thirdParty = (key) llList2String( data, RES_USER2 + 1 );
|
||||
llRegionSayTo( user1, PUBLIC_CHANNEL,
|
||||
llKey2Name( user2 )+" is already partnered with "+llKey2Name( thirdParty ) );
|
||||
llRegionSayTo( user2, PUBLIC_CHANNEL,
|
||||
"You must first dissolve your partnership with "+llKey2Name( thirdParty ) );
|
||||
}
|
||||
}
|
||||
else if( id == rqDiv ){
|
||||
if( result == 2 ){
|
||||
llDialog( user1, "You have disolved your partnership with\n"+llKey2Name( user2 ),
|
||||
["Exit"], random() );
|
||||
if( llGetAgentSize( user2 ) != ZERO_VECTOR ){
|
||||
llDialog( user2, llKey2Name( user1 )+" has disolved your partnership",
|
||||
["Exit"], random() );
|
||||
}
|
||||
else {
|
||||
llInstantMessage( user2, llKey2Name( user1 )+" has disolved your partnership" );
|
||||
}
|
||||
}
|
||||
else {
|
||||
llRegionSayTo( user1, PUBLIC_CHANNEL, "An error occurred, the partnership was not disolved" );
|
||||
}
|
||||
}
|
||||
}
|
||||
listen(integer channel, string name, key id, string msg){
|
||||
endListen();
|
||||
if( msg == "Dissolve" ){
|
||||
rqDiv = sendMessage( "divorce", id, NULL_KEY );
|
||||
}
|
||||
else if( msg == "Accept" ){
|
||||
rqPair = sendMessage( "partner", user1, id );
|
||||
}
|
||||
else if( msg == "Decline" ){
|
||||
busy = FALSE;
|
||||
llRegionSayTo( user1, PUBLIC_CHANNEL, llKey2Name( id )+" declined your proposal" );
|
||||
}
|
||||
else if( msg != "Exit" ){
|
||||
integer msgN = (integer) msg;
|
||||
if( msgN > 0 && msgN < 10 ){
|
||||
user1 = id;
|
||||
user2 = llList2Key( uuids, msgN-1 );
|
||||
menuPartner( user1, user2 );
|
||||
llRegionSayTo( user1, PUBLIC_CHANNEL, llKey2Name( user2 )+" is being asked to accept your proposal" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+480
@@ -0,0 +1,480 @@
|
||||
<?php
|
||||
#namespace ppi\Database\mysql;
|
||||
|
||||
/*
|
||||
* Session Management for PHP3
|
||||
*
|
||||
* Copyright (c) 1998-2000 NetUSE AG
|
||||
* Boris Erdmann, Kristian Koehntopp
|
||||
* Updated 2005 to use mysqli by Philip Ide
|
||||
* Various support functions added since, particularly shortcut functions and object-based records
|
||||
*
|
||||
* $Id: db_mysql.inc,v 1.2 2000/07/12 18:22:34 kk Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
class DB_Sql {
|
||||
|
||||
/* public: connection parameters */
|
||||
var $ctype = __NAMESPACE__;
|
||||
var $Host = "";
|
||||
var $Database = "";
|
||||
var $User = "";
|
||||
var $Password = "";
|
||||
|
||||
/* public: configuration parameters */
|
||||
var $Auto_Free = 0; ## Set to 1 for automatic mysql_free_result()
|
||||
var $Debug = 0; ## Set to 1 for debugging messages.
|
||||
var $Halt_On_Error = "yes"; ## "yes" (halt with message), "no" (ignore errors quietly), "report" (ignore errror, but spit a warning)
|
||||
var $Seq_Table = "db_sequence";
|
||||
|
||||
/* public: result array and current row number */
|
||||
var $Record = array();
|
||||
var $Row;
|
||||
|
||||
/* public: current error number and error text */
|
||||
var $Errno = 0;
|
||||
var $Error = "";
|
||||
|
||||
/* public: this is an api revision, not a CVS revision. */
|
||||
var $type = "mysql";
|
||||
var $revision = "1.2";
|
||||
|
||||
/* private: link and query handles */
|
||||
var $Link_ID = 0;
|
||||
var $Query_ID = 0;
|
||||
|
||||
|
||||
|
||||
/* public: constructor */
|
||||
function DB_Sql($query = "") {
|
||||
$this->query($query);
|
||||
}
|
||||
|
||||
/* public: some trivial reporting */
|
||||
function link_id() {
|
||||
return $this->Link_ID;
|
||||
}
|
||||
|
||||
function query_id() {
|
||||
return $this->Query_ID;
|
||||
}
|
||||
|
||||
/* public: connection management */
|
||||
function connect($Database = "", $Host = "", $User = "", $Password = "") {
|
||||
/* Handle defaults */
|
||||
if ("" == $Database)
|
||||
$Database = $this->Database;
|
||||
if ("" == $Host)
|
||||
$Host = $this->Host;
|
||||
if ("" == $User)
|
||||
$User = $this->User;
|
||||
if ("" == $Password)
|
||||
$Password = $this->Password;
|
||||
|
||||
/* establish connection, select database */
|
||||
if ( !$this->Link_ID ) {
|
||||
$this->Link_ID=mysqli_connect($Host, $User, $Password, $Database);
|
||||
if (!$this->Link_ID) {
|
||||
$this->halt("connect($Host, $User, \$Password) failed.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $this->Link_ID;
|
||||
}
|
||||
|
||||
/* public: discard the query result */
|
||||
function free() {
|
||||
//@mysql_free_result($this->Query_ID);
|
||||
//mysqli_stmt_free_result($this->Query_ID);
|
||||
if( is_object( $this->Query_ID ) ){
|
||||
$this->Query_ID->close();
|
||||
$this->Query_ID = 0;
|
||||
}
|
||||
}
|
||||
|
||||
function escape_string( $string = "" ){
|
||||
return mysqli_real_escape_string( $this->Link_ID, $string );
|
||||
}
|
||||
|
||||
/* public: perform a query */
|
||||
function query($Query_String) {
|
||||
/* No empty queries, please, since PHP4 chokes on them. */
|
||||
if ($Query_String == "")
|
||||
/* The empty query string is passed on from the constructor,
|
||||
* when calling the class without a query, e.g. in situations
|
||||
* like these: '$db = new DB_Sql_Subclass;'
|
||||
*/
|
||||
return 0;
|
||||
|
||||
if (!$this->connect()) {
|
||||
return 0; /* we already complained in connect() about that. */
|
||||
};
|
||||
|
||||
# New query, discard previous result.
|
||||
if ($this->Query_ID) {
|
||||
$this->free();
|
||||
}
|
||||
|
||||
if ($this->Debug)
|
||||
printf("Debug: query = %s<br>\n", $Query_String);
|
||||
|
||||
$this->Query_ID = mysqli_query( $this->Link_ID, $Query_String );
|
||||
$this->Row = 0;
|
||||
/*
|
||||
$this->Errno = mysql_errno();
|
||||
$this->Error = mysql_error();
|
||||
*/
|
||||
$this->Errno = mysqli_errno($this->Link_ID);
|
||||
$this->Error = mysqli_error($this->Link_ID);
|
||||
|
||||
if (!$this->Query_ID) {
|
||||
$this->halt("Invalid SQL: ".$Query_String);
|
||||
}
|
||||
|
||||
# Will return nada if it fails. That's fine.
|
||||
return $this->Query_ID;
|
||||
}
|
||||
|
||||
function execute( $query_String ){
|
||||
$this->query( $query_String );
|
||||
if( is_object( $this->Query_ID ) ){
|
||||
return $this->next_record();
|
||||
}
|
||||
return $this->Query_ID;
|
||||
}
|
||||
|
||||
function execute_as_obj( $query_String ){
|
||||
$this->query( $query_String );
|
||||
if( is_object( $this->Query_ID ) ){
|
||||
return $this->next_rec_as_obj();
|
||||
}
|
||||
return $this->Query_ID;
|
||||
}
|
||||
|
||||
function insert_id()
|
||||
{
|
||||
return mysqli_insert_id($this->Link_ID);
|
||||
}
|
||||
|
||||
|
||||
/* public: walk result set */
|
||||
function next_record() {
|
||||
if (!$this->Query_ID) {
|
||||
$this->halt("next_record called with no query pending.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
$this->Record = mysqli_fetch_array($this->Query_ID);
|
||||
$this->Row += 1;
|
||||
/*
|
||||
$this->Errno = mysql_errno();
|
||||
$this->Error = mysql_error();
|
||||
*/
|
||||
$this->Errno = mysqli_errno($this->Link_ID);
|
||||
$this->Error = mysqli_error($this->Link_ID);
|
||||
|
||||
$stat = is_array($this->Record);
|
||||
if (!$stat && $this->Auto_Free) {
|
||||
$this->free();
|
||||
}
|
||||
return $stat;
|
||||
}
|
||||
|
||||
function locate( $col, $value ){
|
||||
$a = 0;
|
||||
while( $this->next_record() ){
|
||||
$a++;
|
||||
if( $this->f($col) == $value ){
|
||||
return $a;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function as_obj(){
|
||||
return json_decode( json_encode( $this->Record ) );
|
||||
}
|
||||
|
||||
function next_rec_as_obj(){
|
||||
if( $this->next_record() ){
|
||||
return $this->as_obj();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function fetchRecord(){
|
||||
return (object) $this->Record;
|
||||
}
|
||||
|
||||
function fetchNextRecord(){
|
||||
if( $this->next_record() ){
|
||||
return $this->fetchRecord();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* public: position in result set */
|
||||
function seek($pos = 0) {
|
||||
$status = mysqli_data_seek($this->Query_ID, $pos);
|
||||
if ($status)
|
||||
$this->Row = $pos;
|
||||
else {
|
||||
$this->halt("seek($pos) failed: result has ".$this->num_rows()." rows");
|
||||
|
||||
/* half assed attempt to save the day,
|
||||
* but do not consider this documented or even
|
||||
* desireable behaviour.
|
||||
*/
|
||||
mysqli_data_seek($this->Query_ID, $this->num_rows());
|
||||
$this->Row = $this->num_rows;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* public: table locking */
|
||||
function lock($table, $mode="write") {
|
||||
$this->connect();
|
||||
|
||||
$query="lock tables ";
|
||||
if (is_array($table)) {
|
||||
while (list($key,$value)=each($table)) {
|
||||
if ($key=="read" && $key!=0) {
|
||||
$query.="$value read, ";
|
||||
} else {
|
||||
$query.="$value $mode, ";
|
||||
}
|
||||
}
|
||||
$query=substr($query,0,-2);
|
||||
} else {
|
||||
$query.="$table $mode";
|
||||
}
|
||||
$res = mysqli_query( $this->Link_ID, $query );
|
||||
if (!$res) {
|
||||
$this->halt("lock($table, $mode) failed.");
|
||||
return 0;
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
function unlock() {
|
||||
$this->connect();
|
||||
|
||||
$res = mysqli_query( $this->Link_ID, "unlock tables");
|
||||
if (!$res) {
|
||||
$this->halt("unlock() failed.");
|
||||
return 0;
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
/* public: evaluate the result (size, width) */
|
||||
function affected_rows() {
|
||||
return mysqli_affected_rows($this->Link_ID);
|
||||
}
|
||||
|
||||
function num_rows() {
|
||||
return mysqli_num_rows($this->Query_ID);
|
||||
}
|
||||
|
||||
function num_fields() {
|
||||
return mysqli_num_fields($this->Query_ID);
|
||||
}
|
||||
|
||||
function record() {
|
||||
if( $this->Query_ID ){
|
||||
return $this->Record;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* public: shorthand notation */
|
||||
function nf() {
|
||||
return $this->num_rows();
|
||||
}
|
||||
|
||||
function np() {
|
||||
print $this->num_rows();
|
||||
}
|
||||
|
||||
function f($Name) {
|
||||
if(isset($this->Record[$Name]))
|
||||
return $this->Record[$Name];
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
function af( $flist ){
|
||||
$r = array();
|
||||
foreach( $flist as $fname ){
|
||||
$r[$fname] = $this->Record[$fname];
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
function p($Name) {
|
||||
print $this->Record[$Name];
|
||||
}
|
||||
|
||||
/* public: sequence numbers */
|
||||
function nextid($seq_name) {
|
||||
$this->connect();
|
||||
|
||||
if ($this->lock($this->Seq_Table)) {
|
||||
/* get sequence number (locked) and increment */
|
||||
$q = sprintf("select nextid from %s where seq_name = '%s'",
|
||||
$this->Seq_Table,
|
||||
$seq_name);
|
||||
$id = mysqli_query($this->Link_ID, $q);
|
||||
$res = mysqli_fetch_array($id);
|
||||
|
||||
/* No current value, make one */
|
||||
if (!is_array($res)) {
|
||||
$currentid = 0;
|
||||
$q = sprintf("insert into %s values('%s', %s)",
|
||||
$this->Seq_Table,
|
||||
$seq_name,
|
||||
$currentid);
|
||||
$id = mysqli_query( $this->Link_ID, $q );
|
||||
} else {
|
||||
$currentid = $res["nextid"];
|
||||
}
|
||||
$nextid = $currentid + 1;
|
||||
$q = sprintf("update %s set nextid = '%s' where seq_name = '%s'",
|
||||
$this->Seq_Table,
|
||||
$nextid,
|
||||
$seq_name);
|
||||
$id = mysqli_query( $this->Link_ID, $q );
|
||||
$this->unlock();
|
||||
} else {
|
||||
$this->halt("cannot lock ".$this->Seq_Table." - has it been created?");
|
||||
return 0;
|
||||
}
|
||||
return $nextid;
|
||||
}
|
||||
|
||||
/* public: return table metadata */
|
||||
function metadata($table='',$full=false) {
|
||||
$count = 0;
|
||||
$id = 0;
|
||||
$res = array();
|
||||
|
||||
/*
|
||||
* Due to compatibility problems with Table we changed the behavior
|
||||
* of metadata();
|
||||
* depending on $full, metadata returns the following values:
|
||||
*
|
||||
* - full is false (default):
|
||||
* $result[]:
|
||||
* [0]["table"] table name
|
||||
* [0]["name"] field name
|
||||
* [0]["type"] field type
|
||||
* [0]["len"] field length
|
||||
* [0]["flags"] field flags
|
||||
*
|
||||
* - full is true
|
||||
* $result[]:
|
||||
* ["num_fields"] number of metadata records
|
||||
* [0]["table"] table name
|
||||
* [0]["name"] field name
|
||||
* [0]["type"] field type
|
||||
* [0]["len"] field length
|
||||
* [0]["flags"] field flags
|
||||
* ["meta"][field name] index of field named "field name"
|
||||
* The last one is used, if you have a field name, but no index.
|
||||
* Test: if (isset($result['meta']['myfield'])) { ...
|
||||
*/
|
||||
|
||||
// if no $table specified, assume that we are working with a query
|
||||
// result
|
||||
if ($table) {
|
||||
$this->connect();
|
||||
$id = @mysql_list_fields($this->Database, $table);
|
||||
if (!$id)
|
||||
$this->halt("Metadata query failed.");
|
||||
} else {
|
||||
$id = $this->Query_ID;
|
||||
if (!$id)
|
||||
$this->halt("No query specified.");
|
||||
}
|
||||
|
||||
$count = @mysql_num_fields($id);
|
||||
|
||||
// made this IF due to performance (one if is faster than $count if's)
|
||||
if (!$full) {
|
||||
for ($i=0; $i<$count; $i++) {
|
||||
$res[$i]["table"] = @mysql_field_table ($id, $i);
|
||||
$res[$i]["name"] = @mysql_field_name ($id, $i);
|
||||
$res[$i]["type"] = @mysql_field_type ($id, $i);
|
||||
$res[$i]["len"] = @mysql_field_len ($id, $i);
|
||||
$res[$i]["flags"] = @mysql_field_flags ($id, $i);
|
||||
}
|
||||
} else { // full
|
||||
$res["num_fields"]= $count;
|
||||
|
||||
for ($i=0; $i<$count; $i++) {
|
||||
$res[$i]["table"] = @mysql_field_table ($id, $i);
|
||||
$res[$i]["name"] = @mysql_field_name ($id, $i);
|
||||
$res[$i]["type"] = @mysql_field_type ($id, $i);
|
||||
$res[$i]["len"] = @mysql_field_len ($id, $i);
|
||||
$res[$i]["flags"] = @mysql_field_flags ($id, $i);
|
||||
$res["meta"][$res[$i]["name"]] = $i;
|
||||
}
|
||||
}
|
||||
|
||||
// free the result only if we were called on a table
|
||||
if ($table) @mysql_free_result($id);
|
||||
return $res;
|
||||
}
|
||||
|
||||
/* private: error handling */
|
||||
function halt($msg) {
|
||||
$this->Error = mysqli_error($this->Link_ID);
|
||||
$this->Errno = mysqli_errno($this->Link_ID);
|
||||
if ($this->Halt_On_Error == "no")
|
||||
return;
|
||||
|
||||
$this->haltmsg($msg);
|
||||
$this->sqlerror($msg);
|
||||
|
||||
if ($this->Halt_On_Error != "report")
|
||||
die("<br>Session halted.");
|
||||
}
|
||||
|
||||
function haltmsg($msg) {
|
||||
printf("\n<br>Oh dear, we got an error");
|
||||
//printf("</td></tr></table><b>Database error:</b> %s<br>\n", $msg);
|
||||
printf("\n<b>MySQL Error</b>: %s (%s)<br>\n",
|
||||
$this->Errno,
|
||||
$this->Error);
|
||||
|
||||
}
|
||||
|
||||
function table_names() {
|
||||
$this->query("SHOW TABLES");
|
||||
$i=0;
|
||||
while ($info=mysqli_fetch_row($this->Query_ID))
|
||||
{
|
||||
$return[$i]["table_name"]= $info[0];
|
||||
$return[$i]["tablespace_name"]=$this->Database;
|
||||
$return[$i]["database"]=$this->Database;
|
||||
$i++;
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
function sqlerror( $data ){
|
||||
$en = $this->Errno;
|
||||
$em = $this->Error;
|
||||
$msg = "Database error: $data\nMySQL Error: $en ($em)";
|
||||
file_put_contents('sql_error', "\n$data", FILE_APPEND );
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
function setDBParameters( $db ){
|
||||
$db->Host = "localhost";
|
||||
$db->Database = "opensim";
|
||||
$db->User = "opensimuser";
|
||||
$db->Password = "opensimuserPassword"; // honestly, if this is your password, change it
|
||||
}
|
||||
?>
|
||||
Executable
+55
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
class parameters extends randomAccess {
|
||||
function __construct(){
|
||||
parent::__construct();
|
||||
$this->params = $_POST;
|
||||
}
|
||||
}
|
||||
|
||||
class randomAccess {
|
||||
protected $params;
|
||||
|
||||
function __construct(){
|
||||
$this->params = array();
|
||||
}
|
||||
|
||||
function __set( $name, $value ){
|
||||
$this->params[ $name ] = $value;
|
||||
}
|
||||
|
||||
function __get( $name ){
|
||||
$result = "";
|
||||
if( array_key_exists( $name, $this->params ) ){
|
||||
$result = $this->params[ $name ];
|
||||
}
|
||||
else if( array_key_exists( $name, $_POST ) ){
|
||||
$result = $_POST[ $name ];
|
||||
}
|
||||
else if( array_key_exists( $name, $_GET ) ){
|
||||
$result = $_GET[ $name ];
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
function unset( $name ){
|
||||
if( array_key_exists( $name, $this->params ) ){
|
||||
unset( $this->params[ $name ] );
|
||||
}
|
||||
return count( $this->params );
|
||||
}
|
||||
|
||||
function listKeys(){
|
||||
return array_keys( $this->params );
|
||||
}
|
||||
|
||||
function maskedKeys(){
|
||||
$mask = array();
|
||||
foreach( $this->params as $key => $value ){
|
||||
if( array_key_exists( $key, $_POST ) || array_key_exists( $key, $_GET ) ){
|
||||
$mask[] = $key;
|
||||
}
|
||||
}
|
||||
return $mask;
|
||||
}
|
||||
}
|
||||
?>
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
function sendMessage( $url, $data = "" ){
|
||||
$curl_handle=curl_init();
|
||||
curl_setopt($curl_handle, CURLOPT_CAINFO, "cacert.pem");
|
||||
curl_setopt($curl_handle, CURLOPT_URL, $url);
|
||||
curl_setopt($curl_handle, CURLOPT_TIMEOUT, 120);
|
||||
curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, TRUE);
|
||||
if( $data != "" ){
|
||||
curl_setopt($curl_handle, CURLOPT_POSTFIELDS, "$data");
|
||||
}
|
||||
$reply = curl_exec($curl_handle);
|
||||
if (!$reply) {
|
||||
//die('Error: "' . curl_error($curl_handle) . '" - Code: ' . curl_errno($curl_handle));
|
||||
$reply = "$url: ".'Error: "' . curl_error($curl_handle) . '" - Code: ' . curl_errno($curl_handle);
|
||||
}
|
||||
curl_close($curl_handle);
|
||||
return $reply;
|
||||
}
|
||||
|
||||
?>
|
||||
Executable
+56
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
header("Content-type:text/plain");
|
||||
include_once("lib/db_mysql.php");
|
||||
include_once("lib/params.php");
|
||||
include_once("lib/db_params.php");
|
||||
|
||||
define("SECRET", "0TN@Z6E7**1)U'?MH81:[)z|;nj#3N&Ayb@Ql~.4XE+eR$)Dbg-}Omp_f*2iem=" );
|
||||
define("ZERO_UUID", "00000000-0000-0000-0000-000000000000");
|
||||
|
||||
$p = new parameters();
|
||||
|
||||
if( $p->pw != SECRET ){
|
||||
echo "0|Epic Failure|Very Epic Failure|Truly Epic Failure"; // status code and error message
|
||||
exit(0);
|
||||
}
|
||||
$db = new DB_Sql();
|
||||
setDBParameters( $db ); // Host, Database, Username, Password
|
||||
|
||||
$user1 = $p->user1;
|
||||
$user2 = $p->user2 == "" ? ZERO_UUID : $p->user2;
|
||||
$result = 0;
|
||||
$extra = "";
|
||||
|
||||
// 'divorce' splits a partnership from both sides
|
||||
// 'partner' joins two avatars if they both independent
|
||||
// 'info' fetches partnership status for an individual
|
||||
|
||||
if( $p->action == "divorce" || $p->action == "info" ){
|
||||
$sql = "select profilePartner from userprofile where useruuid='$user1'";
|
||||
if( $r = $db->execute_as_obj( $sql ) ){
|
||||
$user2 = $r->profilePartner;
|
||||
}
|
||||
}
|
||||
if( $p->action == "divorce" && $user2 != ZERO_UUID ){
|
||||
$sql = "update userprofile set profilePartner='".ZERO_UUID."'".
|
||||
"where useruuid='$user1' or useruuid='$user2'";
|
||||
$db->query( $sql );
|
||||
$result = $db->affected_rows();
|
||||
}
|
||||
else if( $p->action == "partner" ){
|
||||
$sql = "select useruuid, profilePartner from userprofile where useruuid='$user1' or useruuid='$user2'";
|
||||
$db->query( $sql );
|
||||
$ok = 0;
|
||||
while( $r = $db->next_rec_as_obj() ){
|
||||
if( $r->profilePartner == ZERO_UUID ) $ok++;
|
||||
else $extra = "|$r->profilePartner";
|
||||
}
|
||||
if( $ok == 2 ){
|
||||
$db->execute( "update userprofile set profilePartner='$user2' where useruuid='$user1'" );
|
||||
$result += $db->affected_rows();
|
||||
$db->execute( "update userprofile set profilePartner='$user1' where useruuid='$user2'" );
|
||||
$result += $db->affected_rows();
|
||||
}
|
||||
}
|
||||
echo "$result|$user1|$user2$extra";
|
||||
?>
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
header("Content-type:text/plain");
|
||||
include_once("../lib/sendMessage.php");
|
||||
include_once("../lib/params.php");
|
||||
|
||||
//file_put_contents("data.txt", "pw: ".$_GET["pw"]."\n");
|
||||
|
||||
|
||||
|
||||
$p = new parameters();
|
||||
$data = "pw=".urlencode($p->pw)."&action=$p->action&user1=$p->user1&user2=$p->user2";
|
||||
$r = sendMessage("http://your_url/partnership.php", $data);
|
||||
echo $r;
|
||||
|
||||
?>
|
||||
Reference in New Issue
Block a user