Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Library: FOSSL Vending System v1

Ilobmirt Tenk
Registered User
Join date: 4 Jun 2007
Posts: 135
02-28-2008 04:31
____________________________
| About the FOSSL Vending System |
======================
Updated : 9/10/2008
By: Ilobmirt Tenk

=========
Licensing
=========

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

========
Overview
========

The Fossl Vending system is an Open Source creation of Ilobmirt Tenk
released under the LGPL license for use in business and education.
The goals of this vending system come threefold...

1) To add value to the products and services sold by the merchant
by services offered by the vending system

- The modularity of the vending system allows for added features
and services that a merchant might want or need

2) To provide an extra outlet of content creation

- LGPL licensing and an open communications protocol can allow
for both proprietary and open source modules to interact with
the vending system safeley on a legal level.

- The code and documentation shall continuously be under revision
to allow for enough detail to facilitate learning and inspire development

3) To enrich the lives of the community as a whole

- FOSSL Vendor could be a starting point for education in large in-world
projects involving the Linden Scripting Language

- A group has been created to share the thoughts and ideas of others.
whether they be veteran scripters or simply people with big ideas

- The vending system is a gift to the world. Those that put the effort to
make it happen wish for you to make what you can of it and enjoy the
fruits of their labor.


================
Current Features
================

FOSSL Vendor is capable of the following...

* Selling a Displayed object in-world

* Can operate as a Standalone unit or Network through an in-world server

* Notecard configured (Source code editing no longer necessary)

* Multi Panels (Vendor can display more than one product at a time)

* Buffered memory (Vendor will not run out of memory no matter how many products are being sold)

* Multi Category vending

* Controllable via, verbal commands

a) count

b) debug

c) reset

d) id

e) online

f) offline

g) memory

* Communication between vendor and server can be encrypted with a symmetric key

* Profit splitting Possible

* Catalog Vending Possible

* A different info card can be given out per product

=========
Wish List
=========

* More memory efficient client vendor script

* Faster display update process

* Include a mechanism for in-world network vending fault tolerance in the event server uuid is lost

* Package Management system for vendor component updates

=========
Upgrade Data
=========

The Following has changed since this project's conception...

v1.8 -

+ Patched broken e-mail retrieval system in FOSSLVendorMainClient
due to SL Server upgrade

v1.6 -

+ Added Concept for versioning

* Major vendor functionality and communications protocol
changes deserve its own version number

* Any changes to a module that retains compatibility with
all other modules means that it gets a subversion based
upon the date and time the changes were made

* Format goes like this...
v(Version).(Month).(Day).(Hour).(Minute)

* Its should be safe to use a module with the same version
as the other modules. Reguardless of subversion

+ Enhanced FOSSLVendorBuy module

* Added Split functionality between any number of people

* Split type could be either as a percent, L$, or US$

* L$0 priced items can be purchased with a click instead of
using a money event

+ Updated FOSSLVendorMainClient Module

* Fixed Symetric encryption algorythm

* Added email notifications of purchases

* Added a more granular info card per product functionality
allowing a different info notecard to be delivered based on
suffix

+ Updated FOSSLVendorMainServer Module

* Fixed Symetric encryption algorythm

* Added email notifications of product deliveries

* Set default of "Annon Access" to true. An email
owner identification system that is completey in-word
can't be created as of this time.

v1.0

+ System completeley re-written from scratch

+ Completey in-world networking possible through
server key

+ Notecard configurable

- Lost giftcard and web based database funtionality

v0.5

+ First Incarnation of the FOSSL Vending System

+ Giftard system

+ Sales tracking via webserver

=========
Frequently Asked Questions
=========

Q) How do categories and subcategories really work?

A) The Category and Subcategory system is based upon
index numbers starting from zero. When listing your products,
use the left number as the category and the right number as
the subcategory.

Q) Why are the (sub) categories numbers, not words?

A) When the vending machine is moving around various indexes,
it is much simpler and less time consuming for the vending machine to add and
subtract index positions than to determine the category or subcategory that
comes next. For example, hows the vendor supposed to know that cars come
after clothes and before that came houses? While doable, it would require
a more complex indexing system

Q) Can the FOSSL Vending system do ______?

A) It can do anything that is listed within official documentation.
If a feature isn't listed, its not currently supported within the official
build of the vending system. However there are perhaps third parties
whom have developed addons to this vending system that supports
such funcitonality. If you are a scripter and understand the vending system's
open communications protocol, it should be simple to design an addon to
facilitate this functionality.

Q) Can I sell this vending system along with my own stuff?

A) Under the open source licence that this code is licenced under, it is
acceptable to sell this code granted the source code can be accessible in
some shape or form. If you are publishing changes made to this source code
you still can sell it granted it follows the same licence as well

Q) Can you help me with the vending system you made?

A) Perhaps. It depends if I have the time and in the mood to help others.
(which I usually am). You could consider joining the FOSSL Vendor community
to discuss the issues with peers. There is also a paid support option for those
businesses who want "official" support for the vending system.

Q) Nothing from the above describes my dillema. What now?

A) I'll keep an ear pealed to anything worthwhile to add to the faq.
Just ask, and I might answer and add this to any future documentation.
Nada Epoch
The Librarian
Join date: 4 Nov 2002
Posts: 1,423
Library bump
02-29-2008 08:48
:)
_____________________
i've got nothing. ;)
Ilobmirt Tenk
Registered User
Join date: 4 Jun 2007
Posts: 135
Vendor Readme
02-29-2008 08:58
FOSSL Vendor v1.8
=================

(c)2008 Ilobmirt Tenk

=====
INDEX
=====

0) Thanks...

1) Scripts

2) Setting Up the FOSSL Vending System

3) Networking the FOSSL Vending System

4) Configuring the FOSSL Vending System

5) Configurable Variables (FOSSL_CLIENT_SETTINGS)

6) Configurable Variables (FOSSL_SERVER_SETTINGS)

7) Configurable Variables (FOSSL_LINK_SETTINGS)

8) Configurable Variables (FOSSL_BUY_SETTINGS)

9) Setting Up Inventory

10) Verbal Commands (Vendor)

11) Verbal Commands (Server)




============
0| Thanks...
============

For all the following whom gave me a Secondlife, I wouldn't be here without you...

* Annette Paster
* Ronald Krugman
* LakotaWolf Dawg
* Foxler Nightfire
* Erro Zenovka
* Cessna Riel
* RCFM Community (Notably Lacy Musketeer, Koterie Itoku, and Bunny Halberd)
* Flyintails Community (Noteably Effsey Nelson, Gravity Wright, Sera Kochav, and Sasha Gable)
* The countless others I'm honored to call friend...

For all those who inspire my Secondlife, my mark on the earth wouldn't be here otherwise...

* Yiffy Yaffle
* Esmay Rand
* Fenrir Reitveld
* Kayla Stonecutter
* Suku Ming + Toby Rainbow
* Mephitis Jezebel + Firefox Breed
* Wingless Emoto
* Void Singer
* You =^_-=

I'd like to thank Linden Labs for hosting such a wonderfull social environment. Since joining this community,
I have never been closer to some of the coolest, most talented, and most social minds on this planet. :3

To all those I have mentioned and haven't mentioned, You deserve this recognition and thanks for at least
changing my world. Let this be the thanks I give to you for all the wonderfull things you've done.

To the world, I thank you for even giving me the time of day. :D
As a reward, I give to you the gifts of my scripting knowledge and passionate soul for free software.
I will provide you with a scripted vending solution that is open, alive, and free. Take it with open arms.
Use it, learn from it, nurture it, its something from me to you because you deserve it. I hope you have fun with your
gift as much as I had fun building it.

Sincerely,

~Ilobmirt Tenk

==========
1 | Scripts
==========

This version of the Fossl Vending system contains 6 lsl scripts
The following scripts are...

FOSSLVendorMainClient - This script manages the state of the vendor in general as well as keep track of the
Vendor index and update the displays.

FOSSLVendorProductDatabase - This script contains all of the inventory for your products within an inventory buffer.
Scripts can make out queries in its database using product category and subcategory index.
If the query isn't within the product buffer, this script will search the product notecard
for the requested item. The result of searching in the notecard will then be added to the buffer
for quicker access.

FOSSLVendorLink - This script when clicked notifies the Vendor to move to a certain
product index. If specified, the script will also register itself
into FOSSLVendorMainClient as a display to show its associated
product.

FOSSLVendorBuy - This script when paid a specified amount, will notify FOSSLVendorMainClient
that a sale has been made. It will also get messages from FOSSLVendorMainClient
to change the amount one has to pay to get a product. FOSSLVendorBuy is also now
in charge of splitting the profits of a sale as well as distribute free items upon touch.

FOSSLVendorInfo - This Script when clicked, will notify FOSSLVendorMainClient that a person requests
an information notecard.

FOSSLVendorMainServer - This script will help keep all the client vendors updated with the uuid of
the products notecard. It will also give inventory to a specified uuid upon request.

FOSSLVendorEmailAgent - This script will offload the 20 second script delay penalty from either
FOSSLVendorMainClient or FOSSLVendorMainServer.

======================================
2 | Setting Up the FOSSL Vending System
======================================

1) Design your own vending system, or use a pre-existing design.

2) You need a place to have the FOSSLVendorMainClient script in. Wherever youre placing it, you also need a
notecard called "FOSSL_CLIENT_SETTINGS" to configure it.

3) You need a place to keep track of inventory. Find a logical place to put FOSSLVendorProductDatabase in.
I tend to prefer placing it within the same prim as FOSSLVendorMainClient.

4) You need a place to show your products or move the vendor index around. For each prim that does that, add
the FOSSLVendorLink script in along with its configuration notecard "FOSSL_LINK_SETTINGS".

5) For all prims that an avatar might pay in, add the script FOSSLVendorBuy in it. Wherever youre placing it, you also need a
notecard called "FOSSL_BUY_SETTINGS" to configure it.

6) For all prims that you want to have request for an information notecard, insert the script FOSSLVendorInfo.

7) If you haven't already, configure the "FOSSL_CLIENT_SETTINGS" , "FOSSL_BUY_SETTINGS", and the "FOSSL_LINK_SETTINGS"
notecards.

8) If the vendor is standalone, add a products notecard in the same prim containing the FOSSLVendorClient
script. Its name should be "FOSSL_PRODUCTS_LIST" by default unless configured in the "FOSSL_CLIENT_SETTINGS"
notecard. If the vendor is networked, proceed to the next section.

======================================
3 | Networking the FOSSL Vending System
======================================

1) Rezz an empty prim

2) Insert the FOSSLVendorMainServer script along with its configuration notecard "FOSSL_SERVER_SETTINGS".

3) Add a products notecard ("FOSSL_PRODUCTS_LIST" by default) to the server.

4) by now, you should have recieved a uuid from the server. Copy this UUID for later.

5) In the vendor client, edit "FOSSL_CLIENT_SETTINGS" so that the variable "server" is equal to the server uuid.

(optional)
6) To eliminate the 20 second delay involved with llEmail, add the FOSSLVendorEmailAgent script to both the server
and client vendor object. Configure the "FOSSL_CLIENT_SETTINGS" and "FOSSL_SERVER_SETTINGS" notecard so that
the "email agents" variable is equal to 1 (TRUE).

=======================================
4 | Configuring the FOSSL Vending System
=======================================

The scripts that compose the vending system contain variables that one can change via, a notecard.
The notecard name may be different depending upon the script that uses it, but the general mechanics are
the same. Each line is like an equation. Whatever's on the left of the "=" is a variable name.
Whatever's to the right of the "=" is its value. The scripts will read the notecards from top to bottom
so lines with the same variable later in the notecard will overwrite values defined earlier in the notecard.
Variable names don't take into account the capitalization of the name or how far it is away from the "=" character.
Variable values do take into account the capitalization, but dont care how far it is away from the "=" character.
Variable values for "TRUE" or "FALSE" can't be transfered to an interger. Instead, try using "1" for "TRUE" and
"0" for "FALSE".

=================================================
5 | Configurable Variables (FOSSL_CLIENT_SETTINGS)
=================================================

loading texture - (DEFAULT: 56617727-a972-f7d2-a730-484644a1fcb7 )
Whenever vendor is retrieving item data for display, vendor will change the display to this
texture uuid to represent that the product for this index is being retrieved.

offline texture - (DEFAULT: b8426d53-221d-9fc2-5b29-3ef16e2bd7a3 )
If the vendor is configured to be networked and that the server it has been configured to contact might not be online or if
the vendor's owner requested it to become offline,the vendor will use this texture uuid on all displays to signify that the vendor is unusable.

nothing texture - (DEFAULT: 93481f65-67ff-f166-cc64-e6fe1069c1c1 )
When no product is found for a certain index, the vendor will use this texture uuid to show that no product is available
for that index.

product card - (DEFAULT: "FOSSL_PRODUCTS_LIST" )
Vendor will use this notecard to load its products that the owner wants to sell

info card - (DEFAULT: "INFO" )
Whenever information has been requested, give the person who requested it a notecard of that name.

comm channel - (DEFAULT: 45 )
Vendor owner will use this channel to give the vendor certain commands that it should act out.

buffer - (DEFAULT: 0 )
Vendor will not load the complete list of products into an array as other vendors normally do.
To conserve script memory, the vendor will keep a list of products in a list of a certain size.
The size of this list is as large as the number of displays used to show products plus the value
of the buffer. Increasing this value will reduce the chance that the vendor will retrieve the product
from a notecard slowing the vendor down. Having a buffer that is too large will however cause the script to
produce a stack heap collision.

server - (DEFAULT: NULL_KEY )
When set to a key value other than NULL_KEY, vendor will try to network with that uuid in a networked mode instead of
relying on its own inventory in a standalone mode.

key - (DEFAULT: "" )
When set to a value other than "", vendor will encrypt its communications between itself and the server using this shared key.

refresh - (DEFAULT: 3,600 seconds = 1 hour )
Whenever vendor is in a networked mode, vendor will try to clear its inventory out and obtain the latest product card uuid ensuring
the vendor has the latest product line.

timeout - (DEFAULT: 60 seconds = 1 minute )
The server may not reply the the vendor immediately. Give the server this long to repond to the requests of this vendor.
If server didn't repond to the requests of the vendor in this time, chances are, server might not exist. Vendor will go offline
after the timeout has occured.

email agents - (DEFAULT: 0 )
If vendor is networked and there are dedicated e-mail scripts to offload the 20 second script sleep penalty, setting this value to 1
will make the vendor use the dedicated script keeping the vendor active instead of running into the 20 second e-mail penalty.

email - (DEFAULT: "";)
Whenever there is a sale of a product, if this variable is set to a value other than "", it will send a notification email to that address
about whom bought what with a slurl link that one could click on to teleport themselves to that vendor.


=================================================
6 | Configurable Variables (FOSSL_SERVER_SETTINGS)
=================================================

comm channel - (DEFAULT: 54 )
Server owner will use this channel to give the server certain commands that it should act out.

product card - (DEFAULT: "FOSSL_PRODUCTS_LIST" )
Vendor will use this notecard to load its products that the owner wants to sell. Server will give the uuid of this card out to
the vendors that request it.

email agents - (DEFAULT: 0 )
If server has a dedicated e-mail script to offload the 20 second script sleep penalty, setting this value to 1
will make the server use the dedicated script keeping the server active instead of running into the 20 second e-mail penalty.

key - (DEFAULT: "" )
When set to a value other than "", server will encrypt its communications between itself and the vendor using this shared key.

anon access - (DEFAULT: 1 )
When set to 1, server will accept requests from in-world objects owned by all people. Otherwise, server will only resond to requests
that come from in-world objects of the same owner.

outside access - (DEFAULT: 0 )
When set to 1, server wil accept requests that came from outside Secondlife. Otherwise, requests are limited to in-world objects.
To make use of this variable, "anon access" must be set to 1.

email - (DEFAULT: "";)
Whenever there is a request for product deliverey, if this variable is set to a value other than "", it will send a notification email to
that address about whom bought what with a slurl link that one could click on to teleport themselves to that server.

===============================================
7 | Configurable Variables (FOSSL_LINK_SETTINGS)
===============================================

images - (DEFAULT: 0 )
When set to 1, the containing prim will be used to show a product with associated index.

absolute category - (DEFAULT: 0)
When set to 1, the assigned Category index will not change as vendor index changes

category - (DEFAULT: 0 )
This sets the category index of the link. When containing prim is clicked, this well tell the vendor to move the category either to
that index, or relative by that index. This depends on whether or not the category is absolute or relative.

absolute subcategory - (DEFAULT: 0)
When set to 1, the assigned subCategory index will not change as vendor index changes

subcategory - (DEFAULT: 0 )
This sets the subcategory index of the link. When containing prim is clicked, this well tell the vendor to move the subcategory
either to that index, or relative by that index. This depends on whether or not the subcategory is absolute or relative.

===============================================
8 | Configurable Variables (FOSSL_BUY_SETTINGS)
===============================================

deed to group - (DEFAULT: 0)
This variable allows FOSSLVendorBuyModule to operate when vendor is deeded to a group

split - (DEFAULT: 0)
This variable sets the maximum number of splits between a certain number of avatars.
A value of zero disables profit splitting.

split __ key - (DEFAULT: NULL_KEY)
Where __ could be any number after zero, split __ key sets the key of the avatar that
will get a commission per sale excluding the sale of free items.

split __ amount - (DEFAULT: 0)
Where __ could be any number after zero, split __ amount sets the amount that the
specified avatar will get as a commission per sale excluding the sale of free items.

split __ type - (DEFAULT: "L$";)
Where __ could be any number after zero, split __ type sets the unit of value that
an avatar will get as a commission per sale excluding the sale of free items. Valid
split types are L$, US$, and percentage.

=======================
9 | Setting Up Inventory
=======================

Notecard configuration of vendor products is different than that of setting up a configuration card for vendor scripts.
Each line of this notecard contains a variable length record of the inventory to be sold. Record structure is as follows...

(Category)#(SubCategory)#(Price)#(Inventory Name)#(Texture UUID)

When one creates a list of records, one must make sure that there are no spaces between elements separated by the "#" character.
If one doesn't know the uuid of the texture, the option to copy the uuid of their own images can be found when right clicking on them in inventory.

============================
10 | Verbal Commands (Vendor)
============================

online - When vendor is in an offline mode, attempts to return functioning status to the vendor.

offline - When vendor is functioning, takes the vendor into an offline mode.

reset - Resets vending system scripts.

debug - As the vendor operates, vendor will give its owner an indication of its current processes through verbose output.

count - Returns the number of information notecard requests from this vendor

memory - Returns the number of bytes that are free within the vendor

============================
11 | Verbal Commands (Server)
============================

debug - As the server operates, server will give its owner an indication of its current processes through verbose output.

id - returns the uuid used by the containing object. Use it for configuring the vendors in networked mode.

reset - Resets server system scripts.

count - Returns the number of product deliveries since initialization
Ilobmirt Tenk
Registered User
Join date: 4 Jun 2007
Posts: 135
FOSSLVendorInfo
02-29-2008 09:02
CODE

//---------------------------------------------------------------------------------//
//Copyright Info Below... Please Do not Remove //
//---------------------------------------------------------------------------------//

//(c)2007 Ilobmirt Tenk

//This file is part of the FOSSL Vendor Project

// FOSSL Vendor is free software; you can redistribute it and/or modify
// it under the terms of the Lesser GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.

// FOSSL Vendor is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// Lesser GNU General Public License for more details.

// You should have received a copy of the Lesser GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

//---------------------------------------------------------------------------------//
//Copyright Info Above... Please Do not Remove //
//---------------------------------------------------------------------------------//

default
{

touch_start(integer total_number)
{

//If an avatar touches this object, tell the main script that (insert avatar's name here) touched it.
if (llDetectedType(0) & AGENT){
llMessageLinked(LINK_ROOT,0,"infoRequested#" + llDetectedName(0),NULL_KEY);
}

}
}
Ilobmirt Tenk
Registered User
Join date: 4 Jun 2007
Posts: 135
FOSSLVendorLink
02-29-2008 09:05
CODE

//---------------------------------------------------------------------------------//
//Copyright Info Below... Please Do not Remove //
//---------------------------------------------------------------------------------//

//(c)2007 Ilobmirt Tenk

//This file is part of the FOSSL Vendor Project

// FOSSL Vendor is free software; you can redistribute it and/or modify
// it under the terms of the Lesser GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.

// FOSSL Vendor is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// Lesser GNU General Public License for more details.

// You should have received a copy of the Lesser GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

//---------------------------------------------------------------------------------//
//Copyright Info Above... Please Do not Remove //
//---------------------------------------------------------------------------------//

//=================================================================//
//List all the global variables here...
//=================================================================//

//count of the current Notecard line to read
integer intSettingLines = 0;

//key of the notecard line to be read
key keySettingsId;

//determines if the vendor requested for this script to register if it was meant to display images
integer blnRequested = FALSE;

//determines if it is ready to make that response
integer blnReadyToPost = FALSE;

//determines if this object displays debugging output
integer blnDebug = FALSE;

//=================================================================//
//Customize the following variables
//=================================================================//

//relative category index of the vendor
integer intCategory = 0;

//relative subcategory index of the vendor
integer intSubCategory = 0;

//Is the Category of the vendor absolute (true) or relative (False)
integer blnAbsoluteCategory = FALSE;

//Is the SubCategory of the vendor absolute (true) or relative (False)
integer blnAbsoluteSubCategory = FALSE;

//does this prim display images?
integer blnImages = FALSE;

//=================================================================//
//Customize the above variables
//=================================================================//

//This displays messages to the owner if debug mode has been set to true
debugMessage(string strMessage){

if(blnDebug == TRUE){

llOwnerSay("FOSSLVendorLink: " + strMessage);

}

}

default
{

//start reading the settings notecard upon script start
state_entry(){

//Obtain the first line of the vendor link settings
keySettingsId = llGetNotecardLine("FOSSL_LINK_SETTINGS", intSettingLines);


}

//Reset the script when the container object gets rezzed
on_rez(integer intParam){

llResetScript();

}

//If somehing within the vendor changed, update the setting by resetting the script
changed(integer change){

// If I change the contents of the vendor
if(change & CHANGED_INVENTORY){

//reset the script to make use of the changes
llResetScript();

}

}

//Read the link settings notecard. Configure the link based on each line.
dataserver(key query_id, string data) {

if (query_id == keySettingsId) {
if (data != EOF) { // not at the end of the notecard

debugMessage("Notecard Line = \"" + data + "\"");
//split the record into variable names and values
list lstSplit = llParseString2List(data,["="],[]);
string strVariable = llToUpper(llStringTrim(llList2String(lstSplit,0),STRING_TRIM));
string strValue = llStringTrim(llList2String(lstSplit,1),STRING_TRIM);

if(strVariable == "CATEGORY"){

intCategory = (integer) strValue;
debugMessage("intCategory = " + (string) intCategory);


}
if(strVariable == "SUBCATEGORY"){

intSubCategory = (integer) strValue;
debugMessage("intSubCategory = " + (string) intSubCategory);

}
if(strVariable == "IMAGES"){

blnImages = (integer) strValue;
debugMessage("blnImages = " + (string) blnImages);

}
if(strVariable == "ABSOLUTE CATEGORY"){

blnAbsoluteCategory = (integer) strValue;
debugMessage("blnAbsoluteCategory = " + (string) blnAbsoluteCategory);

}
if(strVariable == "ABSOLUTE SUBCATEGORY"){

blnAbsoluteSubCategory = (integer) strValue;
debugMessage("blnAbsoluteSubCategory = " + (string) blnAbsoluteSubCategory);

}

keySettingsId = llGetNotecardLine("FOSSL_LINK_SETTINGS", ++intSettingLines); // request next line
}
else{

//If this link is a display, add self to vendor's list of displays
if(blnImages == TRUE){

blnReadyToPost = TRUE;

if(blnRequested == TRUE){

debugMessage("addScreen#" + (string) blnAbsoluteCategory + "#" + (string) intCategory + "#"+ (string) blnAbsoluteSubCategory + "#" + (string) intSubCategory);
llMessageLinked(LINK_ROOT,0,"addScreen#" + (string) blnAbsoluteCategory + "#" + (string) intCategory + "#"+ (string) blnAbsoluteSubCategory + "#" + (string) intSubCategory,NULL_KEY);

}

}

}
}

}

//Tell the vendor to change index whenever it gets touched by an avatar
touch_start(integer total_number)
{

//If an avatar touches this object, tell the main script to change its selected index
//If the index is relative to 0#0, ignore the click
if ((llDetectedType(0) & AGENT) && ((blnAbsoluteCategory == TRUE || blnAbsoluteSubCategory == TRUE) || (intCategory != 0 || intSubCategory != 0)) ){

debugMessage("linkClicked#"+ (string) blnAbsoluteCategory + "#" + (string) intCategory + "#"+ (string) blnAbsoluteSubCategory + "#" + (string) intSubCategory);
llMessageLinked(LINK_ROOT,0,"linkClicked#"+ (string) blnAbsoluteCategory + "#" + (string) intCategory + "#"+ (string) blnAbsoluteSubCategory + "#" + (string) intSubCategory,NULL_KEY);

}

}

link_message(integer sender_number, integer number, string message, key id)
{

//Separate the linked message into the function and variables
list lstMessage = llParseString2List(message,["#"],[]);
string strFunction = llList2String(lstMessage,0);

//getDisplays
if(strFunction == "getDisplays" ){

blnRequested = TRUE;
debugMessage("Link has been requested to register itself as a diplay if possible.");
debugMessage("blnRequested = " + (string) blnRequested);
debugMessage("blnReadyToPost = " + (string) blnReadyToPost);
debugMessage("blnImages = " + (string) blnImages);

if(blnImages == TRUE){

debugMessage("Link is ready to post, registering...");
debugMessage("addScreen#" + (string) blnAbsoluteCategory + "#" + (string) intCategory + "#"+ (string) blnAbsoluteSubCategory + "#" + (string) intSubCategory);
llMessageLinked(LINK_ROOT,0,"addScreen#" + (string) blnAbsoluteCategory + "#" + (string) intCategory + "#"+ (string) blnAbsoluteSubCategory + "#" + (string) intSubCategory,NULL_KEY);

}

}
//debugMode#blnEnabled
else if(strFunction == "debugMode"){

blnDebug = (integer) llList2String(lstMessage,1);

}

}

}
Ilobmirt Tenk
Registered User
Join date: 4 Jun 2007
Posts: 135
FOSSLVendorBuy (v1.6)
02-29-2008 09:09
CODE

//FOSSLVendorBuyModule
//---------------------------------------------------------------------------------//
//Copyright Info Below... Please Do not Remove //
//---------------------------------------------------------------------------------//

//(c)2007 Ilobmirt Tenk

//This file is part of the FOSSL Vendor Project

// FOSSL Vendor is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.

// FOSSL Vendor is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

//---------------------------------------------------------------------------------//
//Copyright Info Above... Please Do not Remove //
//---------------------------------------------------------------------------------//
// modified by Fleur Dollinger 6 April 2008 - enable income splitting
// modified by Fleur Dollinger 28 April 2008 - option to disable deed to group

//=================================================================//
//List all the global variables here...
//=================================================================//

//This is the current L$ to US$ rate
float gfltLindenToUSDollarRate = 0.004;
//This is the key used to retrieve the L$ to US$ data via http
key gkeyHTTPLindenToUSDollarRate = NULL_KEY;

//This is the current price of the object displayed in the vendor
integer gintCurrentPrice = 0;

//count of the current Notecard line to read
integer gintSettingLines = 0;

//key of the notecard line to be read
key gkeySettingsId;

//determines if this object displays debugging output
integer gblnDebug = FALSE;

//income can be split between any number of avatars (as well as owner)
//Set gintNumSplit to a value greater than zero and set set up appropriate details for each split.
integer gintNumSplit = 0;

//Each Split is based upon 3 indexes of a list
//Split Array = [(Avatar Key), (Split amount), (Split Type)]
//Avatar Key - The key of the avatar that one plans to split a profit with
//Split Amount - How much that avatar will get per sale
//Split Type - What kind of measurement are we talking about? Percent? L$? US$?
list glstDefaultSplits = []; //Splitting scheme for all items sold by the vendor

//DEFAULT IS TO DISABLE DEED TO GROUP
// note that that the vendor will not be able to refund overpayments or split and distribute money if the vendor is deeded to group so its recommended to always leave this disabled
integer gintDeedToGroup = FALSE;
//get the object's owner - NULL_KEY
list groupD;

//This displays messages to the owner if debug mode has been set to true
debugMessage(string strMessage){

if(gblnDebug == TRUE){

llOwnerSay("FOSSLVendorBuy: " + strMessage);

}
}


//Calculate the amount of cash given as it goes with profit splitting
splitMoney(integer amount)
{

integer intIndex = 0;
integer intLength = llGetListLength(glstDefaultSplits);
key keyAvatar = NULL_KEY;
integer intSplitCurrency = 0;
string strType = "";

for(intIndex = 0; intIndex < intLength; intIndex += 3 ){

keyAvatar = llList2Key(glstDefaultSplits,intIndex);
strType = llToUpper(llList2Key(glstDefaultSplits,intIndex + 2));
if(keyAvatar != NULL_KEY && keyAvatar != llGetOwner()){

//Is the type in US Dollars?
if(strType == "US$" || strType == "$"){

intSplitCurrency = (integer) (llList2Float(glstDefaultSplits,intIndex + 1) / gfltLindenToUSDollarRate);

}
//Is the type shown as a percentage?
else if(strType == "%"){

intSplitCurrency = (integer) ((llList2Float(glstDefaultSplits,intIndex + 1) * (float) amount) / 100.0);

}
//It must be a flat out L$ rate
else{

intSplitCurrency = llList2Integer(glstDefaultSplits,intIndex + 1);

}

llGiveMoney(keyAvatar, intSplitCurrency);
debugMessage("Splitting with "+ (string) keyAvatar +" L$" + (string) intSplitCurrency +".");

}

}

}

//In this state, vendor must accept debit permissions before using the vendor
default
{

state_entry()
{

groupD = llGetObjectDetails(llGetOwner(), [OBJECT_GROUP]);
debugMessage("GroupD:" + (string) llList2String(groupD,0));

//request permission on startup if not deeded to a group
if((gintDeedToGroup == 0 && (key) llList2String(groupD,0) == NULL_KEY) || gintDeedToGroup == 1){

//Asks vendor owner for the ability to withdraw cash from vendor owner's account.
llRequestPermissions(llGetOwner(),PERMISSION_DEBIT );

}
else{

llWhisper(0,"Deeding this vendor to a group is not permitted. Debit permission has been denied.");
}

}


on_rez(integer start_param)
{

//reset script upon rezz
llResetScript();

}

link_message(integer sender_number, integer number, string message, key id)
{

//Separate the linked message into the function and variables
list lstMessage = llParseString2List(message,["#"],[]);
string strFunction = llList2String(lstMessage,0);

if(strFunction == "goingOnline"){

//prevent vendor from staying online untill permissions are granted
llMessageLinked(LINK_SET,0,"goOffline",NULL_KEY); //Tell Vendor to go offline if not already


}
//debugMode#blnEnabled
else if(strFunction == "debugMode"){

gblnDebug = (integer) llList2String(lstMessage,1);

}


}

//Depending on if avatar accepts or declines request, either stay in this state, or move on...
run_time_permissions(integer permissions){

//if user accepted debit permissions
if(permissions & PERMISSION_DEBIT){

state transactionsSetup; //Change state to setup for transactions

}
else if(!(permissions & PERMISSION_DEBIT)){

llOwnerSay("Sorry, but this vendor requires its owner to allow for debit permissions.");
llOwnerSay("To enable vendor service, touch the containing prim of the payment script, and accept the debit request.");

}

}

touch(integer total_number){

if ((gintDeedToGroup == 0 && (key) llList2String(groupD,0) == NULL_KEY) || gintDeedToGroup == 1){

//Asks vendor owner for the ability to withdraw cash from vendor owner's account.
llRequestPermissions(llGetOwner(),PERMISSION_DEBIT );

}
else{

llWhisper(0,"Deeding this vendor to a group is not permitted. Debit permission has been denied.");
}

}

}

//This state sets up all the data before transactions are to occur
state transactionsSetup{

state_entry(){

llOwnerSay("Vendor is now able to make transactions with this script.\nReading Configuration data...");
//Obtain the first line of the vendor buy settings;
gkeySettingsId = llGetNotecardLine("FOSSL_BUY_SETTINGS", gintSettingLines);


}

changed( integer vBitChanges ){

//Detect change of ownership, as this may indicate that the owner has deeded this object to a group, in which case we may want to disable Debit permission.
//If any kind of split is activated you will have to disallow deeding this vendor to the group as groups cannot 'pay' other people out of the split.
//This is really only relevant if you are giving this vendor to other people to sell your products for you.
if (vBitChanges & CHANGED_OWNER){

llResetScript();

}

}

//Reset the vendor upon rezzing
on_rez(integer start_param){

llResetScript();

}

//Read the link settings notecard. Configure the link based on each line.
dataserver(key query_id, string data) {

if (query_id == gkeySettingsId) {

if (data != EOF) { // not at the end of the notecard

debugMessage("Notecard Line = \"" + data + "\"");
//split the record into variable names and values
list lstSplit = llParseString2List(data,["="],[]);
string strVariable = llToUpper(llStringTrim(llList2String(lstSplit,0),STRING_TRIM));
string strValue = llStringTrim(llList2String(lstSplit,1),STRING_TRIM );

// get setting for intDeedToGroup (default is 0 = disable)
if(strVariable == "DEED TO GROUP"){

gintDeedToGroup = (integer) strValue;
debugMessage("intDeedToGroup = " + strValue);

}

//Get settings for splits
//Start By looking for "split"
//Since there's some dynamicism to this, some more proccessing is neccesary
if(llGetSubString(strVariable, 0, 4) == "SPLIT"){

list lstSplitVariableDetails = llParseString2List(strVariable,[" "],[]);

//If it was just "Split" after all, user just wants to set the number of profit splitting in the vendor
if(llGetListLength(lstSplitVariableDetails) == 1){

gintNumSplit = (integer) strValue;
//if income splitting is enabled, must disable Deed To Group
if (gintNumSplit > 0){

gintDeedToGroup = 0;
debugMessage("DEED TO GROUP DISABLED AS INCOME SPLITTING HAS BEEN ACTIVATED");

}

debugMessage("SPLIT = " + (string) gintNumSplit);

//Create an array of splits with just default values
integer intIndex;

//Reset values of default split
glstDefaultSplits = [];

for(intIndex = 0; intIndex < gintNumSplit; intIndex++){

//Add an entity to split with using default values
glstDefaultSplits += [NULL_KEY,0,"L$"];

}

}
//There's more to it than that, Find out what part of the split needs to be set
else{

//Get the index that will be enacted upon
integer intSplitIndexDetails = llList2Integer(lstSplitVariableDetails, 1) - 1;
//Get more info on what the user wants set for the split
string strSubVariable = llList2String(lstSplitVariableDetails, 2);

//The user wants to set the recipient key for the split
if(strSubVariable == "KEY"){

//Replace the index with the new key of the recipient
glstDefaultSplits = llListReplaceList(glstDefaultSplits, [strValue], (intSplitIndexDetails * 3), (intSplitIndexDetails * 3));
debugMessage("glstDefaultSplits["+ (string) (intSplitIndexDetails * 3) +"] = " + strValue);

}
//The user wants to set the amount the recipient gets
else if(strSubVariable == "AMOUNT"){

//Replace the index with the new currency value to be shared
glstDefaultSplits = llListReplaceList(glstDefaultSplits, [strValue], ((intSplitIndexDetails * 3) + 1), ((intSplitIndexDetails * 3) + 1));
debugMessage("glstDefaultSplits["+ (string) ((intSplitIndexDetails * 3) + 1) +"] = " + strValue);

}
//The user wants to set the type of split the recipient gets
else if(strSubVariable == "TYPE"){

//Replace the index with the new type of split to be shared
glstDefaultSplits = llListReplaceList(glstDefaultSplits, [strValue], ((intSplitIndexDetails * 3) + 2), ((intSplitIndexDetails * 3) + 2));
debugMessage("glstDefaultSplits["+ (string) ((intSplitIndexDetails * 3) + 2) +"] = " + strValue);

}

}

}

gkeySettingsId = llGetNotecardLine("FOSSL_BUY_SETTINGS", ++gintSettingLines); // request next line
}
//No more lines to read in the configuration notecard
else{

llOwnerSay("Vendor is now able to sell products. Enabling transactions.");
llMessageLinked(LINK_SET,0,"goOnline",NULL_KEY); //Tell Vendor to go online if not already
state transactionsAcceptable; //Change state to allow for transactions

}

}

}
}

//In this state, vendor is ready to sell products
//Allow transactions to commence
state transactionsAcceptable{

state_entry(){

//Time to start getting lindex data
gkeyHTTPLindenToUSDollarRate = llHTTPRequest("http://secondlife.com/httprequest/homepage.php", [HTTP_METHOD, "GET"], "");
//Poll For Lindex Data every five minutes (300 seconds)
llSetTimerEvent(300.0);

}

changed( integer vBitChanges ){

//Detect change of ownership, as this may indicate that the owner has deeded this object to a group, in which case we may want to disable Debit permission.
//If any kind of split is activated you will have to disallow deeding this vendor to the group as groups cannot 'pay' other people out of the split.
//This is really only relevant if you are giving this vendor to other people to sell your products for you.
if (vBitChanges & CHANGED_OWNER){

llResetScript();

}

}

//Reset the vendor upon rezzing
on_rez(integer start_param){

llResetScript();

}

//set the current price to the value of num. This is incase that the user over/under pays for the item
link_message(integer sender_num, integer num, string str, key id){

if(str == "updatePrice"){

gintCurrentPrice = num;

//If the price of the item is free
if(gintCurrentPrice == 0){

state giveAwayFreeProducts;

}

}

}

//Whenever an avatar pays an object that this script is in, check for correct amount.
//Then if correct amount is payed, notify the system of a sale
money(key giver, integer amount) {

// has the user paid the correct amount?
if (amount == gintCurrentPrice){

// if so, thank the payer by name.
llSay(0,"Thank you, " + llKey2Name(giver) + ".");
//give them the lovely object displayed on the vendor

//send message back to root object to give out product
llMessageLinked(LINK_ROOT,0,"itemBought#" + (string)giver,NULL_KEY);

// if settings card includes split details
if (gintNumSplit > 0){

debugMessage("Splitting Income...");
splitMoney (amount);

}

}

// is the amount paid less than it needs to be?
else if (amount < gintCurrentPrice){

// if so, tell them they're getting a refund, then refund their money.
llSay(0,"You didn't pay enough, " + llKey2Name(giver) + ". Refunding your payment of L$" + (string)amount + ".");
llGiveMoney(giver, amount); // refund amount paid.

}

// if it's not exactly the amount required, and it's not less than the amount required,
// the payer has paid too much.
else{

// tell them they've overpaid.
integer intRefund = amount - gintCurrentPrice; // determine how much extra they've paid.
llSay(0,"You paid too much, " + llKey2Name(giver) + ". Your change is L$" + (string)intRefund + ".");
llGiveMoney(giver, intRefund); // refund their change.
//give them the lovely object displayed on the vendor

//send message back to root object to give out product.
llMessageLinked(LINK_ROOT,0,"itemBought#" + (string)giver,NULL_KEY);

// if settings card includes split details
if (gintNumSplit > 0){

debugMessage("Splitting Income...");
splitMoney (amount);

}

}

}

//Five minutes have elapsed, lets refresh our lindex data
timer(){

//Time to start getting lindex data
gkeyHTTPLindenToUSDollarRate = llHTTPRequest("http://secondlife.com/httprequest/homepage.php", [HTTP_METHOD, "GET"], "");

}

//Use http in this script pureley to collect lindex data
http_response(key request_id, integer status, list metadata, string body){

//If the requested lindex page reponded correctly
if(request_id == gkeyHTTPLindenToUSDollarRate && status == 200){

//Split that garbled mess into data we can actually use
list lstMetaData = llParseString2List(body,["\t","\n"],[]);
//Set the rate using the 17th element of that data
gfltLindenToUSDollarRate = 1.0 / llList2Float(lstMetaData,17);


}

}

}

//In This state, the item is purchased whenever a prim is clicked upon
//This state is exited whenever the price changes to something that isn't free
state giveAwayFreeProducts{

changed( integer vBitChanges ){

//Detect change of ownership, as this may indicate that the owner has deeded this object to a group, in which case we may want to disable Debit permission.
//If any kind of split is activated you will have to disallow deeding this vendor to the group as groups cannot 'pay' other people out of the split.
//This is really only relevant if you are giving this vendor to other people to sell your products for you.
if (vBitChanges & CHANGED_OWNER){

llResetScript();

}

}

//Reset the vendor upon rezzing
on_rez(integer start_param){

llResetScript();

}

//set the current price to the value of num. This is incase that the user over/under pays for the item
link_message(integer sender_num, integer num, string str, key id){

if(str == "updatePrice"){

gintCurrentPrice = num;

//If the price isn't free anymore
if(gintCurrentPrice > 0){

state transactionsAcceptable;

}

}

}

//The User simply needs to touch the prim in order to get the item
touch_end(integer num_detected){

//send message back to root object to give out product.
llMessageLinked(LINK_ROOT,0,"itemBought#" + (string) llDetectedKey(0),NULL_KEY);

}

}
Ilobmirt Tenk
Registered User
Join date: 4 Jun 2007
Posts: 135
FOSSLVendorEmailAgent
02-29-2008 09:11
CODE

//---------------------------------------------------------------------------------//
//Copyright Info Below... Please Do not Remove //
//---------------------------------------------------------------------------------//

//(c)2007 Ilobmirt Tenk

//This file is part of the FOSSL Vendor Project

// FOSSL Vendor is free software; you can redistribute it and/or modify
// it under the terms of the Lesser GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.

// FOSSL Vendor is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// Lesser GNU General Public License for more details.

// You should have received a copy of the Lesser GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

//---------------------------------------------------------------------------------//
//Copyright Info Above... Please Do not Remove //
//---------------------------------------------------------------------------------//

default
{

//Upon hearing "EmailRequest" send an e-mail to a designated target
link_message(integer sender_number, integer number, string message, key id)
{

//split the message into manageable bits
//intent of the message can be defined in index 0
list lstMessageParsed = llParseString2List(message,["#"],[]);

//Is it a request for an e-mail to be sent?
if(llList2String(lstMessageParsed,0) == "EmailRequest"){

//Send an e-mail using the rest of the list
llEmail(llList2String(lstMessageParsed,1),llList2String(lstMessageParsed,2),llList2String(lstMessageParsed,3));

}

}

}
Ilobmirt Tenk
Registered User
Join date: 4 Jun 2007
Posts: 135
FOSSLVendorProductDatabase
02-29-2008 09:16
CODE

//---------------------------------------------------------------------------------//
//Copyright Info Below... Please Do not Remove //
//---------------------------------------------------------------------------------//

//(c)2007 Ilobmirt Tenk

//This file is part of the FOSSL Vendor Project

// FOSSL Vendor is free software; you can redistribute it and/or modify
// it under the terms of the Lesser GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.

// FOSSL Vendor is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// Lesser GNU General Public License for more details.

// You should have received a copy of the Lesser GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

//---------------------------------------------------------------------------------//
//Copyright Info Above... Please Do not Remove //
//---------------------------------------------------------------------------------//

//=================================================================//
//List all the global variables here...
//=================================================================//

list lstProducts; //List of products loaded into memory. Product records are as follows...
//current#Category#Subcategory#Price#Name#TextureUUID

list lstItemRequestList; //List of items to be requested from the server
//each record is in the form of "Category#SubCategory#DatabaseKey#LineRead"

integer intItemRequestList = 0; //Number of item database requests to send to the server

integer intMaxProducts = 0; //Maximum Number of products that can be loaded

integer intProductListCounter = -2147483646; //Keeps track of a counter used for indicating the most and needed products in category

key keyProductsUUID = NULL_KEY; //The uuid of the notecard to be read for products

integer blnDebug = FALSE; //Determines if script will output debugging messages

//=================================================================//
//Define the following functions
//=================================================================//

//This displays messages to the owner if debug mode has been set to true
debugMessage(string strMessage){

if(blnDebug == TRUE){

llOwnerSay("FOSSLProductDatabase: " + strMessage);

}

}

//Find the product array index based upon the Category and Sub category Index
//If Not found, returns -1
integer findIndexByCategory(integer intCategory, integer intSubCategory){

integer intProductListIndex = -1;
integer intTotalLength = llGetListLength(lstProducts);
integer blnFound = FALSE;
string strSearchCondition = ((string)intCategory + "#" +(string)intSubCategory);

list lstProduct = [];

do{

intProductListIndex++;
lstProduct = llParseString2List(llList2String(lstProducts,intProductListIndex),["#"],[]);

//current#Category#Subcategory#Price#Name#TextureUUID
if(strSearchCondition == (llList2String(lstProduct,1) + "#" + llList2String(lstProduct,2))){

blnFound = TRUE;

}


} while(blnFound == FALSE && intProductListIndex < intTotalLength);

if(blnFound == TRUE){

return intProductListIndex;

}
else{

return -1;

}

}

//when product list counter has reached maximum, use this to start back from square 1
resetCounter(){

debugMessage("Query counter Maxed out. Resetting query.");

integer intItemsIndex = -1;
integer intItemsLength = llGetListLength(lstProducts);
integer intMinimum = 0;
integer intMaximum = 0;
integer intDifference = 0;
list lstOpenedIndex = [];

lstProducts = llListSort(lstProducts,1,TRUE);

intMinimum = (integer) llList2String(llParseString2List(llList2String(lstProducts,0),["#"],[]),0);

do{

++intItemsIndex;
lstOpenedIndex = llParseString2List(llList2String(lstProducts,intItemsIndex),["#"],[]);
intMaximum = (integer) llList2String(lstOpenedIndex,0);
intDifference = intMaximum - intMinimum;
lstOpenedIndex = llListReplaceList( lstOpenedIndex,[(string) (-2147483646 + intDifference)], 0,0);
lstProducts = llListReplaceList(lstProducts,[llDumpList2String(lstOpenedIndex,"#")], intItemsIndex,intItemsIndex);

}while(intItemsIndex < intItemsLength);


intProductListCounter = -2147483645 + intDifference; // set the counter to one greater than recent

}

//This function adds an item to the buffer
//If the buffer is full, replace the first item not being used by a display
//If the item is to be used by a display, update the displays.
addItem(string strItem){

debugMessage("Appending Item to Database");

//If the counter is more equal to the maximum integer,
//reset the database index for most and least used database queries
if(intProductListCounter == 2147483646){

resetCounter();

}

//If the number of products are less than that of the maximum, add it to the buffer
if((llGetListLength(lstProducts) - 1) < intMaxProducts){

debugMessage("Buffer not Full. Appending.");

//Use a space hack trick for conserving memory
//Expand lstProducts with an extra element
lstProducts += [ ((string) (++intProductListCounter)) + "#" + strItem];

}
//Otherwise, replace the first index that is least recent
else{

debugMessage("Buffer Full. Replacing least accessed index.");

//Sort lstProducts starting from least recent data to most recent data
lstProducts = llListSort(lstProducts,1,TRUE);
//Overwrite first, least used index with current product
lstProducts = llListReplaceList(lstProducts,[((string) (++intProductListCounter)) + "#" + strItem],0,0);

}

}

//This function adds item requests to the buffer before it starts obtaining them from the notecard
itemRequest(integer intCategory, integer intSubCategory, string strReturnRequest){

//Use memory conservative techniques to reduce memory footprint
//take that record and add it to the waitlist
//categoryRequest#subcategoryRequest#ReturnQuery#notecardKey#notecardLine
debugMessage("Reqesting data from notecard...");
lstItemRequestList = llListReplaceList((lstItemRequestList = []) + lstItemRequestList,[(string)intCategory + "#" + (string)intSubCategory + "#" + strReturnRequest + "#" + (string) llGetNotecardLine(keyProductsUUID,0) + "#0" ],intItemRequestList,intItemRequestList);

//increment # of items on the waitlist
intItemRequestList++;

}

//This function removes item requests by their index
removeItemRequest(integer intIndex){

//Use memory conservative techniques to reduce memory footprint
//remove the item by index
lstItemRequestList = llDeleteSubList((lstItemRequestList = []) + lstItemRequestList,intIndex,intIndex);

//decrement # of items on the waitlist
intItemRequestList--;


}

//Use this function to make database requests off temporary memory first
//If an index can't be found, make a request off of notecard memory
dbQuery(integer intCategory, integer intSubCategory, string strReturnRequest){

integer intFoundIndex = findIndexByCategory(intCategory,intSubCategory);
list lstFoundProduct = [];

//Index found... return the result and update the access couter on that item
if(intFoundIndex != -1){

//If the counter is more equal to the maximum integer,
//reset the database index for most and least used database queries
if(intProductListCounter == 2147483646){

resetCounter();

}

//Split the found product into its elements for individual element manipulation
lstFoundProduct = llParseString2List(llList2String(lstProducts,intFoundIndex),["#"],[]);

//Advance the database access counter indicating this is the latest item in the database
lstFoundProduct = llListReplaceList(lstFoundProduct,[(string)(++intProductListCounter)],0,0);

debugMessage("Found Request in Buffer... returning values");

//return query to owner
//dbResults#ReturnQuery#(productRecord)
llMessageLinked(LINK_SET,0,"dbResults#" + strReturnRequest + "#" + llDumpList2String(llList2List(lstFoundProduct,1,-1),"#"),NULL_KEY);

}
//Index not found... time to make a notecard request
else{

debugMessage("Requested Query not found in Buffer. Retrieving data from source...");
itemRequest(intCategory,intSubCategory,strReturnRequest);

}

}

//=================================================================//
//Customize the above functions
//=================================================================//


default
{

//Activate this event when container script is rezzed
//Its best to just reset the database and start with fresh data
on_rez(integer start_param)
{

//Reset this script upon rezzing the containing prim
llResetScript();

}

//Activate this event when a companion script sends out a linked message
//Use this event to determine if that script is making a request of this script
//This script accepts database query requests, database resizing requests,
//database source requests, and database clearing
link_message(integer sender_number, integer number, string message, key id)
{

//Separate the linked message into the function and variables
list lstMessage = llParseString2List(message,["#"],[]);
string strFunction = llList2String(lstMessage,0);

//A scripted object wants to obtain information about a product
//dbRequest#requestKey#Category#SubCategory
if(strFunction == "dbRequest"){

debugMessage("dbRequest = " + llList2String(lstMessage,1) );
dbQuery((integer) llList2String(lstMessage,2), (integer) llList2String(lstMessage,3), llList2String(lstMessage,1));

}
//clearDatabase
else if(strFunction == "clearDatabase"){

lstProducts = [];

}
//setBuffer#bufferLength
else if(strFunction == "setBuffer"){

//Clear database
lstProducts = [];

//Reset database counter
intProductListCounter = -2147483646;

//Set the maximum # of products in inventory
intMaxProducts = (integer) llList2String(lstMessage,1);

}
//addBuffer#bufferLength
else if(strFunction == "addBuffer"){

//Set the maximum # of products in inventory
intMaxProducts += 1;

}
//setDB#productNotecardUUID
else if(strFunction == "setDB"){

//Clear out any requests and database inventory
lstProducts = [];
intItemRequestList = 0;
lstItemRequestList = [];

//reset inventory counter
intProductListCounter = -2147483646;

//Assign Key of products notecard to this uuid
keyProductsUUID = (key) llList2String(lstMessage,1);

}
//debugMode#blnEnabled
else if(strFunction == "debugMode"){

blnDebug = (integer) llList2String(lstMessage,1);

}
//getMemory
else if(strFunction == "getMemory"){

llOwnerSay("FOSSLVendorProductDatabase: Memory = " + (string) llGetFreeMemory() +"/16000 Bytes");

}

}

//Activate this event when a query couldn't find the solution in a list (fast)
//each request has a notecard line# and key to keep track of where they are
//If request can't find the index in the card, return that the inventory wasn't found
dataserver(key requested, string data)
{

list lstCurrentRequestedItem;
integer intWaitListIndex = 0;
integer blnKeyFound = FALSE;

//loop through the product request list to determine if this data server event matches the product request
for(;(intWaitListIndex < intItemRequestList) && (blnKeyFound == FALSE); intWaitListIndex++){

//Extract the query into its elements
lstCurrentRequestedItem = llParseString2List(llList2String(lstItemRequestList,intWaitListIndex),["#"],[]);

//Attempt to match the current notecard request key with that of the events
if(requested == (key)llList2String(lstCurrentRequestedItem,3)){

//If this is not the end of the product list...
if(data != EOF){

//Extract the product line into its elements
list lstProductParsedLine = llParseString2List(data,["#"],[]);

//Does this product line match with the request?
if( ((integer)llList2String(lstProductParsedLine,0) == (integer)llList2String(lstCurrentRequestedItem,0)) && ((integer)llList2String(lstProductParsedLine,1) == (integer)llList2String(lstCurrentRequestedItem,1)) ){

//return query to owner
//dbResults#ReturnQuery#(productRecord)
llMessageLinked(LINK_SET,0,"dbResults#" + llList2String(lstCurrentRequestedItem,2) + "#" + data,NULL_KEY);

//Add the product line to product buffer
addItem(data);

//Remove the request from the list
removeItemRequest(intWaitListIndex);

}
else{

//start requesting for the next line of the notecard
//categoryRequest#subcategoryRequest#ReturnQuery#notecardKey#notecardLine
lstItemRequestList = llListReplaceList(lstItemRequestList,[llList2String(lstCurrentRequestedItem,0) + "#" + llList2String(lstCurrentRequestedItem,1) + "#" + llList2String(lstCurrentRequestedItem,2) + "#" + (string) llGetNotecardLine(keyProductsUUID,(((integer) llList2String(lstCurrentRequestedItem,4)) + 1)) + "#" + (string)(((integer) llList2String(lstCurrentRequestedItem,4)) + 1) ],intWaitListIndex,intWaitListIndex);

}

}
//If this is the end of the product list and still the item category and subcategory isn't found,
//chances are, there's no product
else{

//return query to owner
//dbResults#ReturnQuery#(productRecord)
llMessageLinked(LINK_SET,0,"dbResults#" + llList2String(lstCurrentRequestedItem,2) + "#" + llList2String(lstCurrentRequestedItem,0) + "#" + llList2String(lstCurrentRequestedItem,1) + "#-1#NO_ITEM_AVAILABLE#NO_IMAGE_AVAILABLE",NULL_KEY);

//Add a NULL product to product buffer
addItem(llList2String(lstCurrentRequestedItem,0) + "#" + llList2String(lstCurrentRequestedItem,1) + "#-1#NO_ITEM_AVAILABLE#NO_IMAGE_AVAILABLE");

//Remove the request from the list
removeItemRequest(intWaitListIndex);

}

blnKeyFound = TRUE;

}

}

}

}
Ilobmirt Tenk
Registered User
Join date: 4 Jun 2007
Posts: 135
FOSSLVendorMainServer (v1.6)
02-29-2008 09:20
CODE

//---------------------------------------------------------------------------------//
//Copyright Info Below... Please Do not Remove //
//---------------------------------------------------------------------------------//

//(c)2007 Ilobmirt Tenk

//This file is part of the FOSSL Vendor Project

// FOSSL Vendor is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.

// FOSSL Vendor is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

//---------------------------------------------------------------------------------//
//Copyright Info Above... Please Do not Remove //
//---------------------------------------------------------------------------------//

//=================================================================//
//List all the global variables here...
//=================================================================//

//count of the current Notecard line to read
integer intSettingLines = 0;

//key of the notecard line to be read
key keySettingsId;

//This is the slurl to the server location
string strServerLocation = "";

//This counts the number of times the server has been made to deliver an item
integer intServerDeliveries = 0;

//determines if this object displays debugging output
integer blnDebug = FALSE;

//=================================================================//
//Customize the following variables
//=================================================================//

//determines if this script will outsource its e-mail functionality to save itself from that horrid 20 second delay
integer blnEmailAgents = FALSE;

//The name of the products notecard vendor clients will be reading off of
string strProductsCardName = "FOSSL_PRODUCTS_LIST";

//The channel in which server will listen to its owner
integer intListenChannel = 54;

//The key in which communication wil be encrypted with
string strEncryptionKey = "";

//determines if this server will allow others inworld to access the server
integer blnAnonAccess = TRUE;

//determines if this server will allow others outside of Secondlife to access the server
integer blnOutsideAccess = FALSE;

//Email this address upon a deliverey to say that an item has been given to the customer
string strEmailOnDeliverey = "";

//=================================================================//
//Customize the above variables
//=================================================================//

//This displays messages to the owner if debug mode has been set to true
debugMessage(string strMessage){

if(blnDebug == TRUE){

llOwnerSay(strMessage);

}

}

//Used for encrypting communications between itself and the inworld server
string encrypt(string strPayload){

//If there is an encryption key...
if(strEncryptionKey != ""){

//Use this simple Algrorythm to encrypt/decrypt input string
return llXorBase64StringsCorrect(llStringToBase64(strPayload), llStringToBase64(strEncryptionKey));

}
//otherwise...
else{

//Just return the string as is.
return strPayload;

}

}

//Used for decrypting communications between itself and the inworld server
string decrypt(string strPayload){

//If there is an encryption key...
if(strEncryptionKey != ""){

//Use this simple Algrorythm to encrypt/decrypt input string
return llBase64ToString(llXorBase64StringsCorrect(strPayload, llStringToBase64(strEncryptionKey)));

}
//otherwise...
else{

//Just return the string as is.
return strPayload;

}

}

default
{
state_entry(){

//Obtain the first line of the vendor link settings
keySettingsId = llGetNotecardLine("FOSSL_SERVER_SETTINGS", intSettingLines);

vector vectSimLocation = llGetPos();
string strPosX = (string) llRound(vectSimLocation.x);
string strPosY = (string) llRound(vectSimLocation.y);
string strPosZ = (string) llRound(vectSimLocation.z);

strServerLocation = "http://slurl.com/secondlife/" + llEscapeURL(llGetRegionName()) + "/" + strPosX + "/" + strPosY + "/" + strPosZ;
debugMessage("Server Location = " + strServerLocation );

}

//Reset the script when the container object gets rezzed
on_rez(integer intParam){

llResetScript();

}

//If somehing within the server changed, update the setting by resetting the script
changed(integer change){

// If I change the contents of the server
if(change & CHANGED_INVENTORY){

llOwnerSay("Server contents changed!");
llOwnerSay("Resetting script to make use of those changes.");
//reset the script to make use of the changes
llResetScript();

}

}

//Read the server settings notecard. Configure the server based on each line.
dataserver(key query_id, string data) {

if (query_id == keySettingsId) {
if (data != EOF) { // not at the end of the notecard

debugMessage("Notecard Line = \"" + data + "\"");
//split the record into variable names and values
list lstSplit = llParseString2List(data,["="],[]);
string strVariable = llToUpper(llStringTrim(llList2String(lstSplit,0),STRING_TRIM));
string strValue = llStringTrim(llList2String(lstSplit,1),STRING_TRIM);

if(strVariable == "PRODUCT CARD"){

strProductsCardName = strValue;
debugMessage("strProductsCardName = " + strProductsCardName);


}
if(strVariable == "EMAIL AGENTS"){

blnEmailAgents = (integer) strValue;
debugMessage("blnEmailAgents = " + (string) blnEmailAgents);

}

if(strVariable == "CHANNEL"){

intListenChannel = (integer) strValue;
debugMessage("intListenChannel = " + (string) intListenChannel);

}

if(strVariable == "KEY"){

strEncryptionKey = strValue;
debugMessage("strEncryptionKey = " + strEncryptionKey);

}

if(strVariable == "ANON ACCESS"){

blnAnonAccess = (integer) strValue;
debugMessage("blnAnonAccess = " + (string) blnAnonAccess);

}

if(strVariable == "OUTSIDE ACCESS"){

blnOutsideAccess = (integer) strValue;
debugMessage("blnOutsideAccess = " + (string) blnOutsideAccess);

}
if(strVariable == "EMAIL"){

strEmailOnDeliverey = strValue;

}

keySettingsId = llGetNotecardLine("FOSSL_SERVER_SETTINGS", ++intSettingLines); // request next line
}
//Server is done reading its settings. Start listening to the owner and start ilstening in for those e-mails
else{

//Capture toggle of Debug Setings
llListen(intListenChannel,"",llGetOwner(),"debug");
llListen(intListenChannel,"",llGetOwner(),"id");
llListen(intListenChannel,"",llGetOwner(),"reset");
llListen(intListenChannel,"",llGetOwner(),"count");

llOwnerSay("Server has completed setup.");
llOwnerSay("Please use \"" + (string) llGetKey() + "\" as the value of \"SERVER\" in the client vendors if you want them to point to this server.");

llSetTimerEvent(1.0); //set e-mail poll time to 1 second

}
}

}

//Follow the commands spoken by its owner
listen(integer channel, string name, key id, string message)
{

//If owner wants to listen to the vendor's debug messages
if(message == "debug"){

blnDebug = !blnDebug;
llOwnerSay("Debug Mode set to: " + (string) blnDebug);

}
//If Owner wants to listen to the server's Id
else if(message == "id"){

llOwnerSay("Please use \"" + (string) llGetKey() + "\" as the value of \"SERVER\" in the client vendors if you want them to point to this server.");

}
//If Owner wants the server to reset its script
else if(message == "reset"){

llOwnerSay("Resetting the Server upon command...");
llResetScript();

}
else if(message == "count"){

llOwnerSay( "This server has delivered " + (string) intServerDeliveries + " objects since script initialization.");

}
//Owner didn't give it an adequate command
else{

llOwnerSay("I don't know what you want me to do.");

}

}

//Use this event to poll for incomming e-mails
timer()
{

//poll for any incomming e-mail
//filtering happens at the e-mail event
llGetNextEmail("","");

}

//Triggered when e-mail poll yeids an incomming e-mail
email(string time, string address, string subject, string body, integer remaining)
{

key keyRequester = (key) llGetSubString(address,0,35); //obtain requester uuid from address
key keyRequesterOwner = llGetOwnerKey(keyRequester); //obtain the owner of the requesting object
string strMessage = decrypt(llDeleteSubString(body, 0, llSubStringIndex(body, "\n\n") + 1)); //the message without e-mail headers
string strSubject = decrypt(subject);
debugMessage("E-mail From: " + address);
debugMessage("E-mail Subject: " + subject);
debugMessage("E-mail Message: " + strMessage);

debugMessage("Object Key: " + (string) keyRequester);
debugMessage("E-mail Owner: " + (string) keyRequesterOwner);
debugMessage("Server Owner: " + (string) llGetOwner());

//First condition:
//Did the e-mail originate with an object made by the same person who owns this server?
//Its considered safe to accept your own requests, not from others
integer blnFirstCondition = (keyRequesterOwner == llGetOwner());

//Second condition:
//Does the server allow e-mail originate with an object made by someone else within Secondlife?
//Its considered less safe than condition 1, but its safer than an a sophisticated attack by a web server
integer blnSecondCondition = ((keyRequester != NULL_KEY) && (blnAnonAccess == TRUE));

//Third condition:
//Does the Server allow for ananymous outside access to thie server?
//Careful, this is the least safest permission of all!!!
//Source will not be checked for authenticity!!!
integer blnThirdCondition = ((blnAnonAccess == TRUE) && (blnOutsideAccess == TRUE));


//Does the source of the message meet any of the specified conditions?
if( (blnFirstCondition == TRUE) || (blnSecondCondition == TRUE) || (blnThirdCondition == TRUE) ){

debugMessage("Requester Passed Verification, processing request...");
llSetTimerEvent(0.0); //Stop the polling timer in case there are more e-mails

//If a client vendor requests for a new product card uuid
if(strSubject == "Requesting Product List"){

debugMessage("Giving " + (string) keyRequester + " the UUID of the product card.");

//If there are available scripts dedicated to offloading the delay in llEmail, do so.
//If not, make the e-mail request within this script taking into account the 20 second
//script delay set in by LL to prevent e-mail spam. <:P
if(blnEmailAgents == TRUE){

llMessageLinked(LINK_SET,0,"EmailRequest#" + address + "#" + encrypt("Update Product List") + "#" + encrypt((string) llGetInventoryKey(strProductsCardName)) ,NULL_KEY);

}
else{

llEmail(address,encrypt("Update Product List"),encrypt((string) llGetInventoryKey(strProductsCardName)));

}

}
//If a client vendor requests for a product to be delivered
else if(strSubject == "Give Item"){

intServerDeliveries++;

//Start by getting the person uuid and the object name
list lstRequestSplit = llParseString2List(strMessage,["^"],[]);
debugMessage("Giving " + llKey2Name((key) llList2String(lstRequestSplit,0)) + " a \"" + decrypt(llList2String(lstRequestSplit,1)) + "\"");
//using the split list, give a person a product as described in the e-mail
llGiveInventory((key) llList2String(lstRequestSplit,0), llList2String(lstRequestSplit,1));

//Notify the certain e-mail address of a sale
if(strEmailOnDeliverey != ""){

//Send another E-mail Request hopefully, its just a missed e-mail request
//Make Request for product card UUID
//If there are available scripts dedicated to offloading the delay in llEmail, do so.
//If not, make the e-mail request within this script taking into account the 20 second
//script delay set in by LL to prevent e-mail spam. <:P
if(blnEmailAgents == TRUE){

llMessageLinked(LINK_SET,0,"EmailRequest#" + strEmailOnDeliverey + "#Item Delivered - "+ llList2String(lstRequestSplit,1) +"#Purchaser - " + llList2String(lstRequestSplit,0) + "\nItem Purchased - " + llList2String(lstRequestSplit,1) +"\nLocation - " + strServerLocation,NULL_KEY);
debugMessage("Sent email notification to " + strEmailOnDeliverey);

}
else{

llEmail(strEmailOnDeliverey ,"Item Delivered - "+ llList2String(lstRequestSplit,1), "Purchaser - " + llList2String(lstRequestSplit,0) + "\nItem Purchased - " + llList2String(lstRequestSplit,1) +"\nLocation - " + strServerLocation);

}

}

}
}

//If there are no more e-mail requests, start polling using the timer
if(remaining <= 0){

llSetTimerEvent(1.0);

}
//Otherwise, just get the next message right here
else{

llGetNextEmail("","");

}

}

}
Ilobmirt Tenk
Registered User
Join date: 4 Jun 2007
Posts: 135
FOSSLVendorMainClient (v1.8) (PART 1 of 2)
02-29-2008 09:25
CODE

//FOSSLVendorMainClient
//---------------------------------------------------------------------------------//
//Copyright Info Below... Please Do not Remove //
//---------------------------------------------------------------------------------//

//(c)2007 Ilobmirt Tenk

//This file is part of the FOSSL Vendor Project

// FOSSL Vendor is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.

// FOSSL Vendor is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

//---------------------------------------------------------------------------------//
//Copyright Info Above... Please Do not Remove //
//---------------------------------------------------------------------------------//

//=================================================================//
//List all the global variables here...
//=================================================================//

string strCurrentItem = ""; //This is the current item that the product index is on
// the server, store the notecards in the server
string strINFO = " Info"; //This is the suffix for the info notecard - create one for each product - if using
integer intSeparateInfo = TRUE; //SET TRUE OR FALSE - if true the vendor will deliver a separate card for each item

list lstItemRequestList; //List of items to be requested from the server
//each record is in the form of "Category#SubCategory#DatabaseKey"

list lstDisplays; //List of displays to render products on
//Each display has a record of "Link#absoluteCategory#Category#absoluteSubCategory #SubCategory"

integer intHashCounter = -2147483646; //Used in the creation of a unique request

integer intSettingLines = 0; //Total # of lines in the settings notecard

integer intProductLines = 0; //Total # of lines in the products notecard

integer intItemRequestList = 0; //Number of item database requests to send to the server

integer intProductIndexCategory = 0; //Current index of visible product shown by Category

integer intProductIndexSubCategory = 0; //Current index of visible product shown by sub Category

integer intProductIndexMaxCategory = 0; //Maximum index of categorys

integer intProductIndexMaxSubCategory = 0; //Maximumindex of SubCategorys

integer intInfoCount = 0; //Number of times people clicked on the info button

integer intEmailRequestStarted = 0; //Last time an e-mail was sent out to the server

integer intLastProductUpdate = 0; //Last time product list was updated

key keySettingsId; //Used to load system Settings

key keyProductsUUID; //The uuid of the notecard to be read for products

key keyProductCategories; //The key of the line being read from the products card to determine length of categories

integer blnWaitingForServer = FALSE; //Used to determine if vendor is currently requesting a uuid for the product notecard

integer blnServerDown = TRUE; //Used to determine if the in-world server is down

integer blnDebug = FALSE; //Used to determine if vendor will output debugging information

string strVendorLocation = ""; //This is the slurl to the vendor location

//=================================================================//
//Customize the following variables
//=================================================================//

key keyTexLoading = "56617727-a972-f7d2-a730-484644a1fcb7"; //Texture UUID to represent that an item is loading

key keyTexOffline = "b8426d53-221d-9fc2-5b29-3ef16e2bd7a3"; //Texture UUID to represent the vendor has no connection to the server

key keyTexNothing = "93481f65-67ff-f166-cc64-e6fe1069c1c1"; //Texture UUID to represent that there is no item for this index

key keyServer = NULL_KEY; //This is a pointer to an object server. If this is not NULL_KEY, the vending system will consider selling items from that server.

string strInfoCardName = ""; //Name of the information notecard that talks about your company

string strProductsCardName = "FOSSL_PRODUCTS_LIST"; //Name of the products card to read off of

string strEncryptionKey = ""; //Key to encrypt its communications with

integer intBuffer = 0; //How big do you want you product inventory to be? This goes beyond the # of displays

float fltInventoryRefresh = 3600.0; //Time delay before vendor clears its product inventory and makes another request for more items

integer intServerTimeout = 60; //Time in seconds before vendor is considered down

integer intCommChannel = 45; //Channel in which you can communicate to your vending machine

string strEmailOnSale = ""; //Email this address upon a sale to say that an item has been bought

integer blnEmailAgents = FALSE; //Can this script export the task of sending e-mails to other in-world objects?

//=================================================================//
//Customize the above variables
//=================================================================//



//=================================================================//
//Define global Functions here...
//=================================================================//

//This displays messages to the owner if debug mode has been set to true
debugMessage(string strMessage){

if(blnDebug == TRUE){

llOwnerSay("FOSSLVendorMainClient: " + strMessage);

}

}

//Used for encrypting communications between itself and the inworld server
string encrypt(string strPayload){

//If there is an encryption key...
if(strEncryptionKey != ""){

//Use this simple Algrorythm to encrypt/decrypt input string
return llXorBase64StringsCorrect(llStringToBase64(strPayload), llStringToBase64(strEncryptionKey));

}
//otherwise...
else{

//Just return the string as is.
return strPayload;

}

}

//Used for decrypting communications between itself and the inworld server
string decrypt(string strPayload){

//If there is an encryption key...
if(strEncryptionKey != ""){

//Use this simple Algrorythm to encrypt/decrypt input string
return llBase64ToString(llXorBase64StringsCorrect(strPayload, llStringToBase64(strEncryptionKey)));

}
//otherwise...
else{

//Just return the string as is.
return strPayload;

}

}

//Enters the vending system into an offline mode if not offline already
goOffline(){

blnServerDown = TRUE; //Set state of vendor to be offline
clearRequests(); //Clear any pending requests for products
llMessageLinked(LINK_SET,0,"goingOffline",NULL_KEY); //Notify system its going offline
displaysOffline(); //Reflect the changes on display

}

//Restores functionality to the vending machine from an offline mode
goOnline(){

blnServerDown = FALSE; //Set state of vendor to be online
llMessageLinked(LINK_SET,0,"goingOnline",NULL_KEY);
displaysLoading(); //reflect changes on display

}

//This will set each display to a loading texture
//This will also send out database requests for each link
displaysLoading(){

list lstDisplay = [];
integer intIndex = 0;
integer intDisplayIndex = 0;
integer intDisplays = llGetListLength(lstDisplays);
integer blnDisplayAbsoluteCategory = 0;
integer blnDisplayAbsoluteSubCategory = 0;
integer intDisplayCategory = 0;
integer intDisplaySubCategory = 0;
integer intDisplayRelativeCategory = 0;
integer intDisplayRelativeSubCategory = 0;

strCurrentItem = "";
updatePrices();

//Loop through each index of the available displays
for(; intIndex < intDisplays; intIndex++){

//collect prim location, then texturethem with the offline texture
//Link#absoluteCategory#Category#absoluteSubCategory #SubCategory
lstDisplay = llParseString2List(llList2String(lstDisplays,intIndex),["#"],[]);
intDisplayIndex = (integer) llList2String(lstDisplay,0);

intDisplayRelativeCategory = (integer) llList2String(lstDisplay,2);
blnDisplayAbsoluteCategory = (integer) llList2String(lstDisplay,1);
blnDisplayAbsoluteSubCategory = (integer) llList2String(lstDisplay,3);
intDisplayRelativeSubCategory = (integer) llList2String(lstDisplay,4);

//Obtain displayed category
if(blnDisplayAbsoluteCategory == TRUE){

intDisplayCategory = intDisplayRelativeCategory;
debugMessage("Display category is Absolute");

}
else{

intDisplayCategory = intDisplayRelativeCategory + intProductIndexCategory;
debugMessage("Display category is Relative");

debugMessage("Normalising Category index");
//Make sure displayed Category is between 0 and the maximum category
while(intDisplayCategory > intProductIndexMaxCategory){

intDisplayCategory -= (intProductIndexMaxCategory + 1);

}

while(intDisplayCategory < 0){

intDisplayCategory += (intProductIndexMaxCategory + 1);

}

}

//Obtain displayed SubCategory
if(blnDisplayAbsoluteSubCategory == TRUE){

intDisplaySubCategory = intDisplayRelativeSubCategory;
debugMessage("Display subcategory is Absolute");

}
else{

intDisplaySubCategory = intDisplayRelativeSubCategory + intProductIndexSubCategory;
debugMessage("Display subcategory is relative");

debugMessage("Normalising Category index");
//Make sure displayed SubCategory is between 0 and the maximum category
while(intDisplaySubCategory > intProductIndexMaxSubCategory){

intDisplaySubCategory -= (intProductIndexMaxSubCategory + 1);

}

while(intDisplaySubCategory < 0){

intDisplaySubCategory += (intProductIndexMaxSubCategory + 1) ;

}

}

debugMessage("Display Categories found @ " + (string) intDisplayCategory + "#" + (string) intDisplaySubCategory);

llSetLinkTexture(intDisplayIndex, keyTexLoading ,ALL_SIDES);

debugMessage("Item Request for link # "+ (string) intDisplayIndex +" = " + (string) intDisplayCategory + "#" + (string) intDisplaySubCategory);
itemRequest(intDisplayCategory,intDisplaySubCategory,intDisplayIndex);

}

}

//This will Update all visible displays with the offline texture
//Also, it will prevent payments to be made to the machine
displaysOffline(){

list lstDisplay = [];
integer intIndex = 0;
integer intDisplayIndex = 0;
integer intDisplays = llGetListLength(lstDisplays);

strCurrentItem = "";
updatePrices();

//Loop through each index of the available displays
for(; intIndex < intDisplays; intIndex++){

//collect prim location, then texturethem with the offline texture
lstDisplay = llParseString2List(llList2String(lstDisplays,intIndex),["#"],[]);
intDisplayIndex = (integer) llList2String(lstDisplay,0);
llSetLinkTexture(intDisplayIndex, keyTexOffline ,ALL_SIDES);

}

}

//This will update a single screen with an associated texture
updateDisplay(string strReturnQuery){

debugMessage("strReturnQuery for texturing = " + strReturnQuery);
//Extract the query into its elements
//return query = "dbResults#ReturnQuery#(productRecord)"
//ProductRecord = "Category#Subcategory#Price#Name#TextureUUID"
list lstReturnQuery = llParseString2List(strReturnQuery,["#"],[]);

//extract the query ID into its elements
//queryID = "linkNumber^queryHash"
list lstQuery = llParseString2List(llList2String(lstReturnQuery,1) ,["#"],[]);
string strTextureElement = llList2String(lstReturnQuery,6);

integer intLinkNumber = (integer) llList2String(lstQuery,0);
debugMessage("Texture for Prim #"+ (string) intLinkNumber +" = " + strTextureElement );

//Granted, the image for the item index is available, texure it.
if( (strTextureElement != "") && (strTextureElement != "NO_IMAGE_AVAILABLE") ){

llSetLinkTexture(intLinkNumber,(key) strTextureElement,ALL_SIDES);

}
//If there doesn't appear to be an image for the product, give it the nothing texture
else{

llSetLinkTexture(intLinkNumber,keyTexNothing,ALL_SIDES);

}

//If query returned something that is equal to product index, capture it as a current index
if((llList2String(lstReturnQuery,2) + "#" + llList2String(lstReturnQuery,3)) == ((string)intProductIndexCategory + "#" + (string)intProductIndexSubCategory )){

strCurrentItem = llDumpList2String(llList2List(lstReturnQuery,2,-1),"#");
//change the info card name
if (intSeparateInfo == TRUE){

// use the product name plus the strINFO suffix to identify the notecard to deliver;
strInfoCardName = llList2String(llList2List(lstReturnQuery,2,-1), 3) + strINFO;

}
//NB if FALSE the originally set info card wil be used instead;

debugMessage("Current Info name:" + strInfoCardName);
//Update prices
updatePrices();

}

}


//This makes the vendor update the price based upon current Index as well as the displayed objects.
updatePrices(){

list lstParsedItem = [];
integer intPrice = 0;

if(strCurrentItem != ""){

lstParsedItem = llParseString2List(strCurrentItem,["#"],[]);
intPrice = (integer) llList2String(lstParsedItem,2);

if((intPrice > 0) && (blnServerDown == FALSE) ){

llSetPayPrice(PAY_HIDE, [intPrice, PAY_HIDE, PAY_HIDE, PAY_HIDE]);

}
else{

llSetPayPrice(PAY_HIDE, [PAY_HIDE, PAY_HIDE, PAY_HIDE, PAY_HIDE]);

}

llMessageLinked(LINK_SET,intPrice,"updatePrice",NULL_KEY); //set the prices for the buy/gift buttons

}
else{

llSetPayPrice(PAY_HIDE, [PAY_HIDE, PAY_HIDE, PAY_HIDE, PAY_HIDE]);

}


}


//This function adds item requests to the buffer before it starts obtaining them from the database
itemRequest(integer intCategory, integer intSubCategory, integer intLink){

//keep hash counter going. Never let it reach its end
if(intHashCounter == 2147483646 ){

intHashCounter = -2147483646;

}

string strQueryID = (string)intLink + "^" + llMD5String("H@5h",++intHashCounter);

//take that record and add it to the waitlist
lstItemRequestList = llListReplaceList((lstItemRequestList = []) + lstItemRequestList,[(string)intCategory + "#" + (string)intSubCategory + "#" + strQueryID ],intItemRequestList,intItemRequestList);

//increment # of items on the waitlist
intItemRequestList++;

llMessageLinked(LINK_SET,0,"dbRequest#" + strQueryID + "#" + (string) intCategory + "#" + (string) intSubCategory ,NULL_KEY);

}

//This function removes item requests by their index
removeItemRequest(integer intIndex){

//remove the item by index
lstItemRequestList = llDeleteSubList((lstItemRequestList = []) + lstItemRequestList,intIndex,intIndex);

//decrement # of items on the waitlist
intItemRequestList--;


}

//clears the request buffer
clearRequests(){

lstItemRequestList= [];
intItemRequestList = 0;

}

//Proccesses the dbQuery to see if it matches a request
processQuery(string strDBQuery){

integer intIndex = -1;
integer blnFound = FALSE;
string strQueryID = llList2String(llParseString2List(strDBQuery,["#"],[]),1);
list lstParsedRequest = [];

debugMessage("Proccessing Query = " + strQueryID );

//loop while there are requests to proccess and if the query doesn't match
do{

++intIndex; //advance an index

lstParsedRequest = llParseString2List(llList2String(lstItemRequestList,intIndex),["#"],[]);

if(strQueryID == llList2String(lstParsedRequest,2) ){

blnFound = TRUE;

updateDisplay(strDBQuery);

removeItemRequest(intIndex);

}

}while( (intIndex < intItemRequestList) && (blnFound == FALSE) );

}

default
{
//Activated upon the beginning of script execution
//Start setting up vendor settings
state_entry(){

//Keep debug mode in all scripts the same on startup or reset
llMessageLinked(LINK_SET,0,"debugMode#"+ (string) blnDebug ,NULL_KEY);
llOwnerSay("FOSSLVendorClient: Loading Settings...");
keySettingsId = llGetNotecardLine("FOSSL_CLIENT_SETTINGS", intSettingLines); //Obtain the first line of the vendor settings

vector vectSimLocation = llGetPos();
string strPosX = (string) llRound(vectSimLocation.x);
string strPosY = (string) llRound(vectSimLocation.y);
string strPosZ = (string) llRound(vectSimLocation.z);


strVendorLocation = "http://slurl.com/secondlife/" + llEscapeURL(llGetRegionName()) + "/" + strPosX + "/" + strPosY + "/" + strPosZ;
debugMessage("Vendor Location = " + strVendorLocation );

}

//Activated upon rezzing of its container prim
//Use this event to update the settings of the vending system
on_rez(integer start_param){

//reset the script when I rez it
llResetScript();

}

//Activated upon modification of vendor's inventory
//Reset script to make use of possible changes
changed(integer change){

// If I change the contents of the vendor
if(change & CHANGED_INVENTORY){

//reset the script to make use of the changes
llResetScript();

}

}



Script is Continued on next post... Stupid character limit :P
Ilobmirt Tenk
Registered User
Join date: 4 Jun 2007
Posts: 135
FOSSLVendorMainClient (v1.8) (2 of 2 parts)
02-29-2008 09:28
Continued from above.
Darn character limit. :P

CODE

//Activate this event when a companion script sends out a linked message
//Use this event to determine if that script is making a request or response of this script
//This script accepts requests to go online of offline, link clicked requests,
//screen addition requests, buying requests, and info requests
link_message(integer sender_num, integer num, string str, key id){

debugMessage("Link message recieved = " + str);

list lstMessage = llParseString2List(str,["#"],[]);
string strFunction = llList2String(lstMessage,0);

//Vendor module wants vendor to go online
if(strFunction == "goOnline"){

goOnline();

}
//Vendor module wants vendor to go offline
if(strFunction == "goOffline"){

goOffline();

}
//"linkClicked#absoluteCategory#CategoryShift#absolut eSubcategory#SubCategoryShift"
if(strFunction == "linkClicked"){

integer intDiffCategory = (integer) llList2String(lstMessage,2);
integer intDiffSubCategory = (integer) llList2String(lstMessage,4);
integer blnAbsoluteCategory = (integer) llList2String(lstMessage,1);
integer blnAbsoluteSubCategory = (integer) llList2String(lstMessage,3);

//Determine Category
if(blnAbsoluteCategory == TRUE){

intProductIndexCategory = intDiffCategory;

}
else{

intProductIndexCategory += intDiffCategory;

//Keep Category larger than 0
while(intProductIndexCategory < 0){

intProductIndexCategory += (intProductIndexMaxCategory + 1);

}
//Keep Category less than or equal to max
while(intProductIndexCategory > intProductIndexMaxCategory){

intProductIndexCategory -= (intProductIndexMaxCategory+1);

}

}

//Determine Subcategory
if(blnAbsoluteSubCategory == TRUE){

intProductIndexSubCategory = intDiffSubCategory;

}
else{

intProductIndexSubCategory += intDiffSubCategory;

//Keep SubCategory larger than 0
while(intProductIndexSubCategory < 0){

intProductIndexSubCategory += (intProductIndexMaxSubCategory + 1);

}

//Keep SubCategory less than or equal to max
while(intProductIndexSubCategory > intProductIndexMaxSubCategory){

intProductIndexSubCategory -= (intProductIndexMaxSubCategory + 1);

}

}

clearRequests();
displaysLoading();

}
//"addScreen#absoluteCategory#CategoryShift#absoluteS ubcategory#SubCategoryShift"
else if(strFunction == "addScreen"){

debugMessage("Screen added ... Updating the screens");

lstDisplays += [(string) sender_num + "#" + llList2String(lstMessage,1) + "#" + llList2String(lstMessage,2) + "#" + llList2String(lstMessage,3) + "#" + llList2String(lstMessage,4) ];

clearRequests();
llMessageLinked(LINK_SET,0,"addBuffer" ,NULL_KEY); //set new Buffer Length
displaysLoading();


}
//"itemBought#BuyerUUID"
else if(strFunction == "itemBought"){

key keyBuyerUUID = (key)llList2String(lstMessage,1);
list lstItemBought = llParseString2List(strCurrentItem,["#"],[]);
string strItemBought = llList2String(lstItemBought,3);

debugMessage( llKey2Name(keyBuyerUUID) + " has bought your item.");
llWhisper(0,"Thank you " + llKey2Name(keyBuyerUUID) + " for purchasing the " + strItemBought +".");

//If this is networked, request server to distribute object
if(keyServer != NULL_KEY){

//Send another E-mail Request hopefully, its just a missed e-mail request
//Make Request for product card UUID
//If there are available scripts dedicated to offloading the delay in llEmail, do so.
//If not, make the e-mail request within this script taking into account the 20 second
//script delay set in by LL to prevent e-mail spam. <:P
if(blnEmailAgents == TRUE){

llMessageLinked(LINK_SET,0,"EmailRequest#" + (string) keyServer + "@lsl.secondlife.com#"+ encrypt("Give Item") +"#" + encrypt((string) keyBuyerUUID + "^" + strItemBought) ,NULL_KEY);

//Notify the certain e-mail address of a sale
if(strEmailOnSale != ""){

llMessageLinked(LINK_SET,0,"EmailRequest#" + strEmailOnSale + "#Item Purchsed - "+ strItemBought +"#Purchaser - " + llKey2Name(keyBuyerUUID) + "\nItem Purchased - " + strItemBought +"\nLocation - " + strVendorLocation,NULL_KEY);
debugMessage("Sent email notification to " + strEmailOnSale);

}

}
else{

llEmail((string) keyServer + "@lsl.secondlife.com",encrypt("Give Item"),encrypt((string) keyBuyerUUID + "^" + strItemBought));
//Notify the certain e-mail address of a sale
if(strEmailOnSale != ""){

llEmail( strEmailOnSale, "Item Purchsed - "+ strItemBought,"Purchaser - " + llKey2Name(keyBuyerUUID) + "\nItem Purchased - " + strItemBought +"\nLocation - " + strVendorLocation);
debugMessage("Sent email notification to " + strEmailOnSale);

}

}

}
//Otherwise, give the person the object in its own inventory
else{

llGiveInventory(keyBuyerUUID, strItemBought);

}

}
//"infoRequested#requesterUUID"
else if(strFunction == "infoRequested"){

intInfoCount++;
key keyRequesterUUID = (key)llList2String(lstMessage,1);
debugMessage( llKey2Name(keyRequesterUUID) + " wants to know more about your business.");


//If this is networked, request server to distribute notecard
if(keyServer != NULL_KEY){

//Send another E-mail Request hopefully, its just a missed e-mail request
//Make Request for product card UUID
//If there are available scripts dedicated to offloading the delay in llEmail, do so.
//If not, make the e-mail request within this script taking into account the 20 second
//script delay set in by LL to prevent e-mail spam. <:P
if(blnEmailAgents == TRUE){

llMessageLinked(LINK_SET,0,"EmailRequest#" + (string) keyServer + "@lsl.secondlife.com#"+ encrypt("Give Note") +"#" + encrypt((string) keyRequesterUUID + "^" + strInfoCardName) ,NULL_KEY);

}
else{

llEmail((string) keyServer + "@lsl.secondlife.com",encrypt("Give Note"),encrypt((string) keyRequesterUUID + "^" + strInfoCardName));

}

}
//Otherwise, give the person the object in its own inventory
else{

llGiveInventory(keyRequesterUUID, strInfoCardName);

}

}
//dbResults#QueryID#(product data)
else if(strFunction == "dbResults"){

processQuery(str);//check if response was needed

}
else{

//Ignore the message

}

}

//used to read vendor settings, calculate index lengths, and retrieve product data
dataserver(key query_id, string data) {

//Whenever vendor is reading the settings notecard.
//This usually happens once during script initialization
//Data should be an assignment per line
//Record format should be "variable=value"
if (query_id == keySettingsId) {

if (data != EOF) { // not at the end of the notecard

//split the record into variable names and values
list lstSplit = llParseString2List(data,["="],[]);
string strVariable = llToUpper(llStringTrim(llList2String(lstSplit,0),STRING_TRIM));
string strValue = llStringTrim(llList2String(lstSplit,1),STRING_TRIM );

if(strVariable == "LOADING TEXTURE"){

keyTexLoading = (key) strValue;

}
if(strVariable == "EMAIL"){

strEmailOnSale = strValue;

}
if(strVariable == "SEPARATE INFO"){

intSeparateInfo = (integer) strValue;

}
if(strVariable == "INFO SUFFIX"){

strINFO = strValue;
debugMessage("INFO CARD SUFFIX:" + strINFO);

}
if(strVariable == "OFFLINE TEXTURE"){

keyTexOffline = (key) strValue;

}
if(strVariable == "NOTHING TEXTURE"){

keyTexNothing = (key) strValue;

}
if(strVariable == "SERVER"){

keyServer = (key) strValue;

}
if(strVariable == "PRODUCT CARD"){

strProductsCardName = strValue;

}
if(strVariable == "INFO CARD"){

strInfoCardName = strValue;

}
if(strVariable == "COMM CHANNEL"){

intCommChannel = (integer) strValue;

}
if(strVariable == "REFRESH"){

fltInventoryRefresh = (float) strValue;

}
if(strVariable == "TIMEOUT"){

intServerTimeout = (integer) strValue;

}
if(strVariable == "BUFFER"){

intBuffer = (integer) strValue;

}
if(strVariable == "EMAIL AGENTS"){

blnEmailAgents = (integer) strValue;

}
if(strVariable == "KEY"){

strEncryptionKey = strValue;

}

keySettingsId = llGetNotecardLine("FOSSL_CLIENT_SETTINGS", ++intSettingLines); // request next line

}
//Settings notecard has been read, proceed with obtaining products card.
else{

llOwnerSay("FOSSLVendorClient: Vendor Settings loaded.");
llListen(intCommChannel,"",llGetOwner(),"count"); //activate listen event whenever I say count on the listening channel
llListen(intCommChannel,"",llGetOwner(),"debug"); //activate listen event whenever I say debug on the listening channel
llListen(intCommChannel,"",llGetOwner(),"reset"); //activate listen event whenever I say reset on the listening channel
llListen(intCommChannel,"",llGetOwner(),"online"); //activate listen event whenever I say online on the listening channel
llListen(intCommChannel,"",llGetOwner(),"offline"); //activate listen event whenever I say offline on the listening channel
llListen(intCommChannel,"",llGetOwner(),"memory"); //activate listen event whenever I say memory on the listening channel

//Is this vendor networked?
if(keyServer != NULL_KEY){

llOwnerSay("FOSSLVendorClient: Vendor is networked. Contacting Server for Product List.");

//If there are available scripts dedicated to offloading the delay in llEmail, do so.
//If not, make the e-mail request within this script taking into account the 20 second
//script delay set in by LL to prevent e-mail spam. <:P
if(blnEmailAgents == TRUE){

llMessageLinked(LINK_SET,0,"EmailRequest#" + (string) keyServer + "@lsl.secondlife.com#"+ encrypt("Requesting Product List") + "#" + encrypt("NULL"),NULL_KEY);

}
else{

llEmail((string) keyServer + "@lsl.secondlife.com",encrypt("Requesting Product List"),encrypt("NULL"));

}
blnWaitingForServer = TRUE;
intEmailRequestStarted = llGetUnixTime();
llSetTimerEvent(1.0);

}
//Otherwise, if it is not networked, load the product list uuid locally
else{

llOwnerSay("FOSSLVendorClient: Vendor is not networked. Obtaining Product List locally.");
keyProductsUUID = llGetInventoryKey(strProductsCardName);
llOwnerSay("FOSSLVendorClient: Determining Maximums for Categories and Subcategories. This may take a while...");
//start obtaining the # of categories and subcategories
keyProductCategories = llGetNotecardLine(keyProductsUUID,intProductLines) ;

}

//Update database buffer to the length specified by notecard
llMessageLinked(LINK_SET, 0, "setBuffer#" + (string) intBuffer, NULL_KEY);

}
}
//Whenever vendor is reading the products notecard to determine size of its categories and subcategories.
else if(query_id == keyProductCategories){

//If the products notecard needs to be read further...
if(data != EOF){

list lstProductParsedLine = llParseString2List(data,["#"],[]); //Parse the line into a list

//Determine if current Category # is the current Maximum
if(intProductIndexMaxCategory < (integer) llList2String(lstProductParsedLine,0)){

intProductIndexMaxCategory = (integer) llList2String(lstProductParsedLine,0);

}

//Determine if current SubCategory # is the current Maximum
if(intProductIndexMaxSubCategory < (integer) llList2String(lstProductParsedLine,1)){

intProductIndexMaxSubCategory = (integer) llList2String(lstProductParsedLine,1);

}

//Read the next line of the products notecard
keyProductCategories = llGetNotecardLine(keyProductsUUID,++intProductLines);

}
//After reading the notecard, vendor is ready to operate
else{

llOwnerSay("FOSSLVendorClient: Categories and SubCategories determined. Vendor is now able to load products.");

intProductLines = 0; //clear this for later updates
clearRequests(); //clear any requests for products if any
llMessageLinked(LINK_SET,0,"setBuffer#" + (string) intBuffer ,NULL_KEY);//clear the current list of products in buffer, if any
llMessageLinked(LINK_SET, 0, "setDB#" + (string) keyProductsUUID, NULL_KEY); //Tell Database where it gets its data
goOnline();

//Request displays to register if there are none already
if(lstDisplays == []){

llMessageLinked(LINK_SET,0,"getDisplays",NULL_KEY); //request all screens to register

}

//Only refresh the inventory if it is networked
if(keyServer != NULL_KEY){

llSetTimerEvent(fltInventoryRefresh); //Set timer to request product notecard uuid at a set interval

}

}

}

}

timer(){

//Depending on if the vendor is waiting from a response from the server,
//either wait for an e-mail from the server, or make a request for an updated product list
if(blnWaitingForServer == TRUE){

if(llGetUnixTime() - intEmailRequestStarted < intServerTimeout){

//llGetNextEmail((string) keyServer + "@lsl.secondlife.com",encrypt("Update Product List"));
llGetNextEmail("","");

}
else{

//take vendor offline if not done already
goOffline();

//Send another E-mail Request hopefully, its just a missed e-mail request
//Make Request for product card UUID
//If there are available scripts dedicated to offloading the delay in llEmail, do so.
//If not, make the e-mail request within this script taking into account the 20 second
//script delay set in by LL to prevent e-mail spam. <:P
if(blnEmailAgents == TRUE){

llMessageLinked(LINK_SET,0,"EmailRequest#" + (string) keyServer + "@lsl.secondlife.com#"+ encrypt("Requesting Product List") + "#" + encrypt("NULL"),NULL_KEY);

}
else{

llEmail((string) keyServer + "@lsl.secondlife.com",encrypt("Requesting Product List"),encrypt("NULL"));

}

intEmailRequestStarted = llGetUnixTime(); //After this, timer loop will look for a server response

}

}
else{

//Make Request for product card UUID
//If there are available scripts dedicated to offloading the delay in llEmail, do so.
//If not, make the e-mail request within this script taking into account the 20 second
//script delay set in by LL to prevent e-mail spam. <:P
if(blnEmailAgents == TRUE){

llMessageLinked(LINK_SET,0,"EmailRequest#" + (string) keyServer + "@lsl.secondlife.com#"+ encrypt("Requesting Product List") + "#" + encrypt("NULL"),NULL_KEY);

}
else{

llEmail((string) keyServer + "@lsl.secondlife.com",encrypt("Requesting Product List"),encrypt("NULL"));

}

blnWaitingForServer = TRUE;
intEmailRequestStarted = llGetUnixTime(); //After this, timer loop will look for a server response
llSetTimerEvent(1.0);

}

}

email(string time, string address, string subject, string body, integer remaining){

debugMessage("Recieved E-mail from : " + address);

if (address == (string) keyServer + "@lsl.secondlife.com" && subject == encrypt("Update Product List")){

//don't wait for more e-mail
blnWaitingForServer = FALSE;

//make this the last time products were updated
intLastProductUpdate = llGetUnixTime();

//Remove e-mail header to generate the new uuid
key keyNewUUID = (key) decrypt(llDeleteSubString(body, 0, llSubStringIndex(body, "\n\n") + 1));

//New product notecard uuid is in the message
keyProductsUUID = keyNewUUID;

//start obtaining the # of categories and subcategories
keyProductCategories = llGetNotecardLine(keyProductsUUID,intProductLines) ;

//polling for further e-mails using the timer event is no longer neccesary
llSetTimerEvent(0.0);

}

if(remaining > 0 ){

//load the next e-mail in que to try and clear the e-mail buffer
//llGetNextEmail((string) keyServer + "@lsl.secondlife.com",encrypt("Update Product List"));
llGetNextEmail("","");

}

}

listen( integer channel, string name, key id, string message ){

if(id == llGetOwner()){

//Count the number of times users requested information
if(message == "count"){

llOwnerSay("FOSSLVendorClient: Notecard info request at " + (string)intInfoCount + ".");

}

//Enable or disable verbose output
else if(message == "debug"){

blnDebug = !blnDebug;
llOwnerSay("FOSSLVendorClient: Debug Mode set to: " + (string) blnDebug);
llMessageLinked(LINK_SET,0,"debugMode#" + (string) blnDebug,NULL_KEY);

}

//Make the vendor go online
else if(message == "online"){

goOnline();
debugMessage("Vendor attempting to go online");

}

//Make the vendor go offline
else if(message == "offline"){

goOffline();
debugMessage("Vendor attempting to go offline");

}

//Reset the scripts
else if(message == "reset"){

llResetScript();

}
//Get the current free memory in script
else if(message == "memory"){

llOwnerSay("FOSSLVendorClient: Memory = " + (string) llGetFreeMemory() +"/16000 Bytes");
llMessageLinked(LINK_SET,0,"getMemory",NULL_KEY); //If other scripts understand this, have them output free memory also

}
else{

llOwnerSay("FOSSLVendorClient: I dunno what youre talking about.");

}

}

}

}
Fleur Dollinger
Registered User
Join date: 31 Mar 2007
Posts: 8
Modded version of FOSSL Vendor Scripts to enable income splitting and multi notecards
04-30-2008 18:49
Thank you for this script.

Since I needed to make some modifications for my purpose, I've posted my mods on the forum at:

/54/b2/256378/1.html#post1970829

Now you can use the FOSSL vendor to give to other sellers and/or enable income splitting. My modification allows for up to a 4-way split and enables the vending of separate info notecards for each product.
Ilobmirt Tenk
Registered User
Join date: 4 Jun 2007
Posts: 135
05-02-2008 18:47
Fleur Dollinger - I really have appreciated your enthusiasm of this project of mine. Profit splitting was one of the major things that was requested of the vending system and you are just about the first to have released the code to it. If that code takes off, I'll consider including it into the next official build. But we all should discuss how the vending system versioning and branching would be done. If I am to take this project further like you have done with this project, we should get this squared away. Then this will truley be a development nirvana.

Everyone - There appears to be some kind of logic flaw within how these scripts communicate with each other. (Either that, or Secondlife was having a bad day at the time :P) Therefore, I go against what I stated earlier in that this vending system cannot fit within one prim. I apologize for the inconvenience. This bug will be looked at personally after the end of my college semester when I finally have free time on my hands.
Ilobmirt Tenk
Registered User
Join date: 4 Jun 2007
Posts: 135
05-02-2008 19:09
Just to let you all know, this project is quite alive and kicking. I'm trying to take it one step at a time to make this vending system a development nirvana for both the entrepreneur and the open-source enthusiast. Just some key areas I want to tackle to make this project move forward...

* Understand the bottlenecks to the FOSSL Vending System
- Develop a Vendor diagnostics module to track message data and overall environment health.
- Pinpoint scripts that are requested of the most. What scripts are forced to do all the number crunching? Can we alleviate that computational stress?

* Versioning, Branching, and Merging
- What to do with all the end user contributions?
- How will we measure the progress of the vending system?

* Speed up the database algorithms
- Current inventory database algorithms are possibly ineficient
- Is there a smarter way to organize database than by (most recent <--> least recent) query?

* Improve the server
- What could we do to add more value on the server side?
+ Sales/Vendor tracking?
+ E-mail History?
+ Giving more than one item at a time? llGiveInventoryList() ?

That's all for now. Again I need to make this into bite sized pieces. I know that this project is already larger than I am. I shouldn't bite off more than I can chew despite how big my dreams are of this project.
Very Keynes
LSL is a Virus
Join date: 6 May 2006
Posts: 484
05-03-2008 04:36
From: Ilobmirt Tenk
* Speed up the database algorithms
- Current inventory database algorithms are possibly ineficient
- Is there a smarter way to organize database than by (most recent <--> least recent) query?


I may be able to help with that. Not sure about the speed issue as I have not yet used your system, but I have developed an in world SQL Database system. The Standalone vendor could use my Embedded SQL scripts and the networked version could use my SQL Server. The SQL code in the vendor remains the same all that is required to switch from standalone to networked is to prefix the table names with the server name.

In this case I would use both versions, embedded for the products stored in the vendor and the server to coordinate the vendors and share common info. The SQL code is in final beta testing, and was intended to be released with MONO, but is working well in standard LSL in the test devices I have created. Give me a shout if you would like to try the code.
Ilobmirt Tenk
Registered User
Join date: 4 Jun 2007
Posts: 135
05-03-2008 07:36
From: Very Keynes
I may be able to help with that. Not sure about the speed issue as I have not yet used your system, but I have developed an in world SQL Database system. The Standalone vendor could use my Embedded SQL scripts and the networked version could use my SQL Server. The SQL code in the vendor remains the same all that is required to switch from standalone to networked is to prefix the table names with the server name.

In this case I would use both versions, embedded for the products stored in the vendor and the server to coordinate the vendors and share common info. The SQL code is in final beta testing, and was intended to be released with MONO, but is working well in standard LSL in the test devices I have created. Give me a shout if you would like to try the code.


Sure thing. Should hold onto that idea for just a bit. I have this large "master plan" I'd like to diagram some time. Inclusion of this idea would allow for third parties to host services. Certainly something that might interest some entrepreneurs.
Ilobmirt Tenk
Registered User
Join date: 4 Jun 2007
Posts: 135
Future of Communications...
05-03-2008 14:59
Please see the following attachment. It contains a diagram about how the system as a whole communicates between the client and server.

Currently - Communication between vendor client and product server uses a process reliant on e-mail. Optimal configuration makes use of an extra script called FOSSLVendorEmailAgent.lsl to pass e-mail between FOSSLVendorMainClient.lsl and FOSSLVendorMainServer.lsl This leaves little flexibility over how messages travel over the metaverse between vendor client and server as it is tied to e-mail as transportation medium.

Near Future - Communication between objects should be handled in a dedicated script. I recommend calling it FOSSLVendorComminicationsAgent.lsl. This script makes communication between objects transparent to the other modules. Third parties could develop replacements to this module that use a medium of communication beyond e-mail.

Far Future - A Web server could enhance the reliability and overall security to the vending system. Being also a place for storage of data, a web server can add many more services towards the collection of functions brought towards this vending system.
Steve63 Avro
SL Junkie <>
Join date: 26 Nov 2007
Posts: 5
05-06-2008 07:31
First off... I'd like to say I'm SURPRISED that SL allowed the image... they must have fixes the board while I wasn't looking :D Hopefully the other board functions will work now too.

I very recently aquired the Code (well written, clear and understandable) and built a couple of the vendor systems... Even went to your shop and grabbed a couple of machines from there. Most Excellent work and I will be using this system, without a doubt. Looks good, easy to use and works.

I think your plans are right on the money and the ability to access an external server I believe would certainly be a positive thing. The idea / suggest that Very Keynes suggested about using a SQL Server engine would most certainly enhance that Database.

Display Performance was mentioned through the thread. While it would be ideal to have the display mechanism work quick for every agent, I don't believe this is possible as such. Much of it is dependent on the clients PC and their video systems. The ability to render the graphics has nothing to do with the vendor, rather it has everythingto do with their Internet Connection and Graphics card. Although, Server Lag (SL) is a contributing factor as well it is not the main issue. One way that I could see an improvement, which woud be dependent on the Machines Owner, would be to ensure that the images used in the display are NOT High Resolution but rather 256x256 or 512x512... the higher the resolution the more load to the client receiving the image.... this could be pointed out in the documentation. The exceptions to this might be IF a Fine Detail Picture is required to show Jewelry or similar items. Unfortunately, SL does not seem to have the ability to resize images in world at this time so the Vendor Owner would have t re-upload lower resolution pictures.

Enhancements / Suggestion Box. ;)
- Popular Items Listing and tracking stats. (SQL could facilitate such easily enough)
- NoteCard Handling for each item that a client could retrieve a Notecard If available giving a despription & details on the product shown. Notecard could be the same name as the product.
- Built in CopyBot Protection service
- Item Rez on Temp Function similar to other vendor systems.

One other item of possible interest. A "Light" Vendor Machine to make it operable in a High Lag Environment with very basic functions. I have seen the system fail to operate in a High Lag Environment (A Club with 60+ patrons active). It's not really a FOSSL problem and I'm not sure how that could be addressed but my thinking is that a lighte version of the system might solve that from occuring... Some kind of LAG Testing ?

I quickly read through all the postings but this is just a few thoughts and observations, at a glance.

Hope it helps & Keep up the Great Work !
Steve
_____________________
Steve63 Avro
LSL Infected Builder & Developer :D
RobbyRacoon Olmstead
Red warrior is hungry!
Join date: 20 Sep 2006
Posts: 1,821
05-06-2008 08:46
From: Steve63 Avro
Enhancements / Suggestion Box. ;)
- Popular Items Listing and tracking stats. (SQL could facilitate such easily enough)
- NoteCard Handling for each item that a client could retrieve a Notecard If available giving a despription & details on the product shown. Notecard could be the same name as the product.
- Built in CopyBot Protection service
- Item Rez on Temp Function similar to other vendor systems.
How exactly do you envision being able to put in a "Built in CopyBot Protection service" feature? There's no way to actually protect from CopyBot that I've ever heard of, so I'm very curious what you mean by that.

@OP - Looks interesting... I just recently rewrote my vendor scripts, so this is a subject that's been on my mind a lot lately. I haven't had time to review the FOSSL yet, but I'm looking forward to doing so as soon as possible.

.
_____________________
Steve63 Avro
SL Junkie <>
Join date: 26 Nov 2007
Posts: 5
05-06-2008 09:03
From: RobbyRacoon Olmstead
How exactly do you envision being able to put in a "Built in CopyBot Protection service" feature? There's no way to actually protect from CopyBot that I've ever heard of, so I'm very curious what you mean by that.


I'm not sure if it is possible or if there is a way to incorporate a CopyBot Protector... I have seen some stuff related to CopyBot Protection but never looked at any of that.

I was just thinking out loud of what would be a nice feature / function.

EDIT: I just searched through the Forums and read up on it... there doesn't see to be a way in regards to CopyBot Protection. Too Bad... so many people getting burned and nothing that can be done about it. :( so Disregard the CopyBot thing altogether...
RobbyRacoon Olmstead
Red warrior is hungry!
Join date: 20 Sep 2006
Posts: 1,821
05-06-2008 09:51
From: Steve63 Avro
I just searched through the Forums and read up on it... there doesn't see to be a way in regards to CopyBot Protection. Too Bad... so many people getting burned and nothing that can be done about it.

Agreed. It's an intractable problem, and I'm sure you're far from being alone in wanting protection built into vendors :)
_____________________
Ilobmirt Tenk
Registered User
Join date: 4 Jun 2007
Posts: 135
05-07-2008 06:23
From: Steve63 Avro


- NoteCard Handling for each item that a client could retrieve a Notecard If available giving a despription & details on the product shown. Notecard could be the same name as the product.


I belive this kind of fuctionality exists thanks to Fleur Dollinger
Please see this link and scroll down to the last few posts. There you'll find the modifications that enable such functionality.

From: Steve63 Avro


- Built in CopyBot Protection service


As said before, there isn't much protection from copybot if it could read all of the product content through the sctreamed data from server. However, I have to believe that Linden Labs will do their best to curb such use because it should be in their best interest to protect the content created by the users of their service.

Therefore, my focus on security shall be in how the network is designed. The question should be how to protect content on a network where there is really no secrets to hide from everyone. The key to prevent such exploitation should be centered around authentication. And at least such code to this system is open. Those whom care to use it might find out ways to increase its security and combat potential threats.

From: Steve63 Avro


- Item Rez on Temp Function similar to other vendor systems.



One of my big ideas was to design a networked holographic system. The user could send data to a web server and have that data be read by the client after authentication. A dedicated rezz script could then send cetain data to the prims it rezzes. Of course, there are issues that need to be ironed out before it ever becomes a viable solution. Especially where issues in security and the limitations in lsl are concerned.

From: Steve63 Avro


One other item of possible interest. A "Light" Vendor Machine to make it operable in a High Lag Environment with very basic functions. I have seen the system fail to operate in a High Lag Environment (A Club with 60+ patrons active). It's not really a FOSSL problem and I'm not sure how that could be addressed but my thinking is that a lighte version of the system might solve that from occuring... Some kind of LAG Testing ?


I'd be flattered to see someone branch this project out with an in-world vendor client replacement that is compatable with the current vending system communications protocol. However, I don't think I will be the one to start such a branch. My focus on this vending system is on increasing its functionality and adding on the value to it to make it a suitable development environment. Of course, this means there are certain caveats to its design such as speed, but those should be ironed out as steps are taken to take care of these problems.

I hope I answered relevently. I appreciate everyone's attention and praise to this project.
Fenrus Silverstar
Registered User
Join date: 21 Mar 2007
Posts: 2
05-10-2008 17:10
Ive checked everything I can think of, perhaps somebody else had this same issue.
I have everything set up right as far as I can tell. yet when a customer or myself goes to buy the item. the pay screen shows no pay info anywhere
Ilobmirt Tenk
Registered User
Join date: 4 Jun 2007
Posts: 135
05-12-2008 06:46
Fenrus Silverstar - please see me. I might have some recommendations as how you might have come across such an error.
Ilobmirt Tenk
Registered User
Join date: 4 Jun 2007
Posts: 135
05-21-2008 17:12
Update:

Plans are to update this vending system in the near future with fixes and addons to the vending system.

-----
Fixes:

* The crypt function doesn't do two way (en/de)cryption with the symmetric key
* Vending system to work in one prim


To be Fixed:

* Validation of object ownership can only happen within the same sim as the server. I originally thought it had something to do with the way in-world email was handled, but this is not the case as pointed out by Meganutter Barthelmess. All the more reason to either file a jira, or start coding up a web service which can track object ownership accross sims.

Features:

* Added split profit functionality to the buy module
* Incorporated database technology within link modules allowing for asynchronous display updating as well as the possibility of reduced linked message activity as vending system continues to be used.
*Updated Documentation reflecting recent changes
----

Again, this hasn't happened yet, but it is in progress.
1 2