\n";
+ }
+ else
+ {
+ return "\n\n";
+ }
+ }
+
+ /**
+ * @access private
+ */
+ function xml_footer()
+ {
+ return '';
+ }
+
+ /**
+ * @access private
+ */
+ function kindOf()
+ {
+ return 'msg';
+ }
+
+ /**
+ * @access private
+ */
+ function createPayload($charset_encoding='')
+ {
+ if ($charset_encoding != '')
+ $this->content_type = 'text/xml; charset=' . $charset_encoding;
+ else
+ $this->content_type = 'text/xml';
+ $this->payload=$this->xml_header($charset_encoding);
+ $this->payload.='' . $this->methodname . "\n";
+ $this->payload.="\n";
+ for($i=0; $iparams); $i++)
+ {
+ $p=$this->params[$i];
+ $this->payload.="\n" . $p->serialize($charset_encoding) .
+ "\n";
+ }
+ $this->payload.="\n";
+ $this->payload.=$this->xml_footer();
+ }
+
+ /**
+ * Gets/sets the xmlrpc method to be invoked
+ * @param string $meth the method to be set (leave empty not to set it)
+ * @return string the method that will be invoked
+ * @access public
+ */
+ function method($meth='')
+ {
+ if($meth!='')
+ {
+ $this->methodname=$meth;
+ }
+ return $this->methodname;
+ }
+
+ /**
+ * Returns xml representation of the message. XML prologue included
+ * @return string the xml representation of the message, xml prologue included
+ * @access public
+ */
+ function serialize($charset_encoding='')
+ {
+ $this->createPayload($charset_encoding);
+ return $this->payload;
+ }
+
+ /**
+ * Add a parameter to the list of parameters to be used upon method invocation
+ * @param xmlrpcval $par
+ * @return boolean false on failure
+ * @access public
+ */
+ function addParam($par)
+ {
+ // add check: do not add to self params which are not xmlrpcvals
+ if(is_object($par) && is_a($par, 'xmlrpcval'))
+ {
+ $this->params[]=$par;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Returns the nth parameter in the message. The index zero-based.
+ * @param integer $i the index of the parameter to fetch (zero based)
+ * @return xmlrpcval the i-th parameter
+ * @access public
+ */
+ function getParam($i) { return $this->params[$i]; }
+
+ /**
+ * Returns the number of parameters in the messge.
+ * @return integer the number of parameters currently set
+ * @access public
+ */
+ function getNumParams() { return count($this->params); }
+
+ /**
+ * Given an open file handle, read all data available and parse it as axmlrpc response.
+ * NB: the file handle is not closed by this function.
+ * NNB: might have trouble in rare cases to work on network streams, as we
+ * check for a read of 0 bytes instead of feof($fp).
+ * But since checking for feof(null) returns false, we would risk an
+ * infinite loop in that case, because we cannot trust the caller
+ * to give us a valid pointer to an open file...
+ * @access public
+ * @return xmlrpcresp
+ * @todo add 2nd & 3rd param to be passed to ParseResponse() ???
+ */
+ function &parseResponseFile($fp)
+ {
+ $ipd='';
+ while($data=fread($fp, 32768))
+ {
+ $ipd.=$data;
+ }
+ //fclose($fp);
+ $r =& $this->parseResponse($ipd);
+ return $r;
+ }
+
+ /**
+ * Parses HTTP headers and separates them from data.
+ * @access private
+ */
+ function &parseResponseHeaders(&$data, $headers_processed=false)
+ {
+ // Support "web-proxy-tunelling" connections for https through proxies
+ if(preg_match('/^HTTP\/1\.[0-1] 200 Connection established/', $data))
+ {
+ // Look for CR/LF or simple LF as line separator,
+ // (even though it is not valid http)
+ $pos = strpos($data,"\r\n\r\n");
+ if($pos || is_int($pos))
+ {
+ $bd = $pos+4;
+ }
+ else
+ {
+ $pos = strpos($data,"\n\n");
+ if($pos || is_int($pos))
+ {
+ $bd = $pos+2;
+ }
+ else
+ {
+ // No separation between response headers and body: fault?
+ $bd = 0;
+ }
+ }
+ if ($bd)
+ {
+ // this filters out all http headers from proxy.
+ // maybe we could take them into account, too?
+ $data = substr($data, $bd);
+ }
+ else
+ {
+ error_log('XML-RPC: xmlrpcmsg::parseResponse: HTTPS via proxy error, tunnel connection possibly failed');
+ $r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['http_error'], $GLOBALS['xmlrpcstr']['http_error']. ' (HTTPS via proxy error, tunnel connection possibly failed)');
+ return $r;
+ }
+ }
+
+ // Strip HTTP 1.1 100 Continue header if present
+ while(preg_match('/^HTTP\/1\.1 1[0-9]{2} /', $data))
+ {
+ $pos = strpos($data, 'HTTP', 12);
+ // server sent a Continue header without any (valid) content following...
+ // give the client a chance to know it
+ if(!$pos && !is_int($pos)) // works fine in php 3, 4 and 5
+ {
+ break;
+ }
+ $data = substr($data, $pos);
+ }
+ if(!preg_match('/^HTTP\/[0-9.]+ 200 /', $data))
+ {
+ $errstr= substr($data, 0, strpos($data, "\n")-1);
+ error_log('XML-RPC: xmlrpcmsg::parseResponse: HTTP error, got response: ' .$errstr);
+ $r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['http_error'], $GLOBALS['xmlrpcstr']['http_error']. ' (' . $errstr . ')');
+ return $r;
+ }
+
+ $GLOBALS['_xh']['headers'] = array();
+ $GLOBALS['_xh']['cookies'] = array();
+
+ // be tolerant to usage of \n instead of \r\n to separate headers and data
+ // (even though it is not valid http)
+ $pos = strpos($data,"\r\n\r\n");
+ if($pos || is_int($pos))
+ {
+ $bd = $pos+4;
+ }
+ else
+ {
+ $pos = strpos($data,"\n\n");
+ if($pos || is_int($pos))
+ {
+ $bd = $pos+2;
+ }
+ else
+ {
+ // No separation between response headers and body: fault?
+ // we could take some action here instead of going on...
+ $bd = 0;
+ }
+ }
+ // be tolerant to line endings, and extra empty lines
+ $ar = split("\r?\n", trim(substr($data, 0, $pos)));
+
+ //while(list(,$line) = @each($ar))
+ while($line = current($ar))
+ {
+ next($ar);
+
+ // take care of multi-line headers and cookies
+ $arr = explode(':',$line,2);
+ if(count($arr) > 1)
+ {
+ $header_name = strtolower(trim($arr[0]));
+ /// @todo some other headers (the ones that allow a CSV list of values)
+ /// do allow many values to be passed using multiple header lines.
+ /// We should add content to $GLOBALS['_xh']['headers'][$header_name]
+ /// instead of replacing it for those...
+ if ($header_name == 'set-cookie' || $header_name == 'set-cookie2')
+ {
+ if ($header_name == 'set-cookie2')
+ {
+ // version 2 cookies:
+ // there could be many cookies on one line, comma separated
+ $cookies = explode(',', $arr[1]);
+ }
+ else
+ {
+ $cookies = array($arr[1]);
+ }
+ foreach ($cookies as $cookie)
+ {
+ // glue together all received cookies, using a comma to separate them
+ // (same as php does with getallheaders())
+ if (isset($GLOBALS['_xh']['headers'][$header_name]))
+ $GLOBALS['_xh']['headers'][$header_name] .= ', ' . trim($cookie);
+ else
+ $GLOBALS['_xh']['headers'][$header_name] = trim($cookie);
+ // parse cookie attributes, in case user wants to correctly honour them
+ // feature creep: only allow rfc-compliant cookie attributes?
+ // @todo support for server sending multiple time cookie with same name, but using different PATHs
+ $cookie = explode(';', $cookie);
+ foreach ($cookie as $pos => $val)
+ {
+ $val = explode('=', $val, 2);
+ $tag = trim($val[0]);
+ $val = trim(@$val[1]);
+ /// @todo with version 1 cookies, we should strip leading and trailing " chars
+ if ($pos == 0)
+ {
+ $cookiename = $tag;
+ $GLOBALS['_xh']['cookies'][$tag] = array();
+ $GLOBALS['_xh']['cookies'][$cookiename]['value'] = urldecode($val);
+ }
+ else
+ {
+ if ($tag != 'value')
+ {
+ $GLOBALS['_xh']['cookies'][$cookiename][$tag] = $val;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ $GLOBALS['_xh']['headers'][$header_name] = trim($arr[1]);
+ }
+ }
+ elseif(isset($header_name))
+ {
+ /// @todo version1 cookies might span multiple lines, thus breaking the parsing above
+ $GLOBALS['_xh']['headers'][$header_name] .= ' ' . trim($line);
+ }
+ }
+
+ $data = substr($data, $bd);
+
+ if($this->debug && count($GLOBALS['_xh']['headers']))
+ {
+ print '';
+ foreach($GLOBALS['_xh']['headers'] as $header => $value)
+ {
+ print htmlentities("HEADER: $header: $value\n");
+ }
+ foreach($GLOBALS['_xh']['cookies'] as $header => $value)
+ {
+ print htmlentities("COOKIE: $header={$value['value']}\n");
+ }
+ print "\n";
+ }
+
+ // if CURL was used for the call, http headers have been processed,
+ // and dechunking + reinflating have been carried out
+ if(!$headers_processed)
+ {
+ // Decode chunked encoding sent by http 1.1 servers
+ if(isset($GLOBALS['_xh']['headers']['transfer-encoding']) && $GLOBALS['_xh']['headers']['transfer-encoding'] == 'chunked')
+ {
+ if(!$data = decode_chunked($data))
+ {
+ error_log('XML-RPC: xmlrpcmsg::parseResponse: errors occurred when trying to rebuild the chunked data received from server');
+ $r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['dechunk_fail'], $GLOBALS['xmlrpcstr']['dechunk_fail']);
+ return $r;
+ }
+ }
+
+ // Decode gzip-compressed stuff
+ // code shamelessly inspired from nusoap library by Dietrich Ayala
+ if(isset($GLOBALS['_xh']['headers']['content-encoding']))
+ {
+ $GLOBALS['_xh']['headers']['content-encoding'] = str_replace('x-', '', $GLOBALS['_xh']['headers']['content-encoding']);
+ if($GLOBALS['_xh']['headers']['content-encoding'] == 'deflate' || $GLOBALS['_xh']['headers']['content-encoding'] == 'gzip')
+ {
+ // if decoding works, use it. else assume data wasn't gzencoded
+ if(function_exists('gzinflate'))
+ {
+ if($GLOBALS['_xh']['headers']['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data))
+ {
+ $data = $degzdata;
+ if($this->debug)
+ print "---INFLATED RESPONSE---[".strlen($data)." chars]---\n" . htmlentities($data) . "\n---END---
";
+ }
+ elseif($GLOBALS['_xh']['headers']['content-encoding'] == 'gzip' && $degzdata = @gzinflate(substr($data, 10)))
+ {
+ $data = $degzdata;
+ if($this->debug)
+ print "---INFLATED RESPONSE---[".strlen($data)." chars]---\n" . htmlentities($data) . "\n---END---
";
+ }
+ else
+ {
+ error_log('XML-RPC: xmlrpcmsg::parseResponse: errors occurred when trying to decode the deflated data received from server');
+ $r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['decompress_fail'], $GLOBALS['xmlrpcstr']['decompress_fail']);
+ return $r;
+ }
+ }
+ else
+ {
+ error_log('XML-RPC: xmlrpcmsg::parseResponse: the server sent deflated data. Your php install must have the Zlib extension compiled in to support this.');
+ $r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['cannot_decompress'], $GLOBALS['xmlrpcstr']['cannot_decompress']);
+ return $r;
+ }
+ }
+ }
+ } // end of 'if needed, de-chunk, re-inflate response'
+
+ // real stupid hack to avoid PHP 4 complaining about returning NULL by ref
+ $r = null;
+ $r =& $r;
+ return $r;
+ }
+
+ /**
+ * Parse the xmlrpc response contained in the string $data and return an xmlrpcresp object.
+ * @param string $data the xmlrpc response, eventually including http headers
+ * @param bool $headers_processed when true prevents parsing HTTP headers for interpretation of content-encoding and consequent decoding
+ * @param string $return_type decides return type, i.e. content of response->value(). Either 'xmlrpcvals', 'xml' or 'phpvals'
+ * @return xmlrpcresp
+ * @access public
+ */
+ function &parseResponse($data='', $headers_processed=false, $return_type='xmlrpcvals')
+ {
+ if($this->debug)
+ {
+ //by maHo, replaced htmlspecialchars with htmlentities
+ print "---GOT---\n" . htmlentities($data) . "\n---END---\n
";
+ }
+
+ if($data == '')
+ {
+ error_log('XML-RPC: xmlrpcmsg::parseResponse: no response received from server.');
+ $r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['no_data'], $GLOBALS['xmlrpcstr']['no_data']);
+ return $r;
+ }
+
+ $GLOBALS['_xh']=array();
+
+ $raw_data = $data;
+ // parse the HTTP headers of the response, if present, and separate them from data
+ if(substr($data, 0, 4) == 'HTTP')
+ {
+ $r =& $this->parseResponseHeaders($data, $headers_processed);
+ if ($r)
+ {
+ // failed processing of HTTP response headers
+ // save into response obj the full payload received, for debugging
+ $r->raw_data = $data;
+ return $r;
+ }
+ }
+ else
+ {
+ $GLOBALS['_xh']['headers'] = array();
+ $GLOBALS['_xh']['cookies'] = array();
+ }
+
+ if($this->debug)
+ {
+ $start = strpos($data, '', $start);
+ $comments = substr($data, $start, $end-$start);
+ print "---SERVER DEBUG INFO (DECODED) ---\n\t".htmlentities(str_replace("\n", "\n\t", base64_decode($comments)))."\n---END---\n";
+ }
+ }
+
+ // be tolerant of extra whitespace in response body
+ $data = trim($data);
+
+ /// @todo return an error msg if $data=='' ?
+
+ // be tolerant of junk after methodResponse (e.g. javascript ads automatically inserted by free hosts)
+ // idea from Luca Mariano originally in PEARified version of the lib
+ $bd = false;
+ // Poor man's version of strrpos for php 4...
+ $pos = strpos($data, '');
+ while($pos || is_int($pos))
+ {
+ $bd = $pos+17;
+ $pos = strpos($data, '', $bd);
+ }
+ if($bd)
+ {
+ $data = substr($data, 0, $bd);
+ }
+
+ // if user wants back raw xml, give it to him
+ if ($return_type == 'xml')
+ {
+ $r = new xmlrpcresp($data, 0, '', 'xml');
+ $r->hdrs = $GLOBALS['_xh']['headers'];
+ $r->_cookies = $GLOBALS['_xh']['cookies'];
+ $r->raw_data = $raw_data;
+ return $r;
+ }
+
+ // try to 'guestimate' the character encoding of the received response
+ $resp_encoding = guess_encoding(@$GLOBALS['_xh']['headers']['content-type'], $data);
+
+ $GLOBALS['_xh']['ac']='';
+ //$GLOBALS['_xh']['qt']=''; //unused...
+ $GLOBALS['_xh']['stack'] = array();
+ $GLOBALS['_xh']['valuestack'] = array();
+ $GLOBALS['_xh']['isf']=0; // 0 = OK, 1 for xmlrpc fault responses, 2 = invalid xmlrpc
+ $GLOBALS['_xh']['isf_reason']='';
+ $GLOBALS['_xh']['rt']=''; // 'methodcall or 'methodresponse'
+
+ // if response charset encoding is not known / supported, try to use
+ // the default encoding and parse the xml anyway, but log a warning...
+ if (!in_array($resp_encoding, array('UTF-8', 'ISO-8859-1', 'US-ASCII')))
+ // the following code might be better for mb_string enabled installs, but
+ // makes the lib about 200% slower...
+ //if (!is_valid_charset($resp_encoding, array('UTF-8', 'ISO-8859-1', 'US-ASCII')))
+ {
+ error_log('XML-RPC: xmlrpcmsg::parseResponse: invalid charset encoding of received response: '.$resp_encoding);
+ $resp_encoding = $GLOBALS['xmlrpc_defencoding'];
+ }
+ $parser = xml_parser_create($resp_encoding);
+ xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);
+ // G. Giunta 2005/02/13: PHP internally uses ISO-8859-1, so we have to tell
+ // the xml parser to give us back data in the expected charset.
+ // What if internal encoding is not in one of the 3 allowed?
+ // we use the broadest one, ie. utf8
+ // This allows to send data which is native in various charset,
+ // by extending xmlrpc_encode_entitites() and setting xmlrpc_internalencoding
+ if (!in_array($GLOBALS['xmlrpc_internalencoding'], array('UTF-8', 'ISO-8859-1', 'US-ASCII')))
+ {
+ xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, 'UTF-8');
+ }
+ else
+ {
+ xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $GLOBALS['xmlrpc_internalencoding']);
+ }
+
+ if ($return_type == 'phpvals')
+ {
+ xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee_fast');
+ }
+ else
+ {
+ xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee');
+ }
+
+ xml_set_character_data_handler($parser, 'xmlrpc_cd');
+ xml_set_default_handler($parser, 'xmlrpc_dh');
+
+ // first error check: xml not well formed
+ if(!xml_parse($parser, $data, count($data)))
+ {
+ // thanks to Peter Kocks
+ if((xml_get_current_line_number($parser)) == 1)
+ {
+ $errstr = 'XML error at line 1, check URL';
+ }
+ else
+ {
+ $errstr = sprintf('XML error: %s at line %d, column %d',
+ xml_error_string(xml_get_error_code($parser)),
+ xml_get_current_line_number($parser), xml_get_current_column_number($parser));
+ }
+ error_log($errstr);
+ $r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['invalid_return'], $GLOBALS['xmlrpcstr']['invalid_return'].' ('.$errstr.')');
+ xml_parser_free($parser);
+ if($this->debug)
+ {
+ print $errstr;
+ }
+ $r->hdrs = $GLOBALS['_xh']['headers'];
+ $r->_cookies = $GLOBALS['_xh']['cookies'];
+ $r->raw_data = $raw_data;
+ return $r;
+ }
+ xml_parser_free($parser);
+ // second error check: xml well formed but not xml-rpc compliant
+ if ($GLOBALS['_xh']['isf'] > 1)
+ {
+ if ($this->debug)
+ {
+ /// @todo echo something for user?
+ }
+
+ $r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['invalid_return'],
+ $GLOBALS['xmlrpcstr']['invalid_return'] . ' ' . $GLOBALS['_xh']['isf_reason']);
+ }
+ // third error check: parsing of the response has somehow gone boink.
+ // NB: shall we omit this check, since we trust the parsing code?
+ elseif ($return_type == 'xmlrpcvals' && !is_object($GLOBALS['_xh']['value']))
+ {
+ // something odd has happened
+ // and it's time to generate a client side error
+ // indicating something odd went on
+ $r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['invalid_return'],
+ $GLOBALS['xmlrpcstr']['invalid_return']);
+ }
+ else
+ {
+ if ($this->debug)
+ {
+ print "---PARSED---\n";
+ // somehow htmlentities chokes on var_export, and some full html string...
+ //print htmlentitites(var_export($GLOBALS['_xh']['value'], true));
+ print htmlspecialchars(var_export($GLOBALS['_xh']['value'], true));
+ print "\n---END---
";
+ }
+
+ // note that using =& will raise an error if $GLOBALS['_xh']['st'] does not generate an object.
+ $v =& $GLOBALS['_xh']['value'];
+
+ if($GLOBALS['_xh']['isf'])
+ {
+ /// @todo we should test here if server sent an int and a string,
+ /// and/or coerce them into such...
+ if ($return_type == 'xmlrpcvals')
+ {
+ $errno_v = $v->structmem('faultCode');
+ $errstr_v = $v->structmem('faultString');
+ $errno = $errno_v->scalarval();
+ $errstr = $errstr_v->scalarval();
+ }
+ else
+ {
+ $errno = $v['faultCode'];
+ $errstr = $v['faultString'];
+ }
+
+ if($errno == 0)
+ {
+ // FAULT returned, errno needs to reflect that
+ $errno = -1;
+ }
+
+ $r = new xmlrpcresp(0, $errno, $errstr);
+ }
+ else
+ {
+ $r = new xmlrpcresp($v, 0, '', $return_type);
+ }
+ }
+
+ $r->hdrs = $GLOBALS['_xh']['headers'];
+ $r->_cookies = $GLOBALS['_xh']['cookies'];
+ $r->raw_data = $raw_data;
+ return $r;
+ }
+ }
+
+
+
+ class xmlrpcval
+ {
+ var $me=array();
+ var $mytype=0;
+ var $_php_class=null;
+
+ /**
+ * @param mixed $val
+ * @param string $type any valid xmlrpc type name (lowercase). If null, 'string' is assumed
+ */
+ function __construct($val=-1, $type='')
+ {
+ /// @todo: optimization creep - do not call addXX, do it all inline.
+ /// downside: booleans will not be coerced anymore
+ if($val!==-1 || $type!='')
+ {
+ // optimization creep: inlined all work done by constructor
+ switch($type)
+ {
+ case '':
+ $this->mytype=1;
+ $this->me['string']=$val;
+ break;
+ case 'i4':
+ case 'int':
+ case 'double':
+ case 'string':
+ case 'boolean':
+ case 'dateTime.iso8601':
+ case 'base64':
+ case 'null':
+ $this->mytype=1;
+ $this->me[$type]=$val;
+ break;
+ case 'array':
+ $this->mytype=2;
+ $this->me['array']=$val;
+ break;
+ case 'struct':
+ $this->mytype=3;
+ $this->me['struct']=$val;
+ break;
+ default:
+ error_log("XML-RPC: xmlrpcval::xmlrpcval: not a known type ($type)");
+ }
+ /*if($type=='')
+ {
+ $type='string';
+ }
+ if($GLOBALS['xmlrpcTypes'][$type]==1)
+ {
+ $this->addScalar($val,$type);
+ }
+ elseif($GLOBALS['xmlrpcTypes'][$type]==2)
+ {
+ $this->addArray($val);
+ }
+ elseif($GLOBALS['xmlrpcTypes'][$type]==3)
+ {
+ $this->addStruct($val);
+ }*/
+ }
+ }
+
+ /**
+ * Add a single php value to an (unitialized) xmlrpcval
+ * @param mixed $val
+ * @param string $type
+ * @return int 1 or 0 on failure
+ */
+ function addScalar($val, $type='string')
+ {
+ $typeof=@$GLOBALS['xmlrpcTypes'][$type];
+ if($typeof!=1)
+ {
+ error_log("XML-RPC: xmlrpcval::addScalar: not a scalar type ($type)");
+ return 0;
+ }
+
+ // coerce booleans into correct values
+ // NB: we should iether do it for datetimes, integers and doubles, too,
+ // or just plain remove this check, implemnted on booleans only...
+ if($type==$GLOBALS['xmlrpcBoolean'])
+ {
+ if(strcasecmp($val,'true')==0 || $val==1 || ($val==true && strcasecmp($val,'false')))
+ {
+ $val=true;
+ }
+ else
+ {
+ $val=false;
+ }
+ }
+
+ switch($this->mytype)
+ {
+ case 1:
+ error_log('XML-RPC: xmlrpcval::addScalar: scalar xmlrpcval can have only one value');
+ return 0;
+ case 3:
+ error_log('XML-RPC: xmlrpcval::addScalar: cannot add anonymous scalar to struct xmlrpcval');
+ return 0;
+ case 2:
+ // we're adding a scalar value to an array here
+ //$ar=$this->me['array'];
+ //$ar[] = new xmlrpcval($val, $type);
+ //$this->me['array']=$ar;
+ // Faster (?) avoid all the costly array-copy-by-val done here...
+ $this->me['array'][] = new xmlrpcval($val, $type);
+ return 1;
+ default:
+ // a scalar, so set the value and remember we're scalar
+ $this->me[$type]=$val;
+ $this->mytype=$typeof;
+ return 1;
+ }
+ }
+
+ /**
+ * Add an array of xmlrpcval objects to an xmlrpcval
+ * @param array $vals
+ * @return int 1 or 0 on failure
+ * @access public
+ *
+ * @todo add some checking for $vals to be an array of xmlrpcvals?
+ */
+ function addArray($vals)
+ {
+ if($this->mytype==0)
+ {
+ $this->mytype=$GLOBALS['xmlrpcTypes']['array'];
+ $this->me['array']=$vals;
+ return 1;
+ }
+ elseif($this->mytype==2)
+ {
+ // we're adding to an array here
+ $this->me['array'] = array_merge($this->me['array'], $vals);
+ return 1;
+ }
+ else
+ {
+ error_log('XML-RPC: xmlrpcval::addArray: already initialized as a [' . $this->kindOf() . ']');
+ return 0;
+ }
+ }
+
+ /**
+ * Add an array of named xmlrpcval objects to an xmlrpcval
+ * @param array $vals
+ * @return int 1 or 0 on failure
+ * @access public
+ *
+ * @todo add some checking for $vals to be an array?
+ */
+ function addStruct($vals)
+ {
+ if($this->mytype==0)
+ {
+ $this->mytype=$GLOBALS['xmlrpcTypes']['struct'];
+ $this->me['struct']=$vals;
+ return 1;
+ }
+ elseif($this->mytype==3)
+ {
+ // we're adding to a struct here
+ $this->me['struct'] = array_merge($this->me['struct'], $vals);
+ return 1;
+ }
+ else
+ {
+ error_log('XML-RPC: xmlrpcval::addStruct: already initialized as a [' . $this->kindOf() . ']');
+ return 0;
+ }
+ }
+
+ // poor man's version of print_r ???
+ // DEPRECATED!
+ function dump($ar)
+ {
+ foreach($ar as $key => $val)
+ {
+ echo "$key => $val
";
+ if($key == 'array')
+ {
+ //while(list($key2, $val2) = each($val))
+ while(list($key2, $val2) = array(key($val), current($val)))
+ {
+ echo "-- $key2 => $val2
";
+ next($val);
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns a string containing "struct", "array" or "scalar" describing the base type of the value
+ * @return string
+ * @access public
+ */
+ function kindOf()
+ {
+ switch($this->mytype)
+ {
+ case 3:
+ return 'struct';
+ break;
+ case 2:
+ return 'array';
+ break;
+ case 1:
+ return 'scalar';
+ break;
+ default:
+ return 'undef';
+ }
+ }
+
+ /**
+ * @access private
+ */
+ function serializedata($typ, $val, $charset_encoding='')
+ {
+ $rs='';
+ switch(@$GLOBALS['xmlrpcTypes'][$typ])
+ {
+ case 1:
+ switch($typ)
+ {
+ case $GLOBALS['xmlrpcBase64']:
+ $rs.="<${typ}>" . base64_encode($val) . "${typ}>";
+ break;
+ case $GLOBALS['xmlrpcBoolean']:
+ $rs.="<${typ}>" . ($val ? '1' : '0') . "${typ}>";
+ break;
+ case $GLOBALS['xmlrpcString']:
+ // G. Giunta 2005/2/13: do NOT use htmlentities, since
+ // it will produce named html entities, which are invalid xml
+ $rs.="<${typ}>" . xmlrpc_encode_entitites($val, $GLOBALS['xmlrpc_internalencoding'], $charset_encoding). "${typ}>";
+ break;
+ case $GLOBALS['xmlrpcInt']:
+ case $GLOBALS['xmlrpcI4']:
+ $rs.="<${typ}>".(int)$val."${typ}>";
+ break;
+ case $GLOBALS['xmlrpcDouble']:
+ // avoid using standard conversion of float to string because it is locale-dependent,
+ // and also because the xmlrpc spec forbids exponential notation
+ // sprintf('%F') would be most likely ok but it is only available since PHP 4.3.10 and PHP 5.0.3.
+ // The code below tries its best at keeping max precision while avoiding exp notation,
+ // but there is of course no limit in the number of decimal places to be used...
+ $rs.="<${typ}>".preg_replace('/\\.?0+$/','',number_format((double)$val, 128, '.', ''))."${typ}>";
+ break;
+ case $GLOBALS['xmlrpcNull']:
+ $rs.="";
+ break;
+ default:
+ // no standard type value should arrive here, but provide a possibility
+ // for xmlrpcvals of unknown type...
+ $rs.="<${typ}>${val}${typ}>";
+ }
+ break;
+ case 3:
+ // struct
+ if ($this->_php_class)
+ {
+ $rs.='\n";
+ }
+ else
+ {
+ $rs.="\n";
+ }
+ foreach($val as $key2 => $val2)
+ {
+ $rs.=''.xmlrpc_encode_entitites($key2, $GLOBALS['xmlrpc_internalencoding'], $charset_encoding)."\n";
+ //$rs.=$this->serializeval($val2);
+ $rs.=$val2->serialize($charset_encoding);
+ $rs.="\n";
+ }
+ $rs.='';
+ break;
+ case 2:
+ // array
+ $rs.="\n\n";
+ for($i=0; $iserializeval($val[$i]);
+ $rs.=$val[$i]->serialize($charset_encoding);
+ }
+ $rs.="\n";
+ break;
+ default:
+ break;
+ }
+ return $rs;
+ }
+
+ /**
+ * Returns xml representation of the value. XML prologue not included
+ * @param string $charset_encoding the charset to be used for serialization. if null, US-ASCII is assumed
+ * @return string
+ * @access public
+ */
+ function serialize($charset_encoding='')
+ {
+ // add check? slower, but helps to avoid recursion in serializing broken xmlrpcvals...
+ //if (is_object($o) && (get_class($o) == 'xmlrpcval' || is_subclass_of($o, 'xmlrpcval')))
+ //{
+ reset($this->me);
+ //list($typ, $val) = each($this->me);
+ $typ = key($this->me);
+ $val = current($this->me);
+ next($this->me);
+ return '' . $this->serializedata($typ, $val, $charset_encoding) . "\n";
+ //}
+ }
+
+ // DEPRECATED
+ function serializeval($o)
+ {
+ // add check? slower, but helps to avoid recursion in serializing broken xmlrpcvals...
+ //if (is_object($o) && (get_class($o) == 'xmlrpcval' || is_subclass_of($o, 'xmlrpcval')))
+ //{
+ $ar=$o->me;
+ reset($ar);
+ //list($typ, $val) = each($ar);
+ $typ = key($ar);
+ $val = current($ar);
+ next($ar);
+ return '' . $this->serializedata($typ, $val) . "\n";
+ //}
+ }
+
+ /**
+ * Checks wheter a struct member with a given name is present.
+ * Works only on xmlrpcvals of type struct.
+ * @param string $m the name of the struct member to be looked up
+ * @return boolean
+ * @access public
+ */
+ function structmemexists($m)
+ {
+ return array_key_exists($m, $this->me['struct']);
+ }
+
+ /**
+ * Returns the value of a given struct member (an xmlrpcval object in itself).
+ * Will raise a php warning if struct member of given name does not exist
+ * @param string $m the name of the struct member to be looked up
+ * @return xmlrpcval
+ * @access public
+ */
+ function structmem($m)
+ {
+ return $this->me['struct'][$m];
+ }
+
+ /**
+ * Reset internal pointer for xmlrpcvals of type struct.
+ * @access public
+ */
+ function structreset()
+ {
+ reset($this->me['struct']);
+ }
+
+ /**
+ * Return next member element for xmlrpcvals of type struct.
+ * @return xmlrpcval
+ * @access public
+ */
+ function structeach()
+ {
+ //return each($this->me['struct']);
+
+ $ret = array(key($this->me['struct']), current($this->me['struct']));
+ next($this->me['struct']);
+ return $ret;
+ }
+
+ // DEPRECATED! this code looks like it is very fragile and has not been fixed
+ // for a long long time. Shall we remove it for 2.0?
+ function getval()
+ {
+ // UNSTABLE
+ reset($this->me);
+ //list($a,$b)=each($this->me);
+ $a = key($this->me);
+ $b = current($this->me);
+ next($this->me);
+
+ // contributed by I Sofer, 2001-03-24
+ // add support for nested arrays to scalarval
+ // i've created a new method here, so as to
+ // preserve back compatibility
+
+ if(is_array($b))
+ {
+ @reset($b);
+
+ //while(list($id,$cont) = @each($b))
+ while(list($id, $cont) = array(key($b), current($b)))
+ {
+ next($b);
+ $b[$id] = $cont->scalarval();
+ }
+ }
+
+ // add support for structures directly encoding php objects
+ if(is_object($b))
+ {
+ $t = get_object_vars($b);
+
+ @reset($t);
+ //while(list($id,$cont) = @each($t))
+ while(list($id, $cont) = array(key($t), current($t)))
+ {
+ next($t);
+ $t[$id] = $cont->scalarval();
+ }
+
+ @reset($t);
+ //while(list($id,$cont) = @each($t))
+ while(list($id, $cont) = array(key($t), current($t)))
+ {
+ next($t);
+ @$b->$id = $cont;
+ }
+ }
+ // end contrib
+ return $b;
+ }
+
+ /**
+ * Returns the value of a scalar xmlrpcval
+ * @return mixed
+ * @access public
+ */
+ function scalarval()
+ {
+ reset($this->me);
+ //list(,$b)=each($this->me);
+ $b = current($this->me);
+ next($this->me);
+ return $b;
+ }
+
+ /**
+ * Returns the type of the xmlrpcval.
+ * For integers, 'int' is always returned in place of 'i4'
+ * @return string
+ * @access public
+ */
+ function scalartyp()
+ {
+ reset($this->me);
+ //list($a,)=each($this->me);
+ $a = current($this->me);
+ next($this->me);
+
+ if($a==$GLOBALS['xmlrpcI4'])
+ {
+ $a=$GLOBALS['xmlrpcInt'];
+ }
+ return $a;
+ }
+
+ /**
+ * Returns the m-th member of an xmlrpcval of struct type
+ * @param integer $m the index of the value to be retrieved (zero based)
+ * @return xmlrpcval
+ * @access public
+ */
+ function arraymem($m)
+ {
+ return $this->me['array'][$m];
+ }
+
+ /**
+ * Returns the number of members in an xmlrpcval of array type
+ * @return integer
+ * @access public
+ */
+ function arraysize()
+ {
+ return count($this->me['array']);
+ }
+
+ /**
+ * Returns the number of members in an xmlrpcval of struct type
+ * @return integer
+ * @access public
+ */
+ function structsize()
+ {
+ return count($this->me['struct']);
+ }
+ }
+
+
+ // date helpers
+
+ /**
+ * Given a timestamp, return the corresponding ISO8601 encoded string.
+ *
+ * Really, timezones ought to be supported
+ * but the XML-RPC spec says:
+ *
+ * "Don't assume a timezone. It should be specified by the server in its
+ * documentation what assumptions it makes about timezones."
+ *
+ * These routines always assume localtime unless
+ * $utc is set to 1, in which case UTC is assumed
+ * and an adjustment for locale is made when encoding
+ *
+ * @param int $timet (timestamp)
+ * @param int $utc (0 or 1)
+ * @return string
+ */
+ function iso8601_encode($timet, $utc=0)
+ {
+ if(!$utc)
+ {
+ $t=strftime("%Y%m%dT%H:%M:%S", $timet);
+ }
+ else
+ {
+ if(function_exists('gmstrftime'))
+ {
+ // gmstrftime doesn't exist in some versions
+ // of PHP
+ $t=gmstrftime("%Y%m%dT%H:%M:%S", $timet);
+ }
+ else
+ {
+ $t=strftime("%Y%m%dT%H:%M:%S", $timet-date('Z'));
+ }
+ }
+ return $t;
+ }
+
+ /**
+ * Given an ISO8601 date string, return a timet in the localtime, or UTC
+ * @param string $idate
+ * @param int $utc either 0 or 1
+ * @return int (datetime)
+ */
+ function iso8601_decode($idate, $utc=0)
+ {
+ $t=0;
+ if(preg_match('/([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})/', $idate, $regs))
+ {
+ if($utc)
+ {
+ $t=gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
+ }
+ else
+ {
+ $t=mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
+ }
+ }
+ return $t;
+ }
+
+ /**
+ * Takes an xmlrpc value in PHP xmlrpcval object format and translates it into native PHP types.
+ *
+ * Works with xmlrpc message objects as input, too.
+ *
+ * Given proper options parameter, can rebuild generic php object instances
+ * (provided those have been encoded to xmlrpc format using a corresponding
+ * option in php_xmlrpc_encode())
+ * PLEASE NOTE that rebuilding php objects involves calling their constructor function.
+ * This means that the remote communication end can decide which php code will
+ * get executed on your server, leaving the door possibly open to 'php-injection'
+ * style of attacks (provided you have some classes defined on your server that
+ * might wreak havoc if instances are built outside an appropriate context).
+ * Make sure you trust the remote server/client before eanbling this!
+ *
+ * @author Dan Libby (dan@libby.com)
+ *
+ * @param xmlrpcval $xmlrpc_val
+ * @param array $options if 'decode_php_objs' is set in the options array, xmlrpc structs can be decoded into php objects
+ * @return mixed
+ */
+ function php_xmlrpc_decode($xmlrpc_val, $options=array())
+ {
+ switch($xmlrpc_val->kindOf())
+ {
+ case 'scalar':
+ if (in_array('extension_api', $options))
+ {
+ reset($xmlrpc_val->me);
+ //list($typ,$val) = each($xmlrpc_val->me);
+ $typ = key($xmlrpc_val->me);
+ $val = current($xmlrpc_val->me);
+ next($xmlrpc_val->me);
+
+ switch ($typ)
+ {
+ case 'dateTime.iso8601':
+ $xmlrpc_val->scalar = $val;
+ $xmlrpc_val->xmlrpc_type = 'datetime';
+ $xmlrpc_val->timestamp = iso8601_decode($val);
+ return $xmlrpc_val;
+ case 'base64':
+ $xmlrpc_val->scalar = $val;
+ $xmlrpc_val->type = $typ;
+ return $xmlrpc_val;
+ default:
+ return $xmlrpc_val->scalarval();
+ }
+ }
+ return $xmlrpc_val->scalarval();
+ case 'array':
+ $size = $xmlrpc_val->arraysize();
+ $arr = array();
+ for($i = 0; $i < $size; $i++)
+ {
+ $arr[] = php_xmlrpc_decode($xmlrpc_val->arraymem($i), $options);
+ }
+ return $arr;
+ case 'struct':
+ $xmlrpc_val->structreset();
+ // If user said so, try to rebuild php objects for specific struct vals.
+ /// @todo should we raise a warning for class not found?
+ // shall we check for proper subclass of xmlrpcval instead of
+ // presence of _php_class to detect what we can do?
+ if (in_array('decode_php_objs', $options) && $xmlrpc_val->_php_class != ''
+ && class_exists($xmlrpc_val->_php_class))
+ {
+ $obj = @new $xmlrpc_val->_php_class;
+ while(list($key,$value)=$xmlrpc_val->structeach())
+ {
+ $obj->$key = php_xmlrpc_decode($value, $options);
+ }
+ return $obj;
+ }
+ else
+ {
+ $arr = array();
+ while(list($key,$value)=$xmlrpc_val->structeach())
+ {
+ $arr[$key] = php_xmlrpc_decode($value, $options);
+ }
+ return $arr;
+ }
+ case 'msg':
+ $paramcount = $xmlrpc_val->getNumParams();
+ $arr = array();
+ for($i = 0; $i < $paramcount; $i++)
+ {
+ $arr[] = php_xmlrpc_decode($xmlrpc_val->getParam($i));
+ }
+ return $arr;
+ }
+ }
+
+ // This constant left here only for historical reasons...
+ // it was used to decide if we have to define xmlrpc_encode on our own, but
+ // we do not do it anymore
+ if(function_exists('xmlrpc_decode'))
+ {
+ define('XMLRPC_EPI_ENABLED','1');
+ }
+ else
+ {
+ define('XMLRPC_EPI_ENABLED','0');
+ }
+
+ /**
+ * Takes native php types and encodes them into xmlrpc PHP object format.
+ * It will not re-encode xmlrpcval objects.
+ *
+ * Feature creep -- could support more types via optional type argument
+ * (string => datetime support has been added, ??? => base64 not yet)
+ *
+ * If given a proper options parameter, php object instances will be encoded
+ * into 'special' xmlrpc values, that can later be decoded into php objects
+ * by calling php_xmlrpc_decode() with a corresponding option
+ *
+ * @author Dan Libby (dan@libby.com)
+ *
+ * @param mixed $php_val the value to be converted into an xmlrpcval object
+ * @param array $options can include 'encode_php_objs', 'auto_dates', 'null_extension' or 'extension_api'
+ * @return xmlrpcval
+ */
+ function &php_xmlrpc_encode($php_val, $options=array())
+ {
+ $type = gettype($php_val);
+ switch($type)
+ {
+ case 'string':
+ if (in_array('auto_dates', $options) && preg_match('/^[0-9]{8}T[0-9]{2}:[0-9]{2}:[0-9]{2}$/', $php_val))
+ $xmlrpc_val = new xmlrpcval($php_val, $GLOBALS['xmlrpcDateTime']);
+ else
+ $xmlrpc_val = new xmlrpcval($php_val, $GLOBALS['xmlrpcString']);
+ break;
+ case 'integer':
+ $xmlrpc_val = new xmlrpcval($php_val, $GLOBALS['xmlrpcInt']);
+ break;
+ case 'double':
+ $xmlrpc_val = new xmlrpcval($php_val, $GLOBALS['xmlrpcDouble']);
+ break;
+ //
+ // Add support for encoding/decoding of booleans, since they are supported in PHP
+ case 'boolean':
+ $xmlrpc_val = new xmlrpcval($php_val, $GLOBALS['xmlrpcBoolean']);
+ break;
+ //
+ case 'array':
+ // PHP arrays can be encoded to either xmlrpc structs or arrays,
+ // depending on wheter they are hashes or plain 0..n integer indexed
+ // A shorter one-liner would be
+ // $tmp = array_diff(array_keys($php_val), range(0, count($php_val)-1));
+ // but execution time skyrockets!
+ $j = 0;
+ $arr = array();
+ $ko = false;
+ foreach($php_val as $key => $val)
+ {
+ $arr[$key] =& php_xmlrpc_encode($val, $options);
+ if(!$ko && $key !== $j)
+ {
+ $ko = true;
+ }
+ $j++;
+ }
+ if($ko)
+ {
+ $xmlrpc_val = new xmlrpcval($arr, $GLOBALS['xmlrpcStruct']);
+ }
+ else
+ {
+ $xmlrpc_val = new xmlrpcval($arr, $GLOBALS['xmlrpcArray']);
+ }
+ break;
+ case 'object':
+ if(is_a($php_val, 'xmlrpcval'))
+ {
+ $xmlrpc_val = $php_val;
+ }
+ else
+ {
+ $arr = array();
+ //while(list($k,$v) = each($php_val))
+ while(list($k,$v) = array(key($php_val), current($php_val)))
+ {
+ $arr[$k] = php_xmlrpc_encode($v, $options);
+ next($php_val);
+ }
+ $xmlrpc_val = new xmlrpcval($arr, $GLOBALS['xmlrpcStruct']);
+ if (in_array('encode_php_objs', $options))
+ {
+ // let's save original class name into xmlrpcval:
+ // might be useful later on...
+ $xmlrpc_val->_php_class = get_class($php_val);
+ }
+ }
+ break;
+ case 'NULL':
+ if (in_array('extension_api', $options))
+ {
+ $xmlrpc_val = new xmlrpcval('', $GLOBALS['xmlrpcString']);
+ }
+ if (in_array('null_extension', $options))
+ {
+ $xmlrpc_val = new xmlrpcval('', $GLOBALS['xmlrpcNull']);
+ }
+ else
+ {
+ $xmlrpc_val = new xmlrpcval();
+ }
+ break;
+ case 'resource':
+ if (in_array('extension_api', $options))
+ {
+ $xmlrpc_val = new xmlrpcval((int)$php_val, $GLOBALS['xmlrpcInt']);
+ }
+ else
+ {
+ $xmlrpc_val = new xmlrpcval();
+ }
+ // catch "user function", "unknown type"
+ default:
+ // giancarlo pinerolo
+ // it has to return
+ // an empty object in case, not a boolean.
+ $xmlrpc_val = new xmlrpcval();
+ break;
+ }
+ return $xmlrpc_val;
+ }
+
+ /**
+ * Convert the xml representation of a method response, method request or single
+ * xmlrpc value into the appropriate object (a.k.a. deserialize)
+ * @param string $xml_val
+ * @param array $options
+ * @return mixed false on error, or an instance of either xmlrpcval, xmlrpcmsg or xmlrpcresp
+ */
+ function php_xmlrpc_decode_xml($xml_val, $options=array())
+ {
+ $GLOBALS['_xh'] = array();
+ $GLOBALS['_xh']['ac'] = '';
+ $GLOBALS['_xh']['stack'] = array();
+ $GLOBALS['_xh']['valuestack'] = array();
+ $GLOBALS['_xh']['params'] = array();
+ $GLOBALS['_xh']['pt'] = array();
+ $GLOBALS['_xh']['isf'] = 0;
+ $GLOBALS['_xh']['isf_reason'] = '';
+ $GLOBALS['_xh']['method'] = false;
+ $GLOBALS['_xh']['rt'] = '';
+ /// @todo 'guestimate' encoding
+ $parser = xml_parser_create();
+ xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);
+ // What if internal encoding is not in one of the 3 allowed?
+ // we use the broadest one, ie. utf8!
+ if (!in_array($GLOBALS['xmlrpc_internalencoding'], array('UTF-8', 'ISO-8859-1', 'US-ASCII')))
+ {
+ xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, 'UTF-8');
+ }
+ else
+ {
+ xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $GLOBALS['xmlrpc_internalencoding']);
+ }
+ xml_set_element_handler($parser, 'xmlrpc_se_any', 'xmlrpc_ee');
+ xml_set_character_data_handler($parser, 'xmlrpc_cd');
+ xml_set_default_handler($parser, 'xmlrpc_dh');
+ if(!xml_parse($parser, $xml_val, 1))
+ {
+ $errstr = sprintf('XML error: %s at line %d, column %d',
+ xml_error_string(xml_get_error_code($parser)),
+ xml_get_current_line_number($parser), xml_get_current_column_number($parser));
+ error_log($errstr);
+ xml_parser_free($parser);
+ return false;
+ }
+ xml_parser_free($parser);
+ if ($GLOBALS['_xh']['isf'] > 1) // test that $GLOBALS['_xh']['value'] is an obj, too???
+ {
+ error_log($GLOBALS['_xh']['isf_reason']);
+ return false;
+ }
+ switch ($GLOBALS['_xh']['rt'])
+ {
+ case 'methodresponse':
+ $v =& $GLOBALS['_xh']['value'];
+ if ($GLOBALS['_xh']['isf'] == 1)
+ {
+ $vc = $v->structmem('faultCode');
+ $vs = $v->structmem('faultString');
+ $r = new xmlrpcresp(0, $vc->scalarval(), $vs->scalarval());
+ }
+ else
+ {
+ $r = new xmlrpcresp($v);
+ }
+ return $r;
+ case 'methodcall':
+ $m = new xmlrpcmsg($GLOBALS['_xh']['method']);
+ for($i=0; $i < count($GLOBALS['_xh']['params']); $i++)
+ {
+ $m->addParam($GLOBALS['_xh']['params'][$i]);
+ }
+ return $m;
+ case 'value':
+ return $GLOBALS['_xh']['value'];
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * decode a string that is encoded w/ "chunked" transfer encoding
+ * as defined in rfc2068 par. 19.4.6
+ * code shamelessly stolen from nusoap library by Dietrich Ayala
+ *
+ * @param string $buffer the string to be decoded
+ * @return string
+ */
+ function decode_chunked($buffer)
+ {
+ // length := 0
+ $length = 0;
+ $new = '';
+
+ // read chunk-size, chunk-extension (if any) and crlf
+ // get the position of the linebreak
+ $chunkend = strpos($buffer,"\r\n") + 2;
+ $temp = substr($buffer,0,$chunkend);
+ $chunk_size = hexdec( trim($temp) );
+ $chunkstart = $chunkend;
+ while($chunk_size > 0)
+ {
+ $chunkend = strpos($buffer, "\r\n", $chunkstart + $chunk_size);
+
+ // just in case we got a broken connection
+ if($chunkend == false)
+ {
+ $chunk = substr($buffer,$chunkstart);
+ // append chunk-data to entity-body
+ $new .= $chunk;
+ $length += strlen($chunk);
+ break;
+ }
+
+ // read chunk-data and crlf
+ $chunk = substr($buffer,$chunkstart,$chunkend-$chunkstart);
+ // append chunk-data to entity-body
+ $new .= $chunk;
+ // length := length + chunk-size
+ $length += strlen($chunk);
+ // read chunk-size and crlf
+ $chunkstart = $chunkend + 2;
+
+ $chunkend = strpos($buffer,"\r\n",$chunkstart)+2;
+ if($chunkend == false)
+ {
+ break; //just in case we got a broken connection
+ }
+ $temp = substr($buffer,$chunkstart,$chunkend-$chunkstart);
+ $chunk_size = hexdec( trim($temp) );
+ $chunkstart = $chunkend;
+ }
+ return $new;
+ }
+
+ /**
+ * xml charset encoding guessing helper function.
+ * Tries to determine the charset encoding of an XML chunk received over HTTP.
+ * NB: according to the spec (RFC 3023), if text/xml content-type is received over HTTP without a content-type,
+ * we SHOULD assume it is strictly US-ASCII. But we try to be more tolerant of unconforming (legacy?) clients/servers,
+ * which will be most probably using UTF-8 anyway...
+ *
+ * @param string $httpheaders the http Content-type header
+ * @param string $xmlchunk xml content buffer
+ * @param string $encoding_prefs comma separated list of character encodings to be used as default (when mb extension is enabled)
+ *
+ * @todo explore usage of mb_http_input(): does it detect http headers + post data? if so, use it instead of hand-detection!!!
+ */
+ function guess_encoding($httpheader='', $xmlchunk='', $encoding_prefs=null)
+ {
+ // discussion: see http://www.yale.edu/pclt/encoding/
+ // 1 - test if encoding is specified in HTTP HEADERS
+
+ //Details:
+ // LWS: (\13\10)?( |\t)+
+ // token: (any char but excluded stuff)+
+ // quoted string: " (any char but double quotes and cointrol chars)* "
+ // header: Content-type = ...; charset=value(; ...)*
+ // where value is of type token, no LWS allowed between 'charset' and value
+ // Note: we do not check for invalid chars in VALUE:
+ // this had better be done using pure ereg as below
+ // Note 2: we might be removing whitespace/tabs that ought to be left in if
+ // the received charset is a quoted string. But nobody uses such charset names...
+
+ /// @todo this test will pass if ANY header has charset specification, not only Content-Type. Fix it?
+ $matches = array();
+ if(preg_match('/;\s*charset\s*=([^;]+)/i', $httpheader, $matches))
+ {
+ return strtoupper(trim($matches[1], " \t\""));
+ }
+
+ // 2 - scan the first bytes of the data for a UTF-16 (or other) BOM pattern
+ // (source: http://www.w3.org/TR/2000/REC-xml-20001006)
+ // NOTE: actually, according to the spec, even if we find the BOM and determine
+ // an encoding, we should check if there is an encoding specified
+ // in the xml declaration, and verify if they match.
+ /// @todo implement check as described above?
+ /// @todo implement check for first bytes of string even without a BOM? (It sure looks harder than for cases WITH a BOM)
+ if(preg_match('/^(\x00\x00\xFE\xFF|\xFF\xFE\x00\x00|\x00\x00\xFF\xFE|\xFE\xFF\x00\x00)/', $xmlchunk))
+ {
+ return 'UCS-4';
+ }
+ elseif(preg_match('/^(\xFE\xFF|\xFF\xFE)/', $xmlchunk))
+ {
+ return 'UTF-16';
+ }
+ elseif(preg_match('/^(\xEF\xBB\xBF)/', $xmlchunk))
+ {
+ return 'UTF-8';
+ }
+
+ // 3 - test if encoding is specified in the xml declaration
+ // Details:
+ // SPACE: (#x20 | #x9 | #xD | #xA)+ === [ \x9\xD\xA]+
+ // EQ: SPACE?=SPACE? === [ \x9\xD\xA]*=[ \x9\xD\xA]*
+ if (preg_match('/^<\?xml\s+version\s*=\s*'. "((?:\"[a-zA-Z0-9_.:-]+\")|(?:'[a-zA-Z0-9_.:-]+'))".
+ '\s+encoding\s*=\s*' . "((?:\"[A-Za-z][A-Za-z0-9._-]*\")|(?:'[A-Za-z][A-Za-z0-9._-]*'))/",
+ $xmlchunk, $matches))
+ {
+ return strtoupper(substr($matches[2], 1, -1));
+ }
+
+ // 4 - if mbstring is available, let it do the guesswork
+ // NB: we favour finding an encoding that is compatible with what we can process
+ if(extension_loaded('mbstring'))
+ {
+ if($encoding_prefs)
+ {
+ $enc = mb_detect_encoding($xmlchunk, $encoding_prefs);
+ }
+ else
+ {
+ $enc = mb_detect_encoding($xmlchunk);
+ }
+ // NB: mb_detect likes to call it ascii, xml parser likes to call it US_ASCII...
+ // IANA also likes better US-ASCII, so go with it
+ if($enc == 'ASCII')
+ {
+ $enc = 'US-'.$enc;
+ }
+ return $enc;
+ }
+ else
+ {
+ // no encoding specified: as per HTTP1.1 assume it is iso-8859-1?
+ // Both RFC 2616 (HTTP 1.1) and 1945 (HTTP 1.0) clearly state that for text/xxx content types
+ // this should be the standard. And we should be getting text/xml as request and response.
+ // BUT we have to be backward compatible with the lib, which always used UTF-8 as default...
+ return $GLOBALS['xmlrpc_defencoding'];
+ }
+ }
+
+ /**
+ * Checks if a given charset encoding is present in a list of encodings or
+ * if it is a valid subset of any encoding in the list
+ * @param string $encoding charset to be tested
+ * @param mixed $validlist comma separated list of valid charsets (or array of charsets)
+ */
+ function is_valid_charset($encoding, $validlist)
+ {
+ $charset_supersets = array(
+ 'US-ASCII' => array ('ISO-8859-1', 'ISO-8859-2', 'ISO-8859-3', 'ISO-8859-4',
+ 'ISO-8859-5', 'ISO-8859-6', 'ISO-8859-7', 'ISO-8859-8',
+ 'ISO-8859-9', 'ISO-8859-10', 'ISO-8859-11', 'ISO-8859-12',
+ 'ISO-8859-13', 'ISO-8859-14', 'ISO-8859-15', 'UTF-8',
+ 'EUC-JP', 'EUC-', 'EUC-KR', 'EUC-CN')
+ );
+ if (is_string($validlist))
+ $validlist = explode(',', $validlist);
+ if (@in_array(strtoupper($encoding), $validlist))
+ return true;
+ else
+ {
+ if (array_key_exists($encoding, $charset_supersets))
+ foreach ($validlist as $allowed)
+ if (in_array($allowed, $charset_supersets[$encoding]))
+ return true;
+ return false;
+ }
+ }
+
diff --git a/helper-php/DTLNSL_helper_scripts/helper/phpxmlrpclib/xmlrpc_wrappers.inc b/helper-php/DTLNSL_helper_scripts/helper/phpxmlrpclib/xmlrpc_wrappers.inc
new file mode 100644
index 0000000..58a07e7
--- /dev/null
+++ b/helper-php/DTLNSL_helper_scripts/helper/phpxmlrpclib/xmlrpc_wrappers.inc
@@ -0,0 +1,944 @@
+' . $funcname[1];
+ }
+ $exists = method_exists($funcname[0], $funcname[1]);
+ }
+ else
+ {
+ $plainfuncname = $funcname;
+ $exists = function_exists($funcname);
+ }
+
+ if(!$exists)
+ {
+ error_log('XML-RPC: function to be wrapped is not defined: '.$plainfuncname);
+ return false;
+ }
+ else
+ {
+ // determine name of new php function
+ if($newfuncname == '')
+ {
+ if(is_array($funcname))
+ {
+ if(is_string($funcname[0]))
+ $xmlrpcfuncname = "{$prefix}_".implode('_', $funcname);
+ else
+ $xmlrpcfuncname = "{$prefix}_".get_class($funcname[0]) . '_' . $funcname[1];
+ }
+ else
+ {
+ $xmlrpcfuncname = "{$prefix}_$funcname";
+ }
+ }
+ else
+ {
+ $xmlrpcfuncname = $newfuncname;
+ }
+ while($buildit && function_exists($xmlrpcfuncname))
+ {
+ $xmlrpcfuncname .= 'x';
+ }
+
+ // start to introspect PHP code
+ if(is_array($funcname))
+ {
+ $func = new ReflectionMethod($funcname[0], $funcname[1]);
+ if($func->isPrivate())
+ {
+ error_log('XML-RPC: method to be wrapped is private: '.$plainfuncname);
+ return false;
+ }
+ if($func->isProtected())
+ {
+ error_log('XML-RPC: method to be wrapped is protected: '.$plainfuncname);
+ return false;
+ }
+ if($func->isConstructor())
+ {
+ error_log('XML-RPC: method to be wrapped is the constructor: '.$plainfuncname);
+ return false;
+ }
+ if($func->isDestructor())
+ {
+ error_log('XML-RPC: method to be wrapped is the destructor: '.$plainfuncname);
+ return false;
+ }
+ if($func->isAbstract())
+ {
+ error_log('XML-RPC: method to be wrapped is abstract: '.$plainfuncname);
+ return false;
+ }
+ /// @todo add more checks for static vs. nonstatic?
+ }
+ else
+ {
+ $func = new ReflectionFunction($funcname);
+ }
+ if($func->isInternal())
+ {
+ // Note: from PHP 5.1.0 onward, we will possibly be able to use invokeargs
+ // instead of getparameters to fully reflect internal php functions ?
+ error_log('XML-RPC: function to be wrapped is internal: '.$plainfuncname);
+ return false;
+ }
+
+ // retrieve parameter names, types and description from javadoc comments
+
+ // function description
+ $desc = '';
+ // type of return val: by default 'any'
+ $returns = $GLOBALS['xmlrpcValue'];
+ // desc of return val
+ $returnsDocs = '';
+ // type + name of function parameters
+ $paramDocs = array();
+
+ $docs = $func->getDocComment();
+ if($docs != '')
+ {
+ $docs = explode("\n", $docs);
+ $i = 0;
+ foreach($docs as $doc)
+ {
+ $doc = trim($doc, " \r\t/*");
+ if(strlen($doc) && strpos($doc, '@') !== 0 && !$i)
+ {
+ if($desc)
+ {
+ $desc .= "\n";
+ }
+ $desc .= $doc;
+ }
+ elseif(strpos($doc, '@param') === 0)
+ {
+ // syntax: @param type [$name] desc
+ if(preg_match('/@param\s+(\S+)(\s+\$\S+)?\s+(.+)/', $doc, $matches))
+ {
+ if(strpos($matches[1], '|'))
+ {
+ //$paramDocs[$i]['type'] = explode('|', $matches[1]);
+ $paramDocs[$i]['type'] = 'mixed';
+ }
+ else
+ {
+ $paramDocs[$i]['type'] = $matches[1];
+ }
+ $paramDocs[$i]['name'] = trim($matches[2]);
+ $paramDocs[$i]['doc'] = $matches[3];
+ }
+ $i++;
+ }
+ elseif(strpos($doc, '@return') === 0)
+ {
+ // syntax: @return type desc
+ //$returns = preg_split('/\s+/', $doc);
+ if(preg_match('/@return\s+(\S+)\s+(.+)/', $doc, $matches))
+ {
+ $returns = php_2_xmlrpc_type($matches[1]);
+ if(isset($matches[2]))
+ {
+ $returnsDocs = $matches[2];
+ }
+ }
+ }
+ }
+ }
+
+ // execute introspection of actual function prototype
+ $params = array();
+ $i = 0;
+ foreach($func->getParameters() as $paramobj)
+ {
+ $params[$i] = array();
+ $params[$i]['name'] = '$'.$paramobj->getName();
+ $params[$i]['isoptional'] = $paramobj->isOptional();
+ $i++;
+ }
+
+
+ // start building of PHP code to be eval'd
+ $innercode = '';
+ $i = 0;
+ $parsvariations = array();
+ $pars = array();
+ $pnum = count($params);
+ foreach($params as $param)
+ {
+ if (isset($paramDocs[$i]['name']) && $paramDocs[$i]['name'] && strtolower($paramDocs[$i]['name']) != strtolower($param['name']))
+ {
+ // param name from phpdoc info does not match param definition!
+ $paramDocs[$i]['type'] = 'mixed';
+ }
+
+ if($param['isoptional'])
+ {
+ // this particular parameter is optional. save as valid previous list of parameters
+ $innercode .= "if (\$paramcount > $i) {\n";
+ $parsvariations[] = $pars;
+ }
+ $innercode .= "\$p$i = \$msg->getParam($i);\n";
+ if ($decode_php_objects)
+ {
+ $innercode .= "if (\$p{$i}->kindOf() == 'scalar') \$p$i = \$p{$i}->scalarval(); else \$p$i = php_{$prefix}_decode(\$p$i, array('decode_php_objs'));\n";
+ }
+ else
+ {
+ $innercode .= "if (\$p{$i}->kindOf() == 'scalar') \$p$i = \$p{$i}->scalarval(); else \$p$i = php_{$prefix}_decode(\$p$i);\n";
+ }
+
+ $pars[] = "\$p$i";
+ $i++;
+ if($param['isoptional'])
+ {
+ $innercode .= "}\n";
+ }
+ if($i == $pnum)
+ {
+ // last allowed parameters combination
+ $parsvariations[] = $pars;
+ }
+ }
+
+ $sigs = array();
+ $psigs = array();
+ if(count($parsvariations) == 0)
+ {
+ // only known good synopsis = no parameters
+ $parsvariations[] = array();
+ $minpars = 0;
+ }
+ else
+ {
+ $minpars = count($parsvariations[0]);
+ }
+
+ if($minpars)
+ {
+ // add to code the check for min params number
+ // NB: this check needs to be done BEFORE decoding param values
+ $innercode = "\$paramcount = \$msg->getNumParams();\n" .
+ "if (\$paramcount < $minpars) return new {$prefix}resp(0, {$GLOBALS['xmlrpcerr']['incorrect_params']}, '{$GLOBALS['xmlrpcstr']['incorrect_params']}');\n" . $innercode;
+ }
+ else
+ {
+ $innercode = "\$paramcount = \$msg->getNumParams();\n" . $innercode;
+ }
+
+ $innercode .= "\$np = false;\n";
+ // since there are no closures in php, if we are given an object instance,
+ // we store a pointer to it in a global var...
+ if ( is_array($funcname) && is_object($funcname[0]) )
+ {
+ $GLOBALS['xmlrpcWPFObjHolder'][$xmlrpcfuncname] =& $funcname[0];
+ $innercode .= "\$obj =& \$GLOBALS['xmlrpcWPFObjHolder']['$xmlrpcfuncname'];\n";
+ $realfuncname = '$obj->'.$funcname[1];
+ }
+ else
+ {
+ $realfuncname = $plainfuncname;
+ }
+ foreach($parsvariations as $pars)
+ {
+ $innercode .= "if (\$paramcount == " . count($pars) . ") \$retval = {$catch_warnings}$realfuncname(" . implode(',', $pars) . "); else\n";
+ // build a 'generic' signature (only use an appropriate return type)
+ $sig = array($returns);
+ $psig = array($returnsDocs);
+ for($i=0; $i < count($pars); $i++)
+ {
+ if (isset($paramDocs[$i]['type']))
+ {
+ $sig[] = php_2_xmlrpc_type($paramDocs[$i]['type']);
+ }
+ else
+ {
+ $sig[] = $GLOBALS['xmlrpcValue'];
+ }
+ $psig[] = isset($paramDocs[$i]['doc']) ? $paramDocs[$i]['doc'] : '';
+ }
+ $sigs[] = $sig;
+ $psigs[] = $psig;
+ }
+ $innercode .= "\$np = true;\n";
+ $innercode .= "if (\$np) return new {$prefix}resp(0, {$GLOBALS['xmlrpcerr']['incorrect_params']}, '{$GLOBALS['xmlrpcstr']['incorrect_params']}'); else {\n";
+ //$innercode .= "if (\$_xmlrpcs_error_occurred) return new xmlrpcresp(0, $GLOBALS['xmlrpcerr']user, \$_xmlrpcs_error_occurred); else\n";
+ $innercode .= "if (is_a(\$retval, '{$prefix}resp')) return \$retval; else\n";
+ if($returns == $GLOBALS['xmlrpcDateTime'] || $returns == $GLOBALS['xmlrpcBase64'])
+ {
+ $innercode .= "return new {$prefix}resp(new {$prefix}val(\$retval, '$returns'));";
+ }
+ else
+ {
+ if ($encode_php_objects)
+ $innercode .= "return new {$prefix}resp(php_{$prefix}_encode(\$retval, array('encode_php_objs')));\n";
+ else
+ $innercode .= "return new {$prefix}resp(php_{$prefix}_encode(\$retval));\n";
+ }
+ // shall we exclude functions returning by ref?
+ // if($func->returnsReference())
+ // return false;
+ $code = "function $xmlrpcfuncname(\$msg) {\n" . $innercode . "}\n}";
+ //print_r($code);
+ if ($buildit)
+ {
+ $allOK = 0;
+ eval($code.'$allOK=1;');
+ // alternative
+ //$xmlrpcfuncname = create_function('$m', $innercode);
+
+ if(!$allOK)
+ {
+ error_log('XML-RPC: could not create function '.$xmlrpcfuncname.' to wrap php function '.$plainfuncname);
+ return false;
+ }
+ }
+
+ /// @todo examine if $paramDocs matches $parsvariations and build array for
+ /// usage as method signature, plus put together a nice string for docs
+
+ $ret = array('function' => $xmlrpcfuncname, 'signature' => $sigs, 'docstring' => $desc, 'signature_docs' => $psigs, 'source' => $code);
+ return $ret;
+ }
+ }
+
+ /**
+ * Given a user-defined PHP class or php object, map its methods onto a list of
+ * PHP 'wrapper' functions that can be exposed as xmlrpc methods from an xmlrpc_server
+ * object and called from remote clients (as well as their corresponding signature info).
+ *
+ * @param mixed $classname the name of the class whose methods are to be exposed as xmlrpc methods, or an object instance of that class
+ * @param array $extra_options see the docs for wrap_php_method for more options
+ * string method_type 'static', 'nonstatic', 'all' and 'auto' (default); the latter will switch between static and non-static depending on wheter $classname is a class name or object instance
+ * @return array or false on failure
+ *
+ * @todo get_class_methods will return both static and non-static methods.
+ * we have to differentiate the action, depending on wheter we recived a class name or object
+ */
+ function wrap_php_class($classname, $extra_options=array())
+ {
+ $methodfilter = isset($extra_options['method_filter']) ? $extra_options['method_filter'] : '';
+ $methodtype = isset($extra_options['method_type']) ? $extra_options['method_type'] : 'auto';
+
+ if(version_compare(phpversion(), '5.0.3') == -1)
+ {
+ // up to php 5.0.3 some useful reflection methods were missing
+ error_log('XML-RPC: cannot not wrap php functions unless running php version bigger than 5.0.3');
+ return false;
+ }
+
+ $result = array();
+ $mlist = get_class_methods($classname);
+ foreach($mlist as $mname)
+ {
+ if ($methodfilter == '' || preg_match($methodfilter, $mname))
+ {
+ // echo $mlist."\n";
+ $func = new ReflectionMethod($classname, $mname);
+ if(!$func->isPrivate() && !$func->isProtected() && !$func->isConstructor() && !$func->isDestructor() && !$func->isAbstract())
+ {
+ if(($func->isStatic && ($methodtype == 'all' || $methodtype == 'static' || ($methodtype == 'auto' && is_string($classname)))) ||
+ (!$func->isStatic && ($methodtype == 'all' || $methodtype == 'nonstatic' || ($methodtype == 'auto' && is_object($classname)))))
+ {
+ $methodwrap = wrap_php_function(array($classname, $mname), '', $extra_options);
+ if ( $methodwrap )
+ {
+ $result[$methodwrap['function']] = $methodwrap['function'];
+ }
+ }
+ }
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * Given an xmlrpc client and a method name, register a php wrapper function
+ * that will call it and return results using native php types for both
+ * params and results. The generated php function will return an xmlrpcresp
+ * oject for failed xmlrpc calls
+ *
+ * Known limitations:
+ * - server must support system.methodsignature for the wanted xmlrpc method
+ * - for methods that expose many signatures, only one can be picked (we
+ * could in priciple check if signatures differ only by number of params
+ * and not by type, but it would be more complication than we can spare time)
+ * - nested xmlrpc params: the caller of the generated php function has to
+ * encode on its own the params passed to the php function if these are structs
+ * or arrays whose (sub)members include values of type datetime or base64
+ *
+ * Notes: the connection properties of the given client will be copied
+ * and reused for the connection used during the call to the generated
+ * php function.
+ * Calling the generated php function 'might' be slow: a new xmlrpc client
+ * is created on every invocation and an xmlrpc-connection opened+closed.
+ * An extra 'debug' param is appended to param list of xmlrpc method, useful
+ * for debugging purposes.
+ *
+ * @param xmlrpc_client $client an xmlrpc client set up correctly to communicate with target server
+ * @param string $methodname the xmlrpc method to be mapped to a php function
+ * @param array $extra_options array of options that specify conversion details. valid ptions include
+ * integer signum the index of the method signature to use in mapping (if method exposes many sigs)
+ * integer timeout timeout (in secs) to be used when executing function/calling remote method
+ * string protocol 'http' (default), 'http11' or 'https'
+ * string new_function_name the name of php function to create. If unsepcified, lib will pick an appropriate name
+ * string return_source if true return php code w. function definition instead fo function name
+ * bool encode_php_objs let php objects be sent to server using the 'improved' xmlrpc notation, so server can deserialize them as php objects
+ * bool decode_php_objs --- WARNING !!! possible security hazard. only use it with trusted servers ---
+ * mixed return_on_fault a php value to be returned when the xmlrpc call fails/returns a fault response (by default the xmlrpcresp object is returned in this case). If a string is used, '%faultCode%' and '%faultString%' tokens will be substituted with actual error values
+ * bool debug set it to 1 or 2 to see debug results of querying server for method synopsis
+ * @return string the name of the generated php function (or false) - OR AN ARRAY...
+ */
+ function wrap_xmlrpc_method($client, $methodname, $extra_options=0, $timeout=0, $protocol='', $newfuncname='')
+ {
+ // mind numbing: let caller use sane calling convention (as per javadoc, 3 params),
+ // OR the 2.0 calling convention (no options) - we really love backward compat, don't we?
+ if (!is_array($extra_options))
+ {
+ $signum = $extra_options;
+ $extra_options = array();
+ }
+ else
+ {
+ $signum = isset($extra_options['signum']) ? (int)$extra_options['signum'] : 0;
+ $timeout = isset($extra_options['timeout']) ? (int)$extra_options['timeout'] : 0;
+ $protocol = isset($extra_options['protocol']) ? $extra_options['protocol'] : '';
+ $newfuncname = isset($extra_options['new_function_name']) ? $extra_options['new_function_name'] : '';
+ }
+ //$encode_php_objects = in_array('encode_php_objects', $extra_options);
+ //$verbatim_client_copy = in_array('simple_client_copy', $extra_options) ? 1 :
+ // in_array('build_class_code', $extra_options) ? 2 : 0;
+
+ $encode_php_objects = isset($extra_options['encode_php_objs']) ? (bool)$extra_options['encode_php_objs'] : false;
+ $decode_php_objects = isset($extra_options['decode_php_objs']) ? (bool)$extra_options['decode_php_objs'] : false;
+ $simple_client_copy = isset($extra_options['simple_client_copy']) ? (int)($extra_options['simple_client_copy']) : 0;
+ $buildit = isset($extra_options['return_source']) ? !($extra_options['return_source']) : true;
+ $prefix = isset($extra_options['prefix']) ? $extra_options['prefix'] : 'xmlrpc';
+ if (isset($extra_options['return_on_fault']))
+ {
+ $decode_fault = true;
+ $fault_response = $extra_options['return_on_fault'];
+ }
+ else
+ {
+ $decode_fault = false;
+ $fault_response = '';
+ }
+ $debug = isset($extra_options['debug']) ? ($extra_options['debug']) : 0;
+
+ $msgclass = $prefix.'msg';
+ $valclass = $prefix.'val';
+ $decodefunc = 'php_'.$prefix.'_decode';
+
+ $msg = new $msgclass('system.methodSignature');
+ $msg->addparam(new $valclass($methodname));
+ $client->setDebug($debug);
+ $response =& $client->send($msg, $timeout, $protocol);
+ if($response->faultCode())
+ {
+ error_log('XML-RPC: could not retrieve method signature from remote server for method '.$methodname);
+ return false;
+ }
+ else
+ {
+ $msig = $response->value();
+ if ($client->return_type != 'phpvals')
+ {
+ $msig = $decodefunc($msig);
+ }
+ if(!is_array($msig) || count($msig) <= $signum)
+ {
+ error_log('XML-RPC: could not retrieve method signature nr.'.$signum.' from remote server for method '.$methodname);
+ return false;
+ }
+ else
+ {
+ // pick a suitable name for the new function, avoiding collisions
+ if($newfuncname != '')
+ {
+ $xmlrpcfuncname = $newfuncname;
+ }
+ else
+ {
+ // take care to insure that methodname is translated to valid
+ // php function name
+ $xmlrpcfuncname = $prefix.'_'.preg_replace(array('/\./', '/[^a-zA-Z0-9_\x7f-\xff]/'),
+ array('_', ''), $methodname);
+ }
+ while($buildit && function_exists($xmlrpcfuncname))
+ {
+ $xmlrpcfuncname .= 'x';
+ }
+
+ $msig = $msig[$signum];
+ $mdesc = '';
+ // if in 'offline' mode, get method description too.
+ // in online mode, favour speed of operation
+ if(!$buildit)
+ {
+ $msg = new $msgclass('system.methodHelp');
+ $msg->addparam(new $valclass($methodname));
+ $response =& $client->send($msg, $timeout, $protocol);
+ if (!$response->faultCode())
+ {
+ $mdesc = $response->value();
+ if ($client->return_type != 'phpvals')
+ {
+ $mdesc = $mdesc->scalarval();
+ }
+ }
+ }
+
+ $results = build_remote_method_wrapper_code($client, $methodname,
+ $xmlrpcfuncname, $msig, $mdesc, $timeout, $protocol, $simple_client_copy,
+ $prefix, $decode_php_objects, $encode_php_objects, $decode_fault,
+ $fault_response);
+
+ //print_r($code);
+ if ($buildit)
+ {
+ $allOK = 0;
+ eval($results['source'].'$allOK=1;');
+ // alternative
+ //$xmlrpcfuncname = create_function('$m', $innercode);
+ if($allOK)
+ {
+ return $xmlrpcfuncname;
+ }
+ else
+ {
+ error_log('XML-RPC: could not create function '.$xmlrpcfuncname.' to wrap remote method '.$methodname);
+ return false;
+ }
+ }
+ else
+ {
+ $results['function'] = $xmlrpcfuncname;
+ return $results;
+ }
+ }
+ }
+ }
+
+ /**
+ * Similar to wrap_xmlrpc_method, but will generate a php class that wraps
+ * all xmlrpc methods exposed by the remote server as own methods.
+ * For more details see wrap_xmlrpc_method.
+ * @param xmlrpc_client $client the client obj all set to query the desired server
+ * @param array $extra_options list of options for wrapped code
+ * @return mixed false on error, the name of the created class if all ok or an array with code, class name and comments (if the appropriatevoption is set in extra_options)
+ */
+ function wrap_xmlrpc_server($client, $extra_options=array())
+ {
+ $methodfilter = isset($extra_options['method_filter']) ? $extra_options['method_filter'] : '';
+ //$signum = isset($extra_options['signum']) ? (int)$extra_options['signum'] : 0;
+ $timeout = isset($extra_options['timeout']) ? (int)$extra_options['timeout'] : 0;
+ $protocol = isset($extra_options['protocol']) ? $extra_options['protocol'] : '';
+ $newclassname = isset($extra_options['new_class_name']) ? $extra_options['new_class_name'] : '';
+ $encode_php_objects = isset($extra_options['encode_php_objs']) ? (bool)$extra_options['encode_php_objs'] : false;
+ $decode_php_objects = isset($extra_options['decode_php_objs']) ? (bool)$extra_options['decode_php_objs'] : false;
+ $verbatim_client_copy = isset($extra_options['simple_client_copy']) ? !($extra_options['simple_client_copy']) : true;
+ $buildit = isset($extra_options['return_source']) ? !($extra_options['return_source']) : true;
+ $prefix = isset($extra_options['prefix']) ? $extra_options['prefix'] : 'xmlrpc';
+
+ $msgclass = $prefix.'msg';
+ //$valclass = $prefix.'val';
+ $decodefunc = 'php_'.$prefix.'_decode';
+
+ $msg = new $msgclass('system.listMethods');
+ $response =& $client->send($msg, $timeout, $protocol);
+ if($response->faultCode())
+ {
+ error_log('XML-RPC: could not retrieve method list from remote server');
+ return false;
+ }
+ else
+ {
+ $mlist = $response->value();
+ if ($client->return_type != 'phpvals')
+ {
+ $mlist = $decodefunc($mlist);
+ }
+ if(!is_array($mlist) || !count($mlist))
+ {
+ error_log('XML-RPC: could not retrieve meaningful method list from remote server');
+ return false;
+ }
+ else
+ {
+ // pick a suitable name for the new function, avoiding collisions
+ if($newclassname != '')
+ {
+ $xmlrpcclassname = $newclassname;
+ }
+ else
+ {
+ $xmlrpcclassname = $prefix.'_'.preg_replace(array('/\./', '/[^a-zA-Z0-9_\x7f-\xff]/'),
+ array('_', ''), $client->server).'_client';
+ }
+ while($buildit && class_exists($xmlrpcclassname))
+ {
+ $xmlrpcclassname .= 'x';
+ }
+
+ /// @todo add function setdebug() to new class, to enable/disable debugging
+ $source = "class $xmlrpcclassname\n{\nvar \$client;\n\n";
+ $source .= "function $xmlrpcclassname()\n{\n";
+ $source .= build_client_wrapper_code($client, $verbatim_client_copy, $prefix);
+ $source .= "\$this->client =& \$client;\n}\n\n";
+ $opts = array('simple_client_copy' => 2, 'return_source' => true,
+ 'timeout' => $timeout, 'protocol' => $protocol,
+ 'encode_php_objs' => $encode_php_objects, 'prefix' => $prefix,
+ 'decode_php_objs' => $decode_php_objects
+ );
+ /// @todo build javadoc for class definition, too
+ foreach($mlist as $mname)
+ {
+ if ($methodfilter == '' || preg_match($methodfilter, $mname))
+ {
+ $opts['new_function_name'] = preg_replace(array('/\./', '/[^a-zA-Z0-9_\x7f-\xff]/'),
+ array('_', ''), $mname);
+ $methodwrap = wrap_xmlrpc_method($client, $mname, $opts);
+ if ($methodwrap)
+ {
+ if (!$buildit)
+ {
+ $source .= $methodwrap['docstring'];
+ }
+ $source .= $methodwrap['source']."\n";
+ }
+ else
+ {
+ error_log('XML-RPC: will not create class method to wrap remote method '.$mname);
+ }
+ }
+ }
+ $source .= "}\n";
+ if ($buildit)
+ {
+ $allOK = 0;
+ eval($source.'$allOK=1;');
+ // alternative
+ //$xmlrpcfuncname = create_function('$m', $innercode);
+ if($allOK)
+ {
+ return $xmlrpcclassname;
+ }
+ else
+ {
+ error_log('XML-RPC: could not create class '.$xmlrpcclassname.' to wrap remote server '.$client->server);
+ return false;
+ }
+ }
+ else
+ {
+ return array('class' => $xmlrpcclassname, 'code' => $source, 'docstring' => '');
+ }
+ }
+ }
+ }
+
+ /**
+ * Given the necessary info, build php code that creates a new function to
+ * invoke a remote xmlrpc method.
+ * Take care that no full checking of input parameters is done to ensure that
+ * valid php code is emitted.
+ * Note: real spaghetti code follows...
+ * @access private
+ */
+ function build_remote_method_wrapper_code($client, $methodname, $xmlrpcfuncname,
+ $msig, $mdesc='', $timeout=0, $protocol='', $client_copy_mode=0, $prefix='xmlrpc',
+ $decode_php_objects=false, $encode_php_objects=false, $decode_fault=false,
+ $fault_response='')
+ {
+ $code = "function $xmlrpcfuncname (";
+ if ($client_copy_mode < 2)
+ {
+ // client copy mode 0 or 1 == partial / full client copy in emitted code
+ $innercode = build_client_wrapper_code($client, $client_copy_mode, $prefix);
+ $innercode .= "\$client->setDebug(\$debug);\n";
+ $this_ = '';
+ }
+ else
+ {
+ // client copy mode 2 == no client copy in emitted code
+ $innercode = '';
+ $this_ = 'this->';
+ }
+ $innercode .= "\$msg = new {$prefix}msg('$methodname');\n";
+
+ if ($mdesc != '')
+ {
+ // take care that PHP comment is not terminated unwillingly by method description
+ $mdesc = "/**\n* ".str_replace('*/', '* /', $mdesc)."\n";
+ }
+ else
+ {
+ $mdesc = "/**\nFunction $xmlrpcfuncname\n";
+ }
+
+ // param parsing
+ $plist = array();
+ $pcount = count($msig);
+ for($i = 1; $i < $pcount; $i++)
+ {
+ $plist[] = "\$p$i";
+ $ptype = $msig[$i];
+ if($ptype == 'i4' || $ptype == 'int' || $ptype == 'boolean' || $ptype == 'double' ||
+ $ptype == 'string' || $ptype == 'dateTime.iso8601' || $ptype == 'base64' || $ptype == 'null')
+ {
+ // only build directly xmlrpcvals when type is known and scalar
+ $innercode .= "\$p$i = new {$prefix}val(\$p$i, '$ptype');\n";
+ }
+ else
+ {
+ if ($encode_php_objects)
+ {
+ $innercode .= "\$p$i =& php_{$prefix}_encode(\$p$i, array('encode_php_objs'));\n";
+ }
+ else
+ {
+ $innercode .= "\$p$i =& php_{$prefix}_encode(\$p$i);\n";
+ }
+ }
+ $innercode .= "\$msg->addparam(\$p$i);\n";
+ $mdesc .= '* @param '.xmlrpc_2_php_type($ptype)." \$p$i\n";
+ }
+ if ($client_copy_mode < 2)
+ {
+ $plist[] = '$debug=0';
+ $mdesc .= "* @param int \$debug when 1 (or 2) will enable debugging of the underlying {$prefix} call (defaults to 0)\n";
+ }
+ $plist = implode(', ', $plist);
+ $mdesc .= '* @return '.xmlrpc_2_php_type($msig[0])." (or an {$prefix}resp obj instance if call fails)\n*/\n";
+
+ $innercode .= "\$res =& \${$this_}client->send(\$msg, $timeout, '$protocol');\n";
+ if ($decode_fault)
+ {
+ if (is_string($fault_response) && ((strpos($fault_response, '%faultCode%') !== false) || (strpos($fault_response, '%faultString%') !== false)))
+ {
+ $respcode = "str_replace(array('%faultCode%', '%faultString%'), array(\$res->faultCode(), \$res->faultString()), '".str_replace("'", "''", $fault_response)."')";
+ }
+ else
+ {
+ $respcode = var_export($fault_response, true);
+ }
+ }
+ else
+ {
+ $respcode = '$res';
+ }
+ if ($decode_php_objects)
+ {
+ $innercode .= "if (\$res->faultcode()) return $respcode; else return php_{$prefix}_decode(\$res->value(), array('decode_php_objs'));";
+ }
+ else
+ {
+ $innercode .= "if (\$res->faultcode()) return $respcode; else return php_{$prefix}_decode(\$res->value());";
+ }
+
+ $code = $code . $plist. ") {\n" . $innercode . "\n}\n";
+
+ return array('source' => $code, 'docstring' => $mdesc);
+ }
+
+ /**
+ * Given necessary info, generate php code that will rebuild a client object
+ * Take care that no full checking of input parameters is done to ensure that
+ * valid php code is emitted.
+ * @access private
+ */
+ function build_client_wrapper_code($client, $verbatim_client_copy, $prefix='xmlrpc')
+ {
+ $code = "\$client = new {$prefix}_client('".str_replace("'", "\'", $client->path).
+ "', '" . str_replace("'", "\'", $client->server) . "', $client->port);\n";
+
+ // copy all client fields to the client that will be generated runtime
+ // (this provides for future expansion or subclassing of client obj)
+ if ($verbatim_client_copy)
+ {
+ foreach($client as $fld => $val)
+ {
+ if($fld != 'debug' && $fld != 'return_type')
+ {
+ $val = var_export($val, true);
+ $code .= "\$client->$fld = $val;\n";
+ }
+ }
+ }
+ // only make sure that client always returns the correct data type
+ $code .= "\$client->return_type = '{$prefix}vals';\n";
+ //$code .= "\$client->setDebug(\$debug);\n";
+ return $code;
+ }
+?>
diff --git a/helper-php/DTLNSL_helper_scripts/helper/phpxmlrpclib/xmlrpcs.inc b/helper-php/DTLNSL_helper_scripts/helper/phpxmlrpclib/xmlrpcs.inc
new file mode 100644
index 0000000..6ac3764
--- /dev/null
+++ b/helper-php/DTLNSL_helper_scripts/helper/phpxmlrpclib/xmlrpcs.inc
@@ -0,0 +1,1206 @@
+
+// $Id: xmlrpcs.inc,v 1.71 2008/10/29 23:41:28 ggiunta Exp $
+
+// Copyright (c) 1999,2000,2002 Edd Dumbill.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+//
+// * Neither the name of the "XML-RPC for PHP" nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+// OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ // XML RPC Server class
+ // requires: xmlrpc.inc
+
+ $GLOBALS['xmlrpcs_capabilities'] = array(
+ // xmlrpc spec: always supported
+ 'xmlrpc' => new xmlrpcval(array(
+ 'specUrl' => new xmlrpcval('http://www.xmlrpc.com/spec', 'string'),
+ 'specVersion' => new xmlrpcval(1, 'int')
+ ), 'struct'),
+ // if we support system.xxx functions, we always support multicall, too...
+ // Note that, as of 2006/09/17, the following URL does not respond anymore
+ 'system.multicall' => new xmlrpcval(array(
+ 'specUrl' => new xmlrpcval('http://www.xmlrpc.com/discuss/msgReader$1208', 'string'),
+ 'specVersion' => new xmlrpcval(1, 'int')
+ ), 'struct'),
+ // introspection: version 2! we support 'mixed', too
+ 'introspection' => new xmlrpcval(array(
+ 'specUrl' => new xmlrpcval('http://phpxmlrpc.sourceforge.net/doc-2/ch10.html', 'string'),
+ 'specVersion' => new xmlrpcval(2, 'int')
+ ), 'struct')
+ );
+
+ /* Functions that implement system.XXX methods of xmlrpc servers */
+ $_xmlrpcs_getCapabilities_sig=array(array($GLOBALS['xmlrpcStruct']));
+ $_xmlrpcs_getCapabilities_doc='This method lists all the capabilites that the XML-RPC server has: the (more or less standard) extensions to the xmlrpc spec that it adheres to';
+ $_xmlrpcs_getCapabilities_sdoc=array(array('list of capabilities, described as structs with a version number and url for the spec'));
+ function _xmlrpcs_getCapabilities($server, $m=null)
+ {
+ $outAr = $GLOBALS['xmlrpcs_capabilities'];
+ // NIL extension
+ if ($GLOBALS['xmlrpc_null_extension']) {
+ $outAr['nil'] = new xmlrpcval(array(
+ 'specUrl' => new xmlrpcval('http://www.ontosys.com/xml-rpc/extensions.php', 'string'),
+ 'specVersion' => new xmlrpcval(1, 'int')
+ ), 'struct');
+ }
+ return new xmlrpcresp(new xmlrpcval($outAr, 'struct'));
+ }
+
+ // listMethods: signature was either a string, or nothing.
+ // The useless string variant has been removed
+ $_xmlrpcs_listMethods_sig=array(array($GLOBALS['xmlrpcArray']));
+ $_xmlrpcs_listMethods_doc='This method lists all the methods that the XML-RPC server knows how to dispatch';
+ $_xmlrpcs_listMethods_sdoc=array(array('list of method names'));
+ function _xmlrpcs_listMethods($server, $m=null) // if called in plain php values mode, second param is missing
+ {
+
+ $outAr=array();
+ foreach($server->dmap as $key => $val)
+ {
+ $outAr[] = new xmlrpcval($key, 'string');
+ }
+ if($server->allow_system_funcs)
+ {
+ foreach($GLOBALS['_xmlrpcs_dmap'] as $key => $val)
+ {
+ $outAr[] = new xmlrpcval($key, 'string');
+ }
+ }
+ return new xmlrpcresp(new xmlrpcval($outAr, 'array'));
+ }
+
+ $_xmlrpcs_methodSignature_sig=array(array($GLOBALS['xmlrpcArray'], $GLOBALS['xmlrpcString']));
+ $_xmlrpcs_methodSignature_doc='Returns an array of known signatures (an array of arrays) for the method name passed. If no signatures are known, returns a none-array (test for type != array to detect missing signature)';
+ $_xmlrpcs_methodSignature_sdoc=array(array('list of known signatures, each sig being an array of xmlrpc type names', 'name of method to be described'));
+ function _xmlrpcs_methodSignature($server, $m)
+ {
+ // let accept as parameter both an xmlrpcval or string
+ if (is_object($m))
+ {
+ $methName=$m->getParam(0);
+ $methName=$methName->scalarval();
+ }
+ else
+ {
+ $methName=$m;
+ }
+ if(strpos($methName, "system.") === 0)
+ {
+ $dmap=$GLOBALS['_xmlrpcs_dmap']; $sysCall=1;
+ }
+ else
+ {
+ $dmap=$server->dmap; $sysCall=0;
+ }
+ if(isset($dmap[$methName]))
+ {
+ if(isset($dmap[$methName]['signature']))
+ {
+ $sigs=array();
+ foreach($dmap[$methName]['signature'] as $inSig)
+ {
+ $cursig=array();
+ foreach($inSig as $sig)
+ {
+ $cursig[] = new xmlrpcval($sig, 'string');
+ }
+ $sigs[] = new xmlrpcval($cursig, 'array');
+ }
+ $r = new xmlrpcresp(new xmlrpcval($sigs, 'array'));
+ }
+ else
+ {
+ // NB: according to the official docs, we should be returning a
+ // "none-array" here, which means not-an-array
+ $r = new xmlrpcresp(new xmlrpcval('undef', 'string'));
+ }
+ }
+ else
+ {
+ $r = new xmlrpcresp(0,$GLOBALS['xmlrpcerr']['introspect_unknown'], $GLOBALS['xmlrpcstr']['introspect_unknown']);
+ }
+ return $r;
+ }
+
+ $_xmlrpcs_methodHelp_sig=array(array($GLOBALS['xmlrpcString'], $GLOBALS['xmlrpcString']));
+ $_xmlrpcs_methodHelp_doc='Returns help text if defined for the method passed, otherwise returns an empty string';
+ $_xmlrpcs_methodHelp_sdoc=array(array('method description', 'name of the method to be described'));
+ function _xmlrpcs_methodHelp($server, $m)
+ {
+ // let accept as parameter both an xmlrpcval or string
+ if (is_object($m))
+ {
+ $methName=$m->getParam(0);
+ $methName=$methName->scalarval();
+ }
+ else
+ {
+ $methName=$m;
+ }
+ if(strpos($methName, "system.") === 0)
+ {
+ $dmap=$GLOBALS['_xmlrpcs_dmap']; $sysCall=1;
+ }
+ else
+ {
+ $dmap=$server->dmap; $sysCall=0;
+ }
+ if(isset($dmap[$methName]))
+ {
+ if(isset($dmap[$methName]['docstring']))
+ {
+ $r = new xmlrpcresp(new xmlrpcval($dmap[$methName]['docstring']), 'string');
+ }
+ else
+ {
+ $r = new xmlrpcresp(new xmlrpcval('', 'string'));
+ }
+ }
+ else
+ {
+ $r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['introspect_unknown'], $GLOBALS['xmlrpcstr']['introspect_unknown']);
+ }
+ return $r;
+ }
+
+ $_xmlrpcs_multicall_sig = array(array($GLOBALS['xmlrpcArray'], $GLOBALS['xmlrpcArray']));
+ $_xmlrpcs_multicall_doc = 'Boxcar multiple RPC calls in one request. See http://www.xmlrpc.com/discuss/msgReader$1208 for details';
+ $_xmlrpcs_multicall_sdoc = array(array('list of response structs, where each struct has the usual members', 'list of calls, with each call being represented as a struct, with members "methodname" and "params"'));
+ function _xmlrpcs_multicall_error($err)
+ {
+ if(is_string($err))
+ {
+ $str = $GLOBALS['xmlrpcstr']["multicall_${err}"];
+ $code = $GLOBALS['xmlrpcerr']["multicall_${err}"];
+ }
+ else
+ {
+ $code = $err->faultCode();
+ $str = $err->faultString();
+ }
+ $struct = array();
+ $struct['faultCode'] = new xmlrpcval($code, 'int');
+ $struct['faultString'] = new xmlrpcval($str, 'string');
+ return new xmlrpcval($struct, 'struct');
+ }
+
+ function _xmlrpcs_multicall_do_call($server, $call)
+ {
+ if($call->kindOf() != 'struct')
+ {
+ return _xmlrpcs_multicall_error('notstruct');
+ }
+ $methName = @$call->structmem('methodName');
+ if(!$methName)
+ {
+ return _xmlrpcs_multicall_error('nomethod');
+ }
+ if($methName->kindOf() != 'scalar' || $methName->scalartyp() != 'string')
+ {
+ return _xmlrpcs_multicall_error('notstring');
+ }
+ if($methName->scalarval() == 'system.multicall')
+ {
+ return _xmlrpcs_multicall_error('recursion');
+ }
+
+ $params = @$call->structmem('params');
+ if(!$params)
+ {
+ return _xmlrpcs_multicall_error('noparams');
+ }
+ if($params->kindOf() != 'array')
+ {
+ return _xmlrpcs_multicall_error('notarray');
+ }
+ $numParams = $params->arraysize();
+
+ $msg = new xmlrpcmsg($methName->scalarval());
+ for($i = 0; $i < $numParams; $i++)
+ {
+ if(!$msg->addParam($params->arraymem($i)))
+ {
+ $i++;
+ return _xmlrpcs_multicall_error(new xmlrpcresp(0,
+ $GLOBALS['xmlrpcerr']['incorrect_params'],
+ $GLOBALS['xmlrpcstr']['incorrect_params'] . ": probable xml error in param " . $i));
+ }
+ }
+
+ $result = $server->execute($msg);
+
+ if($result->faultCode() != 0)
+ {
+ return _xmlrpcs_multicall_error($result); // Method returned fault.
+ }
+
+ return new xmlrpcval(array($result->value()), 'array');
+ }
+
+ function _xmlrpcs_multicall_do_call_phpvals($server, $call)
+ {
+ if(!is_array($call))
+ {
+ return _xmlrpcs_multicall_error('notstruct');
+ }
+ if(!array_key_exists('methodName', $call))
+ {
+ return _xmlrpcs_multicall_error('nomethod');
+ }
+ if (!is_string($call['methodName']))
+ {
+ return _xmlrpcs_multicall_error('notstring');
+ }
+ if($call['methodName'] == 'system.multicall')
+ {
+ return _xmlrpcs_multicall_error('recursion');
+ }
+ if(!array_key_exists('params', $call))
+ {
+ return _xmlrpcs_multicall_error('noparams');
+ }
+ if(!is_array($call['params']))
+ {
+ return _xmlrpcs_multicall_error('notarray');
+ }
+
+ // this is a real dirty and simplistic hack, since we might have received a
+ // base64 or datetime values, but they will be listed as strings here...
+ $numParams = count($call['params']);
+ $pt = array();
+ foreach($call['params'] as $val)
+ $pt[] = php_2_xmlrpc_type(gettype($val));
+
+ $result = $server->execute($call['methodName'], $call['params'], $pt);
+
+ if($result->faultCode() != 0)
+ {
+ return _xmlrpcs_multicall_error($result); // Method returned fault.
+ }
+
+ return new xmlrpcval(array($result->value()), 'array');
+ }
+
+ function _xmlrpcs_multicall($server, $m)
+ {
+ $result = array();
+ // let accept a plain list of php parameters, beside a single xmlrpc msg object
+ if (is_object($m))
+ {
+ $calls = $m->getParam(0);
+ $numCalls = $calls->arraysize();
+ for($i = 0; $i < $numCalls; $i++)
+ {
+ $call = $calls->arraymem($i);
+ $result[$i] = _xmlrpcs_multicall_do_call($server, $call);
+ }
+ }
+ else
+ {
+ $numCalls=count($m);
+ for($i = 0; $i < $numCalls; $i++)
+ {
+ $result[$i] = _xmlrpcs_multicall_do_call_phpvals($server, $m[$i]);
+ }
+ }
+
+ return new xmlrpcresp(new xmlrpcval($result, 'array'));
+ }
+
+ $GLOBALS['_xmlrpcs_dmap']=array(
+ 'system.listMethods' => array(
+ 'function' => '_xmlrpcs_listMethods',
+ 'signature' => $_xmlrpcs_listMethods_sig,
+ 'docstring' => $_xmlrpcs_listMethods_doc,
+ 'signature_docs' => $_xmlrpcs_listMethods_sdoc),
+ 'system.methodHelp' => array(
+ 'function' => '_xmlrpcs_methodHelp',
+ 'signature' => $_xmlrpcs_methodHelp_sig,
+ 'docstring' => $_xmlrpcs_methodHelp_doc,
+ 'signature_docs' => $_xmlrpcs_methodHelp_sdoc),
+ 'system.methodSignature' => array(
+ 'function' => '_xmlrpcs_methodSignature',
+ 'signature' => $_xmlrpcs_methodSignature_sig,
+ 'docstring' => $_xmlrpcs_methodSignature_doc,
+ 'signature_docs' => $_xmlrpcs_methodSignature_sdoc),
+ 'system.multicall' => array(
+ 'function' => '_xmlrpcs_multicall',
+ 'signature' => $_xmlrpcs_multicall_sig,
+ 'docstring' => $_xmlrpcs_multicall_doc,
+ 'signature_docs' => $_xmlrpcs_multicall_sdoc),
+ 'system.getCapabilities' => array(
+ 'function' => '_xmlrpcs_getCapabilities',
+ 'signature' => $_xmlrpcs_getCapabilities_sig,
+ 'docstring' => $_xmlrpcs_getCapabilities_doc,
+ 'signature_docs' => $_xmlrpcs_getCapabilities_sdoc)
+ );
+
+ $GLOBALS['_xmlrpcs_occurred_errors'] = '';
+ $GLOBALS['_xmlrpcs_prev_ehandler'] = '';
+ /**
+ * Error handler used to track errors that occur during server-side execution of PHP code.
+ * This allows to report back to the client whether an internal error has occurred or not
+ * using an xmlrpc response object, instead of letting the client deal with the html junk
+ * that a PHP execution error on the server generally entails.
+ *
+ * NB: in fact a user defined error handler can only handle WARNING, NOTICE and USER_* errors.
+ *
+ */
+ function _xmlrpcs_errorHandler($errcode, $errstring, $filename=null, $lineno=null, $context=null)
+ {
+ // obey the @ protocol
+ if (error_reporting() == 0)
+ return;
+
+ //if($errcode != E_NOTICE && $errcode != E_WARNING && $errcode != E_USER_NOTICE && $errcode != E_USER_WARNING)
+ if($errcode != 2048) // do not use E_STRICT by name, since on PHP 4 it will not be defined
+ {
+ $GLOBALS['_xmlrpcs_occurred_errors'] = $GLOBALS['_xmlrpcs_occurred_errors'] . $errstring . "\n";
+ }
+ // Try to avoid as much as possible disruption to the previous error handling
+ // mechanism in place
+ if($GLOBALS['_xmlrpcs_prev_ehandler'] == '')
+ {
+ // The previous error handler was the default: all we should do is log error
+ // to the default error log (if level high enough)
+ if(ini_get('log_errors') && (intval(ini_get('error_reporting')) & $errcode))
+ {
+ error_log($errstring);
+ }
+ }
+ else
+ {
+ // Pass control on to previous error handler, trying to avoid loops...
+ if($GLOBALS['_xmlrpcs_prev_ehandler'] != '_xmlrpcs_errorHandler')
+ {
+ // NB: this code will NOT work on php < 4.0.2: only 2 params were used for error handlers
+ if(is_array($GLOBALS['_xmlrpcs_prev_ehandler']))
+ {
+ // the following works both with static class methods and plain object methods as error handler
+ call_user_func_array($GLOBALS['_xmlrpcs_prev_ehandler'], array($errcode, $errstring, $filename, $lineno, $context));
+ }
+ else
+ {
+ $GLOBALS['_xmlrpcs_prev_ehandler']($errcode, $errstring, $filename, $lineno, $context);
+ }
+ }
+ }
+ }
+
+ $GLOBALS['_xmlrpc_debuginfo']='';
+
+ /**
+ * Add a string to the debug info that can be later seralized by the server
+ * as part of the response message.
+ * Note that for best compatbility, the debug string should be encoded using
+ * the $GLOBALS['xmlrpc_internalencoding'] character set.
+ * @param string $m
+ * @access public
+ */
+ function xmlrpc_debugmsg($m)
+ {
+ $GLOBALS['_xmlrpc_debuginfo'] .= $m . "\n";
+ }
+
+ class xmlrpc_server
+ {
+ /// array defining php functions exposed as xmlrpc methods by this server
+ var $dmap=array();
+ /**
+ * Defines how functions in dmap will be invokde: either using an xmlrpc msg object
+ * or plain php values.
+ * valid strings are 'xmlrpcvals', 'phpvals' or 'epivals'
+ */
+ var $functions_parameters_type='xmlrpcvals';
+ /// controls wether the server is going to echo debugging messages back to the client as comments in response body. valid values: 0,1,2,3
+ var $debug = 1;
+ /**
+ * When set to true, it will enable HTTP compression of the response, in case
+ * the client has declared its support for compression in the request.
+ */
+ var $compress_response = false;
+ /**
+ * List of http compression methods accepted by the server for requests.
+ * NB: PHP supports deflate, gzip compressions out of the box if compiled w. zlib
+ */
+ var $accepted_compression = array();
+ /// shall we serve calls to system.* methods?
+ var $allow_system_funcs = true;
+ /// list of charset encodings natively accepted for requests
+ var $accepted_charset_encodings = array();
+ /**
+ * charset encoding to be used for response.
+ * NB: if we can, we will convert the generated response from internal_encoding to the intended one.
+ * can be: a supported xml encoding (only UTF-8 and ISO-8859-1 at present, unless mbstring is enabled),
+ * null (leave unspecified in response, convert output stream to US_ASCII),
+ * 'default' (use xmlrpc library default as specified in xmlrpc.inc, convert output stream if needed),
+ * or 'auto' (use client-specified charset encoding or same as request if request headers do not specify it (unless request is US-ASCII: then use library default anyway).
+ * NB: pretty dangerous if you accept every charset and do not have mbstring enabled)
+ */
+ var $response_charset_encoding = '';
+ /// storage for internal debug info
+ var $debug_info = '';
+ /// extra data passed at runtime to method handling functions. Used only by EPI layer
+ var $user_data = null;
+
+ /**
+ * @param array $dispmap the dispatch map withd efinition of exposed services
+ * @param boolean $servicenow set to false to prevent the server from runnung upon construction
+ */
+ /*
+ function xmlrpc_server($dispMap=null, $serviceNow=true)
+ {
+ __construct($dispMap, $serviceNow);
+ }
+ */
+
+
+ function __construct($dispMap=null, $serviceNow=true)
+ {
+ // if ZLIB is enabled, let the server by default accept compressed requests,
+ // and compress responses sent to clients that support them
+ if(function_exists('gzinflate'))
+ {
+ $this->accepted_compression = array('gzip', 'deflate');
+ $this->compress_response = true;
+ }
+
+ // by default the xml parser can support these 3 charset encodings
+ $this->accepted_charset_encodings = array('UTF-8', 'ISO-8859-1', 'US-ASCII');
+
+ // dispMap is a dispatch array of methods
+ // mapped to function names and signatures
+ // if a method
+ // doesn't appear in the map then an unknown
+ // method error is generated
+ /* milosch - changed to make passing dispMap optional.
+ * instead, you can use the class add_to_map() function
+ * to add functions manually (borrowed from SOAPX4)
+ */
+ if($dispMap)
+ {
+ $this->dmap = $dispMap;
+ if($serviceNow)
+ {
+ $this->service();
+ }
+ }
+ }
+
+ /**
+ * Set debug level of server.
+ * @param integer $in debug lvl: determines info added to xmlrpc responses (as xml comments)
+ * 0 = no debug info,
+ * 1 = msgs set from user with debugmsg(),
+ * 2 = add complete xmlrpc request (headers and body),
+ * 3 = add also all processing warnings happened during method processing
+ * (NB: this involves setting a custom error handler, and might interfere
+ * with the standard processing of the php function exposed as method. In
+ * particular, triggering an USER_ERROR level error will not halt script
+ * execution anymore, but just end up logged in the xmlrpc response)
+ * Note that info added at elevel 2 and 3 will be base64 encoded
+ * @access public
+ */
+ function setDebug($in)
+ {
+ $this->debug=$in;
+ }
+
+ /**
+ * Return a string with the serialized representation of all debug info
+ * @param string $charset_encoding the target charset encoding for the serialization
+ * @return string an XML comment (or two)
+ */
+ function serializeDebug($charset_encoding='')
+ {
+ // Tough encoding problem: which internal charset should we assume for debug info?
+ // It might contain a copy of raw data received from client, ie with unknown encoding,
+ // intermixed with php generated data and user generated data...
+ // so we split it: system debug is base 64 encoded,
+ // user debug info should be encoded by the end user using the INTERNAL_ENCODING
+ $out = '';
+ if ($this->debug_info != '')
+ {
+ $out .= "\n";
+ }
+ if($GLOBALS['_xmlrpc_debuginfo']!='')
+ {
+
+ $out .= "\n";
+ // NB: a better solution MIGHT be to use CDATA, but we need to insert it
+ // into return payload AFTER the beginning tag
+ //$out .= "', ']_]_>', $GLOBALS['_xmlrpc_debuginfo']) . "\n]]>\n";
+ }
+ return $out;
+ }
+
+ /**
+ * Execute the xmlrpc request, printing the response
+ * @param string $data the request body. If null, the http POST request will be examined
+ * @return xmlrpcresp the response object (usually not used by caller...)
+ * @access public
+ */
+ function service($data=null, $return_payload=false)
+ {
+ if ($data === null)
+ {
+ // workaround for a known bug in php ver. 5.2.2 that broke $HTTP_RAW_POST_DATA
+ $ver = phpversion();
+ if ($ver[0] >= 5)
+ {
+ $data = file_get_contents('php://input');
+ }
+ else
+ {
+ $data = isset($GLOBALS['HTTP_RAW_POST_DATA']) ? $GLOBALS['HTTP_RAW_POST_DATA'] : '';
+ }
+ }
+ $raw_data = $data;
+
+ // reset internal debug info
+ $this->debug_info = '';
+
+ // Echo back what we received, before parsing it
+ if($this->debug > 1)
+ {
+ $this->debugmsg("+++GOT+++\n" . $data . "\n+++END+++");
+ }
+
+ $r = $this->parseRequestHeaders($data, $req_charset, $resp_charset, $resp_encoding);
+ if (!$r)
+ {
+ $r=$this->parseRequest($data, $req_charset);
+ }
+
+ // save full body of request into response, for more debugging usages
+ $r->raw_data = $raw_data;
+
+ if($this->debug > 2 && $GLOBALS['_xmlrpcs_occurred_errors'])
+ {
+ $this->debugmsg("+++PROCESSING ERRORS AND WARNINGS+++\n" .
+ $GLOBALS['_xmlrpcs_occurred_errors'] . "+++END+++");
+ }
+
+ $payload=$this->xml_header($resp_charset);
+ if($this->debug > 0)
+ {
+ $payload = $payload . $this->serializeDebug($resp_charset);
+ }
+
+ // G. Giunta 2006-01-27: do not create response serialization if it has
+ // already happened. Helps building json magic
+ if (empty($r->payload))
+ {
+ $r->serialize($resp_charset);
+ }
+ $payload = $payload . $r->payload;
+
+ if ($return_payload)
+ {
+ return $payload;
+ }
+
+ // if we get a warning/error that has output some text before here, then we cannot
+ // add a new header. We cannot say we are sending xml, either...
+ if(!headers_sent())
+ {
+ header('Content-Type: '.$r->content_type);
+ // we do not know if client actually told us an accepted charset, but if he did
+ // we have to tell him what we did
+ header("Vary: Accept-Charset");
+
+ // http compression of output: only
+ // if we can do it, and we want to do it, and client asked us to,
+ // and php ini settings do not force it already
+ $php_no_self_compress = !ini_get('zlib.output_compression') && (ini_get('output_handler') != 'ob_gzhandler');
+ if($this->compress_response && function_exists('gzencode') && $resp_encoding != ''
+ && $php_no_self_compress)
+ {
+ if(strpos($resp_encoding, 'gzip') !== false)
+ {
+ $payload = gzencode($payload);
+ header("Content-Encoding: gzip");
+ header("Vary: Accept-Encoding");
+ }
+ elseif (strpos($resp_encoding, 'deflate') !== false)
+ {
+ $payload = gzcompress($payload);
+ header("Content-Encoding: deflate");
+ header("Vary: Accept-Encoding");
+ }
+ }
+
+ // do not ouput content-length header if php is compressing output for us:
+ // it will mess up measurements
+ if($php_no_self_compress)
+ {
+ header('Content-Length: ' . (int)strlen($payload));
+ }
+ }
+ else
+ {
+ error_log('XML-RPC: xmlrpc_server::service: http headers already sent before response is fully generated. Check for php warning or error messages');
+ }
+
+ print $payload;
+
+ // return request, in case subclasses want it
+ return $r;
+ }
+
+ /**
+ * Add a method to the dispatch map
+ * @param string $methodname the name with which the method will be made available
+ * @param string $function the php function that will get invoked
+ * @param array $sig the array of valid method signatures
+ * @param string $doc method documentation
+ * @param array $sigdoc the array of valid method signatures docs (one string per param, one for return type)
+ * @access public
+ */
+ function add_to_map($methodname,$function,$sig=null,$doc=false,$sigdoc=false)
+ {
+ $this->dmap[$methodname] = array(
+ 'function' => $function,
+ 'docstring' => $doc
+ );
+ if ($sig)
+ {
+ $this->dmap[$methodname]['signature'] = $sig;
+ }
+ if ($sigdoc)
+ {
+ $this->dmap[$methodname]['signature_docs'] = $sigdoc;
+ }
+ }
+
+ /**
+ * Verify type and number of parameters received against a list of known signatures
+ * @param array $in array of either xmlrpcval objects or xmlrpc type definitions
+ * @param array $sig array of known signatures to match against
+ * @access private
+ */
+ function verifySignature($in, $sig)
+ {
+ // check each possible signature in turn
+ if (is_object($in))
+ {
+ $numParams = $in->getNumParams();
+ }
+ else
+ {
+ $numParams = count($in);
+ }
+ foreach($sig as $cursig)
+ {
+ if(count($cursig)==$numParams+1)
+ {
+ $itsOK=1;
+ for($n=0; $n<$numParams; $n++)
+ {
+ if (is_object($in))
+ {
+ $p=$in->getParam($n);
+ if($p->kindOf() == 'scalar')
+ {
+ $pt=$p->scalartyp();
+ }
+ else
+ {
+ $pt=$p->kindOf();
+ }
+ }
+ else
+ {
+ $pt= $in[$n] == 'i4' ? 'int' : $in[$n]; // dispatch maps never use i4...
+ }
+
+ // param index is $n+1, as first member of sig is return type
+ if($pt != $cursig[$n+1] && $cursig[$n+1] != $GLOBALS['xmlrpcValue'])
+ {
+ $itsOK=0;
+ $pno=$n+1;
+ $wanted=$cursig[$n+1];
+ $got=$pt;
+ break;
+ }
+ }
+ if($itsOK)
+ {
+ return array(1,'');
+ }
+ }
+ }
+ if(isset($wanted))
+ {
+ return array(0, "Wanted ${wanted}, got ${got} at param ${pno}");
+ }
+ else
+ {
+ return array(0, "No method signature matches number of parameters");
+ }
+ }
+
+ /**
+ * Parse http headers received along with xmlrpc request. If needed, inflate request
+ * @return null on success or an xmlrpcresp
+ * @access private
+ */
+ function parseRequestHeaders(&$data, &$req_encoding, &$resp_encoding, &$resp_compression)
+ {
+ // Play nice to PHP 4.0.x: superglobals were not yet invented...
+ if(!isset($_SERVER))
+ {
+ $_SERVER = $GLOBALS['HTTP_SERVER_VARS'];
+ }
+
+ if($this->debug > 1)
+ {
+ if(function_exists('getallheaders'))
+ {
+ $this->debugmsg(''); // empty line
+ foreach(getallheaders() as $name => $val)
+ {
+ $this->debugmsg("HEADER: $name: $val");
+ }
+ }
+
+ }
+
+ if(isset($_SERVER['HTTP_CONTENT_ENCODING']))
+ {
+ $content_encoding = str_replace('x-', '', $_SERVER['HTTP_CONTENT_ENCODING']);
+ }
+ else
+ {
+ $content_encoding = '';
+ }
+
+ // check if request body has been compressed and decompress it
+ if($content_encoding != '' && strlen($data))
+ {
+ if($content_encoding == 'deflate' || $content_encoding == 'gzip')
+ {
+ // if decoding works, use it. else assume data wasn't gzencoded
+ if(function_exists('gzinflate') && in_array($content_encoding, $this->accepted_compression))
+ {
+ if($content_encoding == 'deflate' && $degzdata = @gzuncompress($data))
+ {
+ $data = $degzdata;
+ if($this->debug > 1)
+ {
+ $this->debugmsg("\n+++INFLATED REQUEST+++[".strlen($data)." chars]+++\n" . $data . "\n+++END+++");
+ }
+ }
+ elseif($content_encoding == 'gzip' && $degzdata = @gzinflate(substr($data, 10)))
+ {
+ $data = $degzdata;
+ if($this->debug > 1)
+ $this->debugmsg("+++INFLATED REQUEST+++[".strlen($data)." chars]+++\n" . $data . "\n+++END+++");
+ }
+ else
+ {
+ $r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['server_decompress_fail'], $GLOBALS['xmlrpcstr']['server_decompress_fail']);
+ return $r;
+ }
+ }
+ else
+ {
+ //error_log('The server sent deflated data. Your php install must have the Zlib extension compiled in to support this.');
+ $r = new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['server_cannot_decompress'], $GLOBALS['xmlrpcstr']['server_cannot_decompress']);
+ return $r;
+ }
+ }
+ }
+
+ // check if client specified accepted charsets, and if we know how to fulfill
+ // the request
+ if ($this->response_charset_encoding == 'auto')
+ {
+ $resp_encoding = '';
+ if (isset($_SERVER['HTTP_ACCEPT_CHARSET']))
+ {
+ // here we should check if we can match the client-requested encoding
+ // with the encodings we know we can generate.
+ /// @todo we should parse q=0.x preferences instead of getting first charset specified...
+ $client_accepted_charsets = explode(',', strtoupper($_SERVER['HTTP_ACCEPT_CHARSET']));
+ // Give preference to internal encoding
+ $known_charsets = array($GLOBALS['xmlrpc_internalencoding'], 'UTF-8', 'ISO-8859-1', 'US-ASCII');
+ foreach ($known_charsets as $charset)
+ {
+ foreach ($client_accepted_charsets as $accepted)
+ if (strpos($accepted, $charset) === 0)
+ {
+ $resp_encoding = $charset;
+ break;
+ }
+ if ($resp_encoding)
+ break;
+ }
+ }
+ }
+ else
+ {
+ $resp_encoding = $this->response_charset_encoding;
+ }
+
+ if (isset($_SERVER['HTTP_ACCEPT_ENCODING']))
+ {
+ $resp_compression = $_SERVER['HTTP_ACCEPT_ENCODING'];
+ }
+ else
+ {
+ $resp_compression = '';
+ }
+
+ // 'guestimate' request encoding
+ /// @todo check if mbstring is enabled and automagic input conversion is on: it might mingle with this check???
+ $req_encoding = guess_encoding(isset($_SERVER['CONTENT_TYPE']) ? $_SERVER['CONTENT_TYPE'] : '',
+ $data);
+
+ return null;
+ }
+
+ /**
+ * Parse an xml chunk containing an xmlrpc request and execute the corresponding
+ * php function registered with the server
+ * @param string $data the xml request
+ * @param string $req_encoding (optional) the charset encoding of the xml request
+ * @return xmlrpcresp
+ * @access private
+ */
+ function parseRequest($data, $req_encoding='')
+ {
+ // 2005/05/07 commented and moved into caller function code
+ //if($data=='')
+ //{
+ // $data=$GLOBALS['HTTP_RAW_POST_DATA'];
+ //}
+
+ // G. Giunta 2005/02/13: we do NOT expect to receive html entities
+ // so we do not try to convert them into xml character entities
+ //$data = xmlrpc_html_entity_xlate($data);
+
+ $GLOBALS['_xh']=array();
+ $GLOBALS['_xh']['ac']='';
+ $GLOBALS['_xh']['stack']=array();
+ $GLOBALS['_xh']['valuestack'] = array();
+ $GLOBALS['_xh']['params']=array();
+ $GLOBALS['_xh']['pt']=array();
+ $GLOBALS['_xh']['isf']=0;
+ $GLOBALS['_xh']['isf_reason']='';
+ $GLOBALS['_xh']['method']=false; // so we can check later if we got a methodname or not
+ $GLOBALS['_xh']['rt']='';
+
+ // decompose incoming XML into request structure
+ if ($req_encoding != '')
+ {
+ if (!in_array($req_encoding, array('UTF-8', 'ISO-8859-1', 'US-ASCII')))
+ // the following code might be better for mb_string enabled installs, but
+ // makes the lib about 200% slower...
+ //if (!is_valid_charset($req_encoding, array('UTF-8', 'ISO-8859-1', 'US-ASCII')))
+ {
+ error_log('XML-RPC: xmlrpc_server::parseRequest: invalid charset encoding of received request: '.$req_encoding);
+ $req_encoding = $GLOBALS['xmlrpc_defencoding'];
+ }
+ /// @BUG this will fail on PHP 5 if charset is not specified in the xml prologue,
+ // the encoding is not UTF8 and there are non-ascii chars in the text...
+ /// @todo use an ampty string for php 5 ???
+ $parser = xml_parser_create($req_encoding);
+ }
+ else
+ {
+ $parser = xml_parser_create();
+ }
+
+ xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);
+ // G. Giunta 2005/02/13: PHP internally uses ISO-8859-1, so we have to tell
+ // the xml parser to give us back data in the expected charset
+ // What if internal encoding is not in one of the 3 allowed?
+ // we use the broadest one, ie. utf8
+ // This allows to send data which is native in various charset,
+ // by extending xmlrpc_encode_entitites() and setting xmlrpc_internalencoding
+ if (!in_array($GLOBALS['xmlrpc_internalencoding'], array('UTF-8', 'ISO-8859-1', 'US-ASCII')))
+ {
+ xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, 'UTF-8');
+ }
+ else
+ {
+ xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $GLOBALS['xmlrpc_internalencoding']);
+ }
+
+ if ($this->functions_parameters_type != 'xmlrpcvals')
+ xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee_fast');
+ else
+ xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee');
+ xml_set_character_data_handler($parser, 'xmlrpc_cd');
+ xml_set_default_handler($parser, 'xmlrpc_dh');
+ if(!xml_parse($parser, $data, 1))
+ {
+ // return XML error as a faultCode
+ $r = new xmlrpcresp(0,
+ $GLOBALS['xmlrpcerrxml']+xml_get_error_code($parser),
+ sprintf('XML error: %s at line %d, column %d',
+ xml_error_string(xml_get_error_code($parser)),
+ xml_get_current_line_number($parser), xml_get_current_column_number($parser)));
+ xml_parser_free($parser);
+ }
+ elseif ($GLOBALS['_xh']['isf'])
+ {
+ xml_parser_free($parser);
+ $r = new xmlrpcresp(0,
+ $GLOBALS['xmlrpcerr']['invalid_request'],
+ $GLOBALS['xmlrpcstr']['invalid_request'] . ' ' . $GLOBALS['_xh']['isf_reason']);
+ }
+ else
+ {
+ xml_parser_free($parser);
+ if ($this->functions_parameters_type != 'xmlrpcvals')
+ {
+ if($this->debug > 1)
+ {
+ $this->debugmsg("\n+++PARSED+++\n".var_export($GLOBALS['_xh']['params'], true)."\n+++END+++");
+ }
+ $r = $this->execute($GLOBALS['_xh']['method'], $GLOBALS['_xh']['params'], $GLOBALS['_xh']['pt']);
+ }
+ else
+ {
+ // build an xmlrpcmsg object with data parsed from xml
+ $m = new xmlrpcmsg($GLOBALS['_xh']['method']);
+ // now add parameters in
+ for($i=0; $iaddParam($GLOBALS['_xh']['params'][$i]);
+ }
+
+ if($this->debug > 1)
+ {
+ $this->debugmsg("\n+++PARSED+++\n".var_export($m, true)."\n+++END+++");
+ }
+ $r = $this->execute($m);
+ }
+ }
+ return $r;
+ }
+
+ /**
+ * Execute a method invoked by the client, checking parameters used
+ * @param mixed $m either an xmlrpcmsg obj or a method name
+ * @param array $params array with method parameters as php types (if m is method name only)
+ * @param array $paramtypes array with xmlrpc types of method parameters (if m is method name only)
+ * @return xmlrpcresp
+ * @access private
+ */
+ function execute($m, $params=null, $paramtypes=null)
+ {
+ if (is_object($m))
+ {
+ $methName = $m->method();
+ }
+ else
+ {
+ $methName = $m;
+ }
+ $sysCall = $this->allow_system_funcs && (strpos($methName, "system.") === 0);
+ $dmap = $sysCall ? $GLOBALS['_xmlrpcs_dmap'] : $this->dmap;
+
+ if(!isset($dmap[$methName]['function']))
+ {
+ // No such method
+ return new xmlrpcresp(0,
+ $GLOBALS['xmlrpcerr']['unknown_method'],
+ $GLOBALS['xmlrpcstr']['unknown_method']);
+ }
+
+ // Check signature
+ if(isset($dmap[$methName]['signature']))
+ {
+ $sig = $dmap[$methName]['signature'];
+ if (is_object($m))
+ {
+ list($ok, $errstr) = $this->verifySignature($m, $sig);
+ }
+ else
+ {
+ list($ok, $errstr) = $this->verifySignature($paramtypes, $sig);
+ }
+ if(!$ok)
+ {
+ // Didn't match.
+ return new xmlrpcresp(
+ 0,
+ $GLOBALS['xmlrpcerr']['incorrect_params'],
+ $GLOBALS['xmlrpcstr']['incorrect_params'] . ": ${errstr}"
+ );
+ }
+ }
+
+ $func = $dmap[$methName]['function'];
+ // let the 'class::function' syntax be accepted in dispatch maps
+ if(is_string($func) && strpos($func, '::'))
+ {
+ $func = explode('::', $func);
+ }
+ // verify that function to be invoked is in fact callable
+ if(!is_callable($func))
+ {
+ error_log("XML-RPC: xmlrpc_server::execute: function $func registered as method handler is not callable");
+ return new xmlrpcresp(
+ 0,
+ $GLOBALS['xmlrpcerr']['server_error'],
+ $GLOBALS['xmlrpcstr']['server_error'] . ": no function matches method"
+ );
+ }
+
+ // If debug level is 3, we should catch all errors generated during
+ // processing of user function, and log them as part of response
+ if($this->debug > 2)
+ {
+ $GLOBALS['_xmlrpcs_prev_ehandler'] = set_error_handler('_xmlrpcs_errorHandler');
+ }
+ if (is_object($m))
+ {
+ if($sysCall)
+ {
+ $r = call_user_func($func, $this, $m);
+ }
+ else
+ {
+ $r = call_user_func($func, $m);
+ }
+ if (!is_a($r, 'xmlrpcresp'))
+ {
+ error_log("XML-RPC: xmlrpc_server::execute: function $func registered as method handler does not return an xmlrpcresp object");
+ if (is_a($r, 'xmlrpcval'))
+ {
+ $r = new xmlrpcresp($r);
+ }
+ else
+ {
+ $r = new xmlrpcresp(
+ 0,
+ $GLOBALS['xmlrpcerr']['server_error'],
+ $GLOBALS['xmlrpcstr']['server_error'] . ": function does not return xmlrpcresp object"
+ );
+ }
+ }
+ }
+ else
+ {
+ // call a 'plain php' function
+ if($sysCall)
+ {
+ array_unshift($params, $this);
+ $r = call_user_func_array($func, $params);
+ }
+ else
+ {
+ // 3rd API convention for method-handling functions: EPI-style
+ if ($this->functions_parameters_type == 'epivals')
+ {
+ $r = call_user_func_array($func, array($methName, $params, $this->user_data));
+ // mimic EPI behaviour: if we get an array that looks like an error, make it
+ // an eror response
+ if (is_array($r) && array_key_exists('faultCode', $r) && array_key_exists('faultString', $r))
+ {
+ $r = new xmlrpcresp(0, (integer)$r['faultCode'], (string)$r['faultString']);
+ }
+ else
+ {
+ // functions using EPI api should NOT return resp objects,
+ // so make sure we encode the return type correctly
+ $r = new xmlrpcresp(php_xmlrpc_encode($r, array('extension_api')));
+ }
+ }
+ else
+ {
+ $r = call_user_func_array($func, $params);
+ }
+ }
+ // the return type can be either an xmlrpcresp object or a plain php value...
+ if (!is_a($r, 'xmlrpcresp'))
+ {
+ // what should we assume here about automatic encoding of datetimes
+ // and php classes instances???
+ $r = new xmlrpcresp(php_xmlrpc_encode($r, array('auto_dates')));
+ }
+ }
+ if($this->debug > 2)
+ {
+ // note: restore the error handler we found before calling the
+ // user func, even if it has been changed inside the func itself
+ if($GLOBALS['_xmlrpcs_prev_ehandler'])
+ {
+ set_error_handler($GLOBALS['_xmlrpcs_prev_ehandler']);
+ }
+ else
+ {
+ restore_error_handler();
+ }
+ }
+ return $r;
+ }
+
+ /**
+ * add a string to the 'internal debug message' (separate from 'user debug message')
+ * @param string $strings
+ * @access private
+ */
+ function debugmsg($string)
+ {
+ $this->debug_info .= $string."\n";
+ }
+
+ /**
+ * @access private
+ */
+ function xml_header($charset_encoding='')
+ {
+ if ($charset_encoding != '')
+ {
+ return "\n";
+ }
+ else
+ {
+ return "\n";
+ }
+ }
+
+ /**
+ * A debugging routine: just echoes back the input packet as a string value
+ * DEPRECATED!
+ */
+ function echoInput()
+ {
+ $r = new xmlrpcresp(new xmlrpcval( "'Aha said I: '" . $GLOBALS['HTTP_RAW_POST_DATA'], 'string'));
+ print $r->serialize();
+ }
+ }
+?>
diff --git a/helper-php/DTLNSL_helper_scripts/helper/xmlgroups.php b/helper-php/DTLNSL_helper_scripts/helper/xmlgroups.php
new file mode 100644
index 0000000..29c0a23
--- /dev/null
+++ b/helper-php/DTLNSL_helper_scripts/helper/xmlgroups.php
@@ -0,0 +1,24 @@
+ "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+
+ Methods that run without errors, but do not have the intended result should return as:
+
+ return array('succeed' => 'false', 'message' => 'No Groups Found', 'params' => var_export($params, TRUE));
+
+ or if applicable:
+
+ return array('succeed' => 'false', 'message' => 'What went wrong', 'params' => var_export($params, TRUE), 'sql' => $sql);
+ */
+
+
+ // Modified by Fumi.Iseki '09 5/31
+ // Modified by Fumi.Iseki '14 3/4
+ // Modified by Fumi.Iseki '16 7/14
+
+ include(dirname(__FILE__).'/phpxmlrpclib/xmlrpc.inc');
+ include(dirname(__FILE__).'/phpxmlrpclib/xmlrpcs.inc');
+
+ // Global
+ $osagent = XMLGROUP_ACTIVE_TBL;
+ $osgroup = XMLGROUP_LIST_TBL;
+ $osgroupinvite = XMLGROUP_INVITE_TBL;
+ $osgroupmembership = XMLGROUP_MEMBERSHIP_TBL;
+ $osgroupnotice = XMLGROUP_NOTICE_TBL;
+ $osgrouprolemembership = XMLGROUP_ROLE_MEMBER_TBL;
+ $osrole = XMLGROUP_ROLE_TBL;
+
+
+ $groupPowers = array(
+ 'None' => 0,
+ /// Can send invitations to groups default role
+ 'Invite' => 1,
+ /// Can eject members from group
+ 'Eject' => 2,
+ /// Can toggle 'Open Enrollment' and change 'Signup fee'
+ 'ChangeOptions' => 4,
+ /// Can create new roles
+ 'CreateRole' => 8,
+ /// Can delete existing roles
+ 'DeleteRole' => 16,
+ /// Can change Role names, titles and descriptions
+ 'RoleProperties' => 32,
+ /// Can assign other members to assigners role
+ 'AssignMemberLimited' => 64,
+ /// Can assign other members to any role
+ 'AssignMember' => 128,
+ /// Can remove members from roles
+ 'RemoveMember' => 256,
+ /// Can assign and remove abilities in roles
+ 'ChangeActions' => 512,
+ /// Can change group Charter, Insignia, 'Publish on the web' and which
+ /// members are publicly visible in group member listings
+ 'ChangeIdentity' => 1024,
+ /// Can buy land or deed land to group
+ 'LandDeed' => 2048,
+ /// Can abandon group owned land to Governor Linden on mainland, or Estate owner for
+ /// private estates
+ 'LandRelease' => 4096,
+ /// Can set land for-sale information on group owned parcels
+ 'LandSetSale' => 8192,
+ /// Can subdivide and join parcels
+ 'LandDivideJoin' => 16384,
+ /// Can join group chat sessions
+ 'JoinChat' => 32768,
+ /// Can toggle "Show in Find Places" and set search category
+ 'FindPlaces' => 65536,
+ /// Can change parcel name, description, and 'Publish on web' settings
+ 'LandChangeIdentity' => 131072,
+ /// Can set the landing point and teleport routing on group land
+ 'SetLandingPoint' => 262144,
+ /// Can change music and media settings
+ 'ChangeMedia' => 524288,
+ /// Can toggle 'Edit Terrain' option in Land settings
+ 'LandEdit' => 1048576,
+ /// Can toggle various About Land > Options settings
+ 'LandOptions' => 2097152,
+ /// Can always terraform land, even if parcel settings have it turned off
+ 'AllowEditLand' => 4194304,
+ /// Can always fly while over group owned land
+ 'AllowFly' => 8388608,
+ /// Can always rez objects on group owned land
+ 'AllowRez' => 16777216,
+ /// Can always create landmarks for group owned parcels
+ 'AllowLandmark' => 33554432,
+ /// Can use voice chat in Group Chat sessions
+ 'AllowVoiceChat' => 67108864,
+ /// Can set home location on any group owned parcel
+ 'AllowSetHome' => 134217728,
+ /// Can modify public access settings for group owned parcels
+ 'LandManageAllowed' => 268435456,
+ /// Can manager parcel ban lists on group owned land
+ 'LandManageBanned' => 536870912,
+ /// Can manage pass list sales information
+ 'LandManagePasses' => 1073741824,
+ /// Can eject and freeze other avatars on group owned land
+ 'LandEjectAndFreeze' => 2147483648,
+ /// Can return objects set to group
+ 'ReturnGroupSet' => 4294967296,
+ /// Can return non-group owned/set objects
+ 'ReturnNonGroup' => 8589934592,
+ /// Can landscape using Linden plants
+ 'LandGardening' => 17179869184,
+ /// Can deed objects to group
+ 'DeedObject' => 34359738368,
+ /// Can moderate group chat sessions
+ 'ModerateChat' => 68719476736,
+ /// Can move group owned objects
+ 'ObjectManipulate' => 137438953472,
+ /// Can set group owned objects for-sale
+ 'ObjectSetForSale' => 274877906944,
+ /// Pay group liabilities and receive group dividends
+ 'Accountable' => 549755813888,
+ /// Can send group notices
+ 'SendNotices' => 1099511627776,
+ /// Can receive group notices
+ 'ReceiveNotices' => 2199023255552,
+ /// Can create group proposals
+ 'StartProposal' => 4398046511104,
+ /// Can vote on group proposals
+ 'VoteOnProposal' => 8796093022208,
+ /// Can return group owned objects
+ 'ReturnGroupOwned' => 17592186044416
+ );
+
+
+ $uuidZero = "00000000-0000-0000-0000-000000000000";
+
+ $groupDBCon = mysql_connect($XMLGRP_DB_HOST, $XMLGRP_DB_USER, $XMLGRP_DB_PASS);
+ if (!$groupDBCon)
+ {
+ die('Could not connect: ' . mysql_error());
+ }
+ mysql_select_db($XMLGRP_DB_NAME, $groupDBCon);
+
+ // This is filled in by secure()
+ $requestingAgent = $uuidZero;
+
+
+ function test()
+ {
+ return array('name' => 'Joe','age' => 27);
+ }
+
+ // Use a common signature for all the group functions -> struct foo($struct)
+ $common_sig = array(array($xmlrpcStruct, $xmlrpcStruct));
+
+
+ function createGroup($params)
+ {
+ if( is_array($error = secureRequest($params, TRUE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $groupID = $params["GroupID"];
+ $name = addslashes( $params["Name"] );
+ $charter = addslashes( $params["Charter"] );
+ $insigniaID = $params["InsigniaID"];
+ $founderID = $params["FounderID"];
+ $membershipFee = $params["MembershipFee"];
+ $openEnrollment = $params["OpenEnrollment"];
+ $showInList = $params["ShowInList"];
+ $allowPublish = $params["AllowPublish"];
+ $maturePublish = $params["MaturePublish"];
+ $ownerRoleID = $params["OwnerRoleID"];
+ $everyonePowers = $params["EveryonePowers"];
+ $ownersPowers = $params["OwnersPowers"];
+
+ // Create group
+ $sql = "INSERT INTO $osgroup
+ (GroupID, Name, Charter, InsigniaID, FounderID, MembershipFee, OpenEnrollment, ShowInList, AllowPublish, MaturePublish, OwnerRoleID)
+ VALUES
+ ('$groupID','$name','$charter','$insigniaID','$founderID',$membershipFee,$openEnrollment,$showInList,$allowPublish,$maturePublish,'$ownerRoleID')";
+
+ if (!mysql_query($sql, $groupDBCon))
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+
+ // Create Everyone Role
+ // NOTE: FIXME: This is a temp fix until the libomv enum for group powers is fixed in OpenSim
+ $everyonePowers = 8796495740928;
+ $result = _addRoleToGroup(array('GroupID' => $groupID, 'RoleID' => $uuidZero, 'Name' => 'Everyone',
+ 'Description' => 'Everyone in the group is in the everyone role.', 'Title' => "Member of $name", 'Powers' => $everyonePowers));
+ if( isset($result['error']) )
+ {
+ return $result;
+ }
+
+ // Create Owner Role
+ $result = _addRoleToGroup(array('GroupID' => $groupID, 'RoleID' => $ownerRoleID, 'Name' => 'Owners', 'Description' => "Owners of $name",
+ 'Title' => "Owner of $name", 'Powers' => $ownersPowers));
+ if( isset($result['error']) )
+ {
+ return $result;
+ }
+
+ // Add founder to group, will automatically place them in the Everyone Role, also places them in specified Owner Role
+ $result = _addAgentToGroup(array('AgentID' => $founderID, 'GroupID' => $groupID, 'RoleID' => $ownerRoleID));
+ if( isset($result['error']) )
+ {
+ return $result;
+ }
+
+ // Select the owner's role for the founder
+ $result = _setAgentGroupSelectedRole(array('AgentID' => $founderID, 'RoleID' => $ownerRoleID, 'GroupID' => $groupID));
+ if( isset($result['error']) )
+ {
+ return $result;
+ }
+
+ // Set the new group as the founder's active group
+ $result = _setAgentActiveGroup(array('AgentID' => $founderID, 'GroupID' => $groupID));
+ if( isset($result['error']) )
+ {
+ return $result;
+ }
+
+
+ return getGroup(array("GroupID"=>$groupID));
+ }
+
+
+ // Private method, does not include security, to only be called from places that have already verified security
+ function _addRoleToGroup($params)
+ {
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $groupID = $params['GroupID'];
+ $roleID = $params['RoleID'];
+ $name = addslashes( $params['Name'] );
+ $desc = addslashes( $params['Description'] );
+ $title = addslashes( $params['Title'] );
+ $powers = $params['Powers'];
+
+ $sql = " INSERT INTO $osrole (GroupID, RoleID, Name, Description, Title, Powers) VALUES "
+ ." ('$groupID', '$roleID', '$name', '$desc', '$title', $powers)";
+
+ if (!mysql_query($sql, $groupDBCon))
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error()
+ , 'method' => 'addRoleToGroup'
+ , 'params' => var_export($params, TRUE));
+ }
+
+ return array("success" => "true");
+ }
+
+
+ function addRoleToGroup($params)
+ {
+ if( is_array($error = secureRequest($params, TRUE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ $groupID = $params['GroupID'];
+
+ // Verify the requesting agent has permission
+ if( is_array($error = checkGroupPermission($groupID, $groupPowers['CreateRole'])) )
+ {
+ return $error;
+ }
+
+ return _addRoleToGroup($params);
+ }
+
+
+ function updateGroupRole($params)
+ {
+ if( is_array($error = secureRequest($params, TRUE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $groupID = $params['GroupID'];
+ $roleID = $params['RoleID'];
+ $name = addslashes( $params['Name'] );
+ $desc = addslashes( $params['Description'] );
+ $title = addslashes( $params['Title'] );
+ $powers = $params['Powers'];
+
+ // Verify the requesting agent has permission
+ if( is_array($error = checkGroupPermission($groupID, $groupPowers['RoleProperties'])) )
+ {
+ return $error;
+ }
+
+
+ $sql = " UPDATE $osrole SET RoleID = '$roleID' ";
+ if( isset($params['Name']) )
+ {
+ $sql .= ", Name = '$name'";
+ }
+ if( isset($params['Description']) )
+ {
+ $sql .= ", Description = '$desc'";
+ }
+ if( isset($params['Title']) )
+ {
+ $sql .= ", Title = '$title'";
+ }
+ if( isset($params['Powers']) )
+ {
+ $sql .= ", Powers = $powers";
+ }
+
+ $sql .= " WHERE GroupID = '$groupID' AND RoleID = '$roleID'";
+
+ if (!mysql_query($sql, $groupDBCon))
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+
+ return array("success" => "true");
+ }
+
+
+ function removeRoleFromGroup($params)
+ {
+ if( is_array($error = secureRequest($params, TRUE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $groupID = $params['GroupID'];
+ $roleID = $params['RoleID'];
+
+ if( is_array($error = checkGroupPermission($groupID, $groupPowers['RoleProperties'])) )
+ {
+ return $error;
+ }
+
+ /// 1. Remove all members from Role
+ /// 2. Set selected Role to uuidZero for anyone that had the role selected
+ /// 3. Delete roll
+
+ $sql = "DELETE FROM $osgrouprolemembership WHERE GroupID = '$groupID' AND RoleID = '$roleID'";
+ if (!mysql_query($sql, $groupDBCon))
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+
+ $sql = "UPDATE $osgroupmembership SET SelectedRoleID = '$uuidZero' WHERE GroupID = '$groupID' AND SelectedRoleID = '$roleID'";
+ if (!mysql_query($sql, $groupDBCon))
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+
+ $sql = "DELETE FROM $osrole WHERE GroupID = '$groupID' AND RoleID = '$roleID'";
+ if (!mysql_query($sql, $groupDBCon))
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+
+ return array("success" => "true");
+ }
+
+
+ function getGroup($params)
+ {
+ if( is_array($error = secureRequest($params, FALSE)) )
+ {
+ return $error;
+ }
+
+ return _getGroup($params);
+ }
+
+
+ function _getGroup($params)
+ {
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $sql = " SELECT $osgroup.GroupID, $osgroup.Name, Charter, InsigniaID, FounderID, MembershipFee, OpenEnrollment, ShowInList, AllowPublish, MaturePublish, OwnerRoleID"
+ ." , count($osrole.RoleID) as GroupRolesCount, count($osgroupmembership.AgentID) as GroupMembershipCount "
+ ." FROM $osgroup "
+ ." LEFT JOIN $osrole ON ($osgroup.GroupID = $osrole.GroupID)"
+ ." LEFT JOIN $osgroupmembership ON ($osgroup.GroupID = $osgroupmembership.GroupID)"
+ ." WHERE ";
+ if( isset($params['GroupID']) )
+ {
+ $sql .= "$osgroup.GroupID = '".$params['GroupID']."'";
+
+ } else if( isset($params['Name']) )
+ {
+ $sql .= "$osgroup.Name = '".addslashes($params['Name'])."'";
+ } else {
+ return array("error" => "Must specify GroupID or Name");
+ }
+
+ $sql .= " GROUP BY $osgroup.GroupID, $osgroup.name, charter, insigniaID, founderID, membershipFee, openEnrollment, showInList, allowPublish, maturePublish, ownerRoleID";
+
+ $result = mysql_query($sql, $groupDBCon);
+
+ if (!$result)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+
+ if (mysql_num_rows($result) == 0)
+ {
+ return array('succeed' => 'false', 'error' => 'Group Not Found', 'params' => var_export($params, TRUE), 'sql' => $sql);
+ }
+
+ return mysql_fetch_assoc($result);
+ }
+
+
+ function updateGroup($params)
+ {
+ if( is_array($error = secureRequest($params, TRUE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $groupID = $params["GroupID"];
+ $charter = addslashes( $params["Charter"] );
+ $insigniaID = $params["InsigniaID"];
+ $membershipFee = $params["MembershipFee"];
+ $openEnrollment = $params["OpenEnrollment"];
+ $showInList = $params["ShowInList"];
+ $allowPublish = $params["AllowPublish"];
+ $maturePublish = $params["MaturePublish"];
+
+ if( is_array($error = checkGroupPermission($groupID, $groupPowers['ChangeOptions'])) )
+ {
+ return $error;
+ }
+
+ // Create group
+ $sql = "UPDATE $osgroup
+ SET
+ Charter = '$charter'
+ , InsigniaID = '$insigniaID'
+ , MembershipFee = $membershipFee
+ , OpenEnrollment= $openEnrollment
+ , ShowInList = $showInList
+ , AllowPublish = $allowPublish
+ , MaturePublish = $maturePublish
+ WHERE
+ GroupID = '$groupID'";
+
+ if (!mysql_query($sql, $groupDBCon))
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+
+ return array('success' => 'true');
+ }
+
+
+ function findGroups($params)
+ {
+ if( is_array($error = secureRequest($params, FALSE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $search = addslashes( $params['Search'] );
+
+ // FULLTEXT indexes is not supported in InnoDB :(
+ $sql = " SELECT $osgroup.GroupID, $osgroup.Name, count($osgroupmembership.AgentID) as Members "
+ ." FROM $osgroup LEFT JOIN $osgroupmembership ON ($osgroup.GroupID = $osgroupmembership.GroupID) "
+ ." WHERE "
+ // ." ( MATCH ($osgroup.name) AGAINST ('$search' IN BOOLEAN MODE)"
+ // ." OR $osgroup.name LIKE '%$search%'"
+ // ." OR $osgroup.name REGEXP '$search'"
+ // ." ) AND ShowInList = 1"
+ ." ( $osgroup.name LIKE '%$search%'"
+ ." OR $osgroup.name REGEXP '$search'"
+ ." ) AND ShowInList = 1"
+ ." GROUP BY $osgroup.GroupID, $osgroup.Name";
+
+ $result = mysql_query($sql, $groupDBCon);
+
+ if (!$result)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+
+ if( mysql_num_rows($result) == 0 )
+ {
+ return array('succeed' => 'false', 'error' => 'No groups found.', 'params' => var_export($params, TRUE), 'sql' => $sql);
+ }
+
+ $results = array();
+
+ while ($row = mysql_fetch_assoc($result))
+ {
+ $groupID = $row['GroupID'];
+ $results[$groupID] = $row;
+ }
+
+ return array('results' => $results, 'success' => TRUE);
+ }
+
+
+ function _setAgentActiveGroup($params)
+ {
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $agentID = $params['AgentID'];
+ $groupID = $params['GroupID'];
+
+ $sql = " UPDATE $osagent "
+ ." SET ActiveGroupID = '$groupID'"
+ ." WHERE AgentID = '$agentID'";
+
+ if (!mysql_query($sql, $groupDBCon))
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+
+ if( mysql_affected_rows() == 0 )
+ {
+ $sql = " INSERT INTO $osagent (ActiveGroupID, AgentID) VALUES "
+ ." ('$groupID', '$agentID')";
+
+ if (!mysql_query($sql, $groupDBCon))
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+ }
+
+ return array("success" => "true");
+ }
+
+
+ function setAgentActiveGroup($params)
+ {
+ if( is_array($error = secureRequest($params, TRUE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ $agentID = $params['AgentID'];
+ $groupID = $params['GroupID'];
+
+ if( isset($requestingAgent) && ($requestingAgent != $uuidZero) && ($requestingAgent != $agentID) )
+ {
+ return array('error' => "Agent can only change their own Selected Group Role", 'params' => var_export($params, TRUE));
+ }
+
+ return _setAgentActiveGroup($params);
+ }
+
+
+ function addAgentToGroup($params)
+ {
+ if( is_array($error = secureRequest($params, TRUE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $groupID = $params["GroupID"];
+ $agentID = $params["AgentID"];
+
+ if( is_array($error = checkGroupPermission($groupID, $groupPowers['AssignMember'])) )
+ {
+ // If they don't have direct permission, check to see if the group is marked for open enrollment
+ $groupInfo = _getGroup( array ('GroupID'=>$groupID) );
+
+ if( isset($groupInfo['error']))
+ {
+ return $groupInfo;
+ }
+
+ if($groupInfo['OpenEnrollment'] != 1)
+ {
+ // Group is not open enrollment, check if the specified agentid has an invite
+ $sql = " SELECT GroupID, RoleID, AgentID FROM $osgroupinvite"
+ ." WHERE $osgroupinvite.AgentID = '$agentID' AND $osgroupinvite.GroupID = '$groupID'";
+
+ $results = mysql_query($sql, $groupDBCon);
+ if (!$results)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+
+ if( mysql_num_rows($results) == 1 )
+ {
+ // if there is an invite, make sure we're adding the user to the role specified in the invite
+ $inviteInfo = mysql_fetch_assoc($results);
+ $params['RoleID'] = $inviteInfo['RoleID'];
+ } else {
+ // Not openenrollment, not invited, return permission denied error
+ return $error;
+ }
+
+ }
+ }
+
+ return _addAgentToGroup($params);
+ }
+
+
+ // Private method, does not include security, to only be called from places that have already verified security
+ function _addAgentToGroup($params)
+ {
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $agentID = $params["AgentID"];
+ $groupID = $params["GroupID"];
+
+ $roleID = $uuidZero;
+ if( isset($params["RoleID"]) )
+ {
+ $roleID = $params["RoleID"];
+ }
+
+ // Check if agent already a member
+ $sql = " SELECT count(AgentID) as isMember FROM $osgroupmembership WHERE AgentID = '$agentID' AND GroupID = '$groupID'";
+ $result = mysql_query($sql, $groupDBCon);
+ if (!$result)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+
+ // If not a member, add membership, select role (defaults to uuidZero, or everyone role)
+ if( mysql_result($result, 0) == 0 )
+ {
+ $sql = " INSERT INTO $osgroupmembership (GroupID, AgentID, Contribution, ListInProfile, AcceptNotices, SelectedRoleID) VALUES "
+ ."('$groupID','$agentID', 0, 1, 1,'$roleID')";
+
+ if (!mysql_query($sql, $groupDBCon))
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+ }
+
+ // Make sure they're in the Everyone role
+ $result = _addAgentToGroupRole(array("GroupID" => $groupID, "RoleID" => $uuidZero, "AgentID" => $agentID));
+ if( isset($result['error']) )
+ {
+ return $result;
+ }
+
+ // Make sure they're in specified role, if they were invited
+ if( $roleID != $uuidZero )
+ {
+ $result = _addAgentToGroupRole(array("GroupID" => $groupID, "RoleID" => $roleID, "AgentID" => $agentID));
+ if( isset($result['error']) )
+ {
+ return $result;
+ }
+ }
+
+ return array("success" => "true");
+ }
+
+
+ function removeAgentFromGroup($params)
+ {
+ if( is_array($error = secureRequest($params, TRUE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $agentID = $params["AgentID"];
+ $groupID = $params["GroupID"];
+
+ if( is_array($error = checkGroupPermission($groupID, $groupPowers['RemoveMember'])) )
+ {
+ return $error;
+ }
+
+ // 1. If group is agent's active group, change active group to uuidZero
+ // 2. Remove Agent from group (osgroupmembership)
+ // 3. Remove Agent from all of the groups roles (osgrouprolemembership)
+
+ $sql = " UPDATE $osagent "
+ ." SET ActiveGroupID = '$uuidZero'"
+ ." WHERE AgentID = '$agentID' AND ActiveGroupID = '$groupID'";
+ if (!mysql_query($sql, $groupDBCon))
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+
+ $sql = " DELETE FROM $osgroupmembership "
+ ." WHERE AgentID = '$agentID' AND GroupID = '$groupID'";
+ if (!mysql_query($sql, $groupDBCon))
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+
+ $sql = " DELETE FROM $osgrouprolemembership "
+ ." WHERE AgentID = '$agentID' AND GroupID = '$groupID'";
+ if (!mysql_query($sql, $groupDBCon))
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+
+ return array("success" => "true");
+ }
+
+
+ function _addAgentToGroupRole($params)
+ {
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $agentID = $params["AgentID"];
+ $groupID = $params["GroupID"];
+ $roleID = $params["RoleID"];
+
+ // Check if agent already a member
+ $sql = " SELECT count(AgentID) as isMember FROM $osgrouprolemembership WHERE AgentID = '$agentID' AND RoleID = '$roleID' AND GroupID = '$groupID'";
+ $result = mysql_query($sql, $groupDBCon);
+ if (!$result)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+
+ if( mysql_result($result, 0) == 0 )
+ {
+ $sql = " INSERT INTO $osgrouprolemembership (GroupID, RoleID, AgentID) VALUES "
+ ."('$groupID', '$roleID', '$agentID')";
+
+ if (!mysql_query($sql, $groupDBCon))
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+ }
+
+ return array("success" => "true");
+ }
+
+
+ function addAgentToGroupRole($params)
+ {
+ if( is_array($error = secureRequest($params, TRUE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $agentID = $params["AgentID"];
+ $groupID = $params["GroupID"];
+ $roleID = $params["RoleID"];
+
+ // Check if being assigned to Owners role, assignments to an owners role can only be requested by owners.
+ $sql = " SELECT OwnerRoleID, AgentID "
+ ." FROM $osgroup LEFT JOIN $osgrouprolemembership ON ($osgroup.GroupID = $osgrouprolemembership.GroupID AND $osgroup.OwnerRoleID = $osgrouprolemembership.RoleID) "
+ ." WHERE $osgrouprolemembership.AgentID = '$agentID' AND $osgroup.GroupID = '$groupID'";
+
+ $results = mysql_query($sql, $groupDBCon);
+ if (!$results)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+
+ if( mysql_num_rows($results) != 0 )
+ {
+ $ownerRoleInfo = mysql_fetch_assoc($results);
+ if( ($ownerRoleInfo['OwnerRoleID'] == $roleID) && ($ownerRoleInfo['AgentID'] != $requestingAgent) )
+ {
+ return array('error' => "Requesting agent $requestingAgent is not a member of the Owners Role and cannot add members to the owners role.",
+ 'params' => var_export($params, TRUE));
+ }
+ }
+
+ if( is_array($error = checkGroupPermission($groupID, $groupPowers['AssignMember'])) )
+ {
+ return $error;
+ }
+
+ return _addAgentToGroupRole($params);
+ }
+
+
+ function removeAgentFromGroupRole($params)
+ {
+ if( is_array($error = secureRequest($params, TRUE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $agentID = $params["AgentID"];
+ $groupID = $params["GroupID"];
+ $roleID = $params["RoleID"];
+
+ if( is_array($error = checkGroupPermission($groupID, $groupPowers['AssignMember'])) )
+ {
+ return $error;
+ }
+
+ // If agent has this role selected, change their selection to everyone (uuidZero) role
+ $sql = " UPDATE $osgroupmembership SET SelectedRoleID = '$uuidZero' WHERE AgentID = '$agentID' AND GroupID = '$groupID' AND SelectedRoleID = '$roleID'";
+ $result = mysql_query($sql, $groupDBCon);
+ if (!$result)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+
+ $sql = " DELETE FROM $osgrouprolemembership WHERE AgentID = '$agentID' AND GroupID = '$groupID' AND RoleID = '$roleID'";
+
+ if (!mysql_query($sql, $groupDBCon))
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+
+ return array("success" => "true");
+ }
+
+
+ function _setAgentGroupSelectedRole($params)
+ {
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $agentID = $params["AgentID"];
+ $groupID = $params["GroupID"];
+ $roleID = $params["RoleID"];
+
+ $sql = " UPDATE $osgroupmembership SET SelectedRoleID = '$roleID' WHERE AgentID = '$agentID' AND GroupID = '$groupID'";
+ $result = mysql_query($sql, $groupDBCon);
+ if (!$result)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+
+ return array('success' => 'true');
+ }
+
+
+ function setAgentGroupSelectedRole($params)
+ {
+ if( is_array($error = secureRequest($params, TRUE)) )
+ {
+ return $error;
+ }
+
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ $agentID = $params["AgentID"];
+ $groupID = $params["GroupID"];
+ $roleID = $params["RoleID"];
+
+ if( isset($requestingAgent) && ($requestingAgent != $uuidZero) && ($requestingAgent != $agentID) )
+ {
+ return array('error' => "Agent can only change their own Selected Group Role", 'params' => var_export($params, TRUE));
+ }
+
+ return _setAgentGroupSelectedRole($params);
+ }
+
+
+ function getAgentGroupMembership($params)
+ {
+ if( is_array($error = secureRequest($params, FALSE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $groupID = $params['GroupID'];
+ $agentID = $params['AgentID'];
+
+ $sql = " SELECT $osgroup.GroupID, $osgroup.Name as GroupName, $osgroup.Charter, $osgroup.InsigniaID, $osgroup.FounderID"
+ ." , $osgroup.MembershipFee, $osgroup.OpenEnrollment, $osgroup.ShowInList, $osgroup.AllowPublish, $osgroup.MaturePublish"
+ ." , $osgroupmembership.Contribution, $osgroupmembership.ListInProfile, $osgroupmembership.AcceptNotices"
+ ." , $osgroupmembership.SelectedRoleID, $osrole.Title"
+ ." , $osagent.ActiveGroupID "
+ ." FROM $osgroup JOIN $osgroupmembership ON ($osgroup.GroupID = $osgroupmembership.GroupID)"
+ ." JOIN $osrole ON ($osgroupmembership.SelectedRoleID = $osrole.RoleID AND $osgroupmembership.GroupID = $osrole.GroupID)"
+ ." JOIN $osagent ON ($osagent.AgentID = $osgroupmembership.AgentID)"
+ ." WHERE $osgroup.GroupID = '$groupID' AND $osgroupmembership.AgentID = '$agentID'";
+
+ $groupmembershipResult = mysql_query($sql, $groupDBCon);
+ if (!$groupmembershipResult)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+
+ if( mysql_num_rows($groupmembershipResult) == 0 )
+ {
+ return array('succeed' => 'false', 'error' => 'None Found', 'params' => var_export($params, TRUE), 'sql' => $sql);
+ }
+
+ $groupMembershipInfo = mysql_fetch_assoc($groupmembershipResult);
+
+ $sql = " SELECT BIT_OR($osrole.Powers) AS GroupPowers"
+ ." FROM $osgrouprolemembership JOIN $osrole ON ($osgrouprolemembership.GroupID = $osrole.GroupID AND $osgrouprolemembership.RoleID = $osrole.RoleID)"
+ ." WHERE $osgrouprolemembership.GroupID = '$groupID' AND $osgrouprolemembership.AgentID = '$agentID'";
+ $groupPowersResult = mysql_query($sql, $groupDBCon);
+ if (!$groupPowersResult)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+ $groupPowersInfo = mysql_fetch_assoc($groupPowersResult);
+
+ return array_merge($groupMembershipInfo, $groupPowersInfo);
+ }
+
+
+ function getAgentGroupMemberships($params)
+ {
+ if( is_array($error = secureRequest($params, FALSE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+ $agentID = $params['AgentID'];
+
+ $sql = " SELECT $osgroup.GroupID, $osgroup.Name as GroupName, $osgroup.Charter, $osgroup.InsigniaID, $osgroup.FounderID"
+ ." , $osgroup.MembershipFee, $osgroup.OpenEnrollment, $osgroup.ShowInList, $osgroup.AllowPublish, $osgroup.MaturePublish"
+ ." , $osgroupmembership.Contribution, $osgroupmembership.ListInProfile, $osgroupmembership.AcceptNotices"
+ ." , $osgroupmembership.SelectedRoleID, $osrole.Title"
+ ." , IFNULL($osagent.ActiveGroupID, '$uuidZero') AS ActiveGroupID"
+ ." FROM $osgroup JOIN $osgroupmembership ON ($osgroup.GroupID = $osgroupmembership.GroupID)"
+ ." JOIN $osrole ON ($osgroupmembership.SelectedRoleID = $osrole.RoleID AND $osgroupmembership.GroupID = $osrole.GroupID)"
+ ." LEFT JOIN $osagent ON ($osagent.AgentID = $osgroupmembership.AgentID)"
+ ." WHERE $osgroupmembership.AgentID = '$agentID'";
+
+ $groupmembershipResults = mysql_query($sql, $groupDBCon);
+ if (!$groupmembershipResults)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+
+ if( mysql_num_rows($groupmembershipResults) == 0 )
+ {
+ return array('succeed' => 'false', 'error' => 'No Memberships', 'params' => var_export($params, TRUE), 'sql' => $sql);
+
+ }
+
+ $groupResults = array();
+ while($groupMembershipInfo = mysql_fetch_assoc($groupmembershipResults))
+ {
+ $groupID = $groupMembershipInfo['GroupID'];
+ $sql = " SELECT BIT_OR($osrole.Powers) AS GroupPowers"
+ ." FROM $osgrouprolemembership JOIN $osrole ON ($osgrouprolemembership.GroupID = $osrole.GroupID AND $osgrouprolemembership.RoleID = $osrole.RoleID)"
+ ." WHERE $osgrouprolemembership.GroupID = '$groupID' AND $osgrouprolemembership.AgentID = '$agentID'";
+ $groupPowersResult = mysql_query($sql, $groupDBCon);
+ if (!$groupPowersResult)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+ $groupPowersInfo = mysql_fetch_assoc($groupPowersResult);
+ $groupResults[$groupID] = array_merge($groupMembershipInfo, $groupPowersInfo);
+ }
+
+ return $groupResults;
+ }
+
+
+ function getGroupMembers($params)
+ {
+ if( is_array($error = secureRequest($params, FALSE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $groupID = $params['GroupID'];
+
+ $sql = " SELECT $osgroupmembership.AgentID"
+ ." , $osgroupmembership.Contribution, $osgroupmembership.ListInProfile, $osgroupmembership.AcceptNotices"
+ ." , $osgroupmembership.SelectedRoleID, $osrole.Title"
+ ." , CASE WHEN OwnerRoleMembership.AgentID IS NOT NULL THEN 1 ELSE 0 END AS IsOwner"
+ ." FROM $osgroup JOIN $osgroupmembership ON ($osgroup.GroupID = $osgroupmembership.GroupID)"
+ ." JOIN $osrole ON ($osgroupmembership.SelectedRoleID = $osrole.RoleID AND $osgroupmembership.GroupID = $osrole.GroupID)"
+ ." JOIN $osrole AS OwnerRole ON ($osgroup.OwnerRoleID = OwnerRole.RoleID AND $osgroup.GroupID = OwnerRole.GroupID)"
+ ." LEFT JOIN $osgrouprolemembership AS OwnerRoleMembership ON ($osgroup.OwnerRoleID = OwnerRoleMembership.RoleID
+ AND ($osgroup.GroupID = OwnerRoleMembership.GroupID)
+ AND ($osgroupmembership.AgentID = OwnerRoleMembership.AgentID))"
+ ." WHERE $osgroup.GroupID = '$groupID'";
+
+ $groupmemberResults = mysql_query($sql, $groupDBCon);
+ if (!$groupmemberResults)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+
+ if (mysql_num_rows($groupmemberResults) == 0)
+ {
+ return array('succeed' => 'false', 'error' => 'No Group Members found', 'params' => var_export($params, TRUE), 'sql' => $sql);
+ }
+
+ $memberResults = array();
+ while($memberInfo = mysql_fetch_assoc($groupmemberResults))
+ {
+ $agentID = $memberInfo['AgentID'];
+ $sql = " SELECT BIT_OR($osrole.Powers) AS AgentPowers"
+ ." FROM $osgrouprolemembership JOIN $osrole ON ($osgrouprolemembership.GroupID = $osrole.GroupID AND $osgrouprolemembership.RoleID = $osrole.RoleID)"
+ ." WHERE $osgrouprolemembership.GroupID = '$groupID' AND $osgrouprolemembership.AgentID = '$agentID'";
+ $memberPowersResult = mysql_query($sql, $groupDBCon);
+ if (!$memberPowersResult)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+
+ if (mysql_num_rows($groupmemberResults) == 0)
+ {
+ $memberResults[$agentID] = array_merge($memberInfo, array('AgentPowers' => 0));
+ } else {
+ $memberPowersInfo = mysql_fetch_assoc($memberPowersResult);
+ $memberResults[$agentID] = array_merge($memberInfo, $memberPowersInfo);
+ }
+ }
+
+ return $memberResults;
+ }
+
+
+ function getAgentActiveMembership($params)
+ {
+ if( is_array($error = secureRequest($params, FALSE)) )
+ {
+ return $error;
+ }
+
+ secureRequest($params, FALSE);
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $agentID = $params['AgentID'];
+
+ $sql = " SELECT $osgroup.GroupID, $osgroup.Name as GroupName, $osgroup.Charter, $osgroup.InsigniaID, $osgroup.FounderID"
+ ." , $osgroup.MembershipFee, $osgroup.OpenEnrollment, $osgroup.ShowInList, $osgroup.AllowPublish, $osgroup.MaturePublish"
+ ." , $osgroupmembership.Contribution, $osgroupmembership.ListInProfile, $osgroupmembership.AcceptNotices"
+ ." , $osgroupmembership.SelectedRoleID, $osrole.Title"
+ ." , $osagent.ActiveGroupID "
+ ." FROM $osagent JOIN $osgroup ON ($osgroup.GroupID = $osagent.ActiveGroupID)"
+ ." JOIN $osgroupmembership ON ($osgroup.GroupID = $osgroupmembership.GroupID AND $osagent.AgentID = $osgroupmembership.AgentID)"
+ ." JOIN $osrole ON ($osgroupmembership.SelectedRoleID = $osrole.RoleID AND $osgroupmembership.GroupID = $osrole.GroupID)"
+ ." WHERE $osagent.AgentID = '$agentID'";
+
+ $groupmembershipResult = mysql_query($sql, $groupDBCon);
+ if (!$groupmembershipResult)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+ if (mysql_num_rows($groupmembershipResult) == 0)
+ {
+ return array('succeed' => 'false', 'error' => 'No Active Group Specified', 'params' => var_export($params, TRUE), 'sql' => $sql);
+ }
+ $groupMembershipInfo = mysql_fetch_assoc($groupmembershipResult);
+
+ $groupID = $groupMembershipInfo['GroupID'];
+ $sql = " SELECT BIT_OR($osrole.Powers) AS GroupPowers"
+ ." FROM $osgrouprolemembership JOIN $osrole ON ($osgrouprolemembership.GroupID = $osrole.GroupID AND $osgrouprolemembership.RoleID = $osrole.RoleID)"
+ ." WHERE $osgrouprolemembership.GroupID = '$groupID' AND $osgrouprolemembership.AgentID = '$agentID'";
+ $groupPowersResult = mysql_query($sql, $groupDBCon);
+ if (!$groupPowersResult)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+ $groupPowersInfo = mysql_fetch_assoc($groupPowersResult);
+
+ return array_merge($groupMembershipInfo, $groupPowersInfo);
+ }
+
+
+ function getAgentRoles($params)
+ {
+ if( is_array($error = secureRequest($params, FALSE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $agentID = $params['AgentID'];
+
+ $sql = " SELECT "
+ ." $osrole.RoleID, $osrole.GroupID, $osrole.Title, $osrole.Name, $osrole.Description, $osrole.Powers"
+ ." , CASE WHEN $osgroupmembership.SelectedRoleID = $osrole.RoleID THEN 1 ELSE 0 END AS Selected"
+ ." FROM $osgroupmembership JOIN $osgrouprolemembership ON ($osgroupmembership.GroupID = $osgrouprolemembership.GroupID "
+ ." AND $osgroupmembership.AgentID = $osgrouprolemembership.AgentID)"
+ ." JOIN $osrole ON ( $osgrouprolemembership.RoleID = $osrole.RoleID AND $osgrouprolemembership.GroupID = $osrole.GroupID)"
+ ." LEFT JOIN $osagent ON ($osagent.AgentID = $osgroupmembership.AgentID)"
+ ." WHERE $osgroupmembership.AgentID = '$agentID'";
+
+ if( isset($params['GroupID']) )
+ {
+ $groupID = $params['GroupID'];
+ $sql .= " AND $osgroupmembership.GroupID = '$groupID'";
+ }
+
+ $roleResults = mysql_query($sql, $groupDBCon);
+ if (!$roleResults)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+
+ if( mysql_num_rows($roleResults) == 0 )
+ {
+ return array('succeed' => 'false', 'error' => 'None found', 'params' => var_export($params, TRUE), 'sql' => $sql);
+ }
+
+ $roles = array();
+ while($role = mysql_fetch_assoc($roleResults))
+ {
+ $ID = $role['GroupID'].$role['RoleID'];
+ $roles[$ID] = $role;
+ }
+
+ return $roles;
+ }
+
+
+ function getGroupRoles($params)
+ {
+ if( is_array($error = secureRequest($params, FALSE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $groupID = $params['GroupID'];
+
+ $sql = " SELECT "
+ ." $osrole.RoleID, $osrole.Name, $osrole.Title, $osrole.Description, $osrole.Powers, count($osgrouprolemembership.AgentID) as Members"
+ ." FROM $osrole LEFT JOIN $osgrouprolemembership ON ($osrole.GroupID = $osgrouprolemembership.GroupID AND $osrole.RoleID = $osgrouprolemembership.RoleID)"
+ ." WHERE $osrole.GroupID = '$groupID'"
+ ." GROUP BY $osrole.RoleID, $osrole.Name, $osrole.Title, $osrole.Description, $osrole.Powers";
+
+ $roleResults = mysql_query($sql, $groupDBCon);
+ if (!$roleResults)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+
+ if( mysql_num_rows($roleResults) == 0 )
+ {
+ return array('succeed' => 'false', 'error' => 'No roles found for group', 'params' => var_export($params, TRUE), 'sql' => $sql);
+ }
+
+ $roles = array();
+ while($role = mysql_fetch_assoc($roleResults))
+ {
+ $RoleID = $role['RoleID'];
+ $roles[$RoleID] = $role;
+ }
+
+ return $roles;
+ }
+
+
+ function getGroupRoleMembers($params)
+ {
+ if( is_array($error = secureRequest($params, FALSE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $groupID = $params['GroupID'];
+ // $roleID = $params['RoleID'];
+
+ $sql = " SELECT "
+ ." $osrole.RoleID, $osgrouprolemembership.AgentID"
+ ." FROM $osrole JOIN $osgrouprolemembership ON ($osrole.GroupID = $osgrouprolemembership.GroupID AND $osrole.RoleID = $osgrouprolemembership.RoleID)"
+ ." WHERE $osrole.GroupID = '$groupID'";
+// ." AND $osrole.RoleID = '$roleID'";
+
+ $memberResults = mysql_query($sql, $groupDBCon);
+ if (!$memberResults)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+
+ $members = array();
+ while($member = mysql_fetch_assoc($memberResults))
+ {
+ $Key = $member['AgentID'] . $member['RoleID'];
+ $members[$Key ] = $member;
+ }
+
+ return $members;
+ }
+
+
+ function setAgentGroupInfo($params)
+ {
+ if( is_array($error = secureRequest($params, TRUE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ if (isset($params['AgentID'])) {
+ $agentID = $params['AgentID'];
+ } else {
+ $agentID = "";
+ }
+ if (isset($params['GroupID'])) {
+ $groupID = $params['GroupID'];
+ } else {
+ $groupID = "";
+ }
+ if (isset($params['SelectedRoleID'])) {
+ $roleID = $params['SelectedRoleID'];
+ } else {
+ $roleID = "";
+ }
+ if (isset($params['AcceptNotice'])) {
+ $acceptNotices = $params['AcceptNotices'];
+ } else {
+ $acceptNotices = "";
+ }
+ if (isset($params['ListInProfile'])) {
+ $listInProfile = $params['ListInProfile'];
+ } else {
+ $listInProfile = "";
+ }
+
+ if( isset($requestingAgent) && ($requestingAgent != $uuidZero) && ($requestingAgent != $agentID) )
+ {
+ return array('error' => "Agent can only change their own group info", 'params' => var_export($params, TRUE));
+ }
+
+ $sql = " UPDATE "
+ ." $osgroupmembership"
+ ." SET "
+ ." AgentID = '$agentID'";
+
+ if( isset($params['SelectedRoleID']) )
+ {
+ $sql .=" , SelectedRoleID = '$roleID'";
+ }
+ if( isset($params['AcceptNotices']) )
+ {
+ $sql .=" , AcceptNotices = '$acceptNotices'";
+ }
+ if( isset($params['ListInProfile']) )
+ {
+ $sql .=" , ListInProfile = '$listInProfile'";
+ }
+
+ $sql .=" WHERE $osgroupmembership.GroupID = '$groupID' AND $osgroupmembership.AgentID = '$agentID'";
+
+ $memberResults = mysql_query($sql, $groupDBCon);
+ if (!$memberResults)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+
+ return array('success'=> 'true');
+ }
+
+
+ function getGroupNotices($params)
+ {
+ if( is_array($error = secureRequest($params, FALSE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $groupID = $params['GroupID'];
+
+
+ $sql = " SELECT "
+ ." GroupID, NoticeID, Timestamp, FromName, Subject, Message, BinaryBucket"
+ ." FROM $osgroupnotice"
+ ." WHERE $osgroupnotice.GroupID = '$groupID'";
+
+ $results = mysql_query($sql, $groupDBCon);
+ if (!$results)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+
+ if( mysql_num_rows($results) == 0 )
+ {
+ return array('succeed' => 'false', 'error' => 'No Notices', 'params' => var_export($params, TRUE), 'sql' => $sql);
+ }
+
+ $notices = array();
+ while($notice = mysql_fetch_assoc($results))
+ {
+ $NoticeID = $notice['NoticeID'];
+ $notices[$NoticeID] = $notice;
+ }
+
+ return $notices;
+ }
+
+
+ function getGroupNotice($params)
+ {
+ if( is_array($error = secureRequest($params, FALSE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $noticeID = $params['NoticeID'];
+
+
+ $sql = " SELECT "
+ ." GroupID, NoticeID, Timestamp, FromName, Subject, Message, BinaryBucket"
+ ." FROM $osgroupnotice"
+ ." WHERE $osgroupnotice.NoticeID = '$noticeID'";
+
+ $results = mysql_query($sql, $groupDBCon);
+ if (!$results)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+
+ if( mysql_num_rows($results) == 0 )
+ {
+ return array('succeed' => 'false', 'error' => 'Group Notice Not Found', 'params' => var_export($params, TRUE), 'sql' => $sql);
+ }
+
+ return mysql_fetch_assoc($results);
+ }
+
+
+ function addGroupNotice($params)
+ {
+ if( is_array($error = secureRequest($params, TRUE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $groupID = $params['GroupID'];
+ $noticeID = $params['NoticeID'];
+ $fromName = addslashes($params['FromName']);
+ $subject = addslashes($params['Subject']);
+ $binaryBucket = $params['BinaryBucket'];
+ $message = addslashes($params['Message']);
+ $timeStamp = $params['TimeStamp'];
+
+ if( is_array($error = checkGroupPermission($groupID, $groupPowers['SendNotices'])) )
+ {
+ return $error;
+ }
+
+ $sql = " INSERT INTO $osgroupnotice"
+ ." (GroupID, NoticeID, Timestamp, FromName, Subject, Message, BinaryBucket)"
+ ." VALUES "
+ ." ('$groupID', '$noticeID', $timeStamp, '$fromName', '$subject', '$message', '$binaryBucket')";
+
+ $results = mysql_query($sql, $groupDBCon);
+ if (!$results)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+
+ return array('success' => 'true');
+ }
+
+
+ function addAgentToGroupInvite($params)
+ {
+ if( is_array($error = secureRequest($params, TRUE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $inviteID = $params['InviteID'];
+ $groupID = $params['GroupID'];
+ $roleID = $params['RoleID'];
+ $agentID = $params['AgentID'];
+
+ if( is_array($error = checkGroupPermission($groupID, $groupPowers['AssignMember'])) )
+ {
+ return $error;
+ }
+
+ // Remove any existing invites for this agent to this group
+ $sql = " DELETE FROM $osgroupinvite"
+ ." WHERE $osgroupinvite.AgentID = '$agentID' AND $osgroupinvite.GroupID = '$groupID'";
+
+ $results = mysql_query($sql, $groupDBCon);
+ if (!$results)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+
+ // Add new invite for this agent to this group for the specifide role
+ $sql = " INSERT INTO $osgroupinvite"
+ ." (InviteID, GroupID, RoleID, AgentID) VALUES ('$inviteID', '$groupID', '$roleID', '$agentID')";
+
+ $results = mysql_query($sql, $groupDBCon);
+ if (!$results)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+
+ return array('success' => 'true');
+ }
+
+
+ function getAgentToGroupInvite($params)
+ {
+ if( is_array($error = secureRequest($params, FALSE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $inviteID = $params['InviteID'];
+
+
+ $sql = " SELECT GroupID, RoleID, AgentID FROM $osgroupinvite"
+ ." WHERE $osgroupinvite.InviteID = '$inviteID'";
+
+ $results = mysql_query($sql, $groupDBCon);
+ if (!$results)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+
+ if( mysql_num_rows($results) == 1 )
+ {
+ $inviteInfo = mysql_fetch_assoc($results);
+ $groupID = $inviteInfo['GroupID'];
+ $roleID = $inviteInfo['RoleID'];
+ $agentID = $inviteInfo['AgentID'];
+
+ return array('success' => 'true', 'GroupID'=>$groupID, 'RoleID'=>$roleID, 'AgentID'=>$agentID);
+ } else {
+ return array('succeed' => 'false', 'error' => 'Invitation not found', 'params' => var_export($params, TRUE), 'sql' => $sql);
+ }
+ }
+
+
+ function removeAgentToGroupInvite($params)
+ {
+ if( is_array($error = secureRequest($params, TRUE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $inviteID = $params['InviteID'];
+
+ $sql = " DELETE FROM $osgroupinvite"
+ ." WHERE $osgroupinvite.InviteID = '$inviteID'";
+
+ $results = mysql_query($sql, $groupDBCon);
+ if (!$results)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysql_error(), 'params' => var_export($params, TRUE));
+ }
+
+ return array('success' => 'true');
+ }
+
+
+ function secureRequest($params, $write = FALSE)
+ {
+ global $GroupWriteKey, $GroupReadKey, $VerifiedReadKey, $VerifiedWriteKey, $GroupRequireAgentAuthForWrite, $requestingAgent;
+
+ if( isset($GroupReadKey) && ($GroupReadKey != '') && (!isset($VerifiedReadKey) || ($VerifiedReadKey !== TRUE)) )
+ {
+ if( !isset($params['ReadKey']) || ($params['ReadKey'] != $GroupReadKey ) )
+ {
+ return array('error' => "Invalid (or No) Read Key Specified", 'params' => var_export($params, TRUE));
+ } else {
+ $VerifiedReadKey = TRUE;
+ }
+ }
+
+ if( ($write == TRUE) && isset($GroupWriteKey) && ($GroupWriteKey != '') && (!isset($VerifiedWriteKey) || ($VerifiedWriteKey !== TRUE)) )
+ {
+ if( !isset($params['WriteKey']) || ($params['WriteKey'] != $GroupWriteKey ) )
+ {
+ return array('error' => "Invalid (or No) Write Key Specified", 'params' => var_export($params, TRUE));
+ } else {
+ $VerifiedWriteKey = TRUE;
+ }
+ }
+
+ if( ($write == TRUE) && isset($GroupRequireAgentAuthForWrite) && ($GroupRequireAgentAuthForWrite == TRUE) )
+ {
+ // Note: my brain can't do boolean logic this morning, so just putting this here instead of integrating with line above.
+ // If the write key has already been verified for this request, don't check it again.
+ // This comes into play with methods that call other methods, such as CreateGroup() which calls Addrole()
+ if( isset($VerifiedWriteKey) && ($VerifiedWriteKey !== TRUE))
+ {
+ return TRUE;
+ }
+
+ if( !isset($params['RequestingAgentID'])
+ || !isset($params['RequestingAgentUserService'])
+ || !isset($params['RequestingSessionID'])
+ )
+ {
+ return array('error' => "Requesting AgentID and SessionID must be specified", 'params' => var_export($params, TRUE));
+ }
+
+ $requestingAgent = $params['RequestingAgentID'];
+
+ // NOTE: an AgentID and SessionID of $uuidZero will likely be a region making a request, that is not tied to a specific agent making the request.
+
+ $client = new xmlrpc_client($params['RequestingAgentUserService']);
+ $client->return_type = 'phpvals';
+
+ $verifyParams = new xmlrpcval(array('avatar_uuid' => new xmlrpcval($params['RequestingAgentID'], 'string')
+ ,'session_id' => new xmlrpcval($params['RequestingSessionID'], 'string')), 'struct');
+
+ $message = new xmlrpcmsg("check_auth_session", array($verifyParams));
+ $resp = $client->send($message, 5);
+ if ($resp->faultCode())
+ {
+ return array('error' => "Error validating AgentID and SessionID"
+ , 'xmlrpcerror'=> $resp->faultString()
+ , 'params' => var_export($params, TRUE));
+ }
+
+ $verifyReturn = $resp->value();
+
+ if( !isset($verifyReturn['auth_session']) || ($verifyReturn['auth_session'] != 'TRUE') )
+ {
+ return array('error' => "UserService.check_auth_session() did not return TRUE"
+ , 'userservice' => var_export($verifyReturn, TRUE)
+ , 'params' => var_export($params, TRUE));
+
+ }
+ }
+
+ return TRUE;
+ }
+
+
+ function checkGroupPermission($GroupID, $Permission)
+ {
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+
+ // If it isn't set to true, then always return true, otherwise verify they have perms
+ if( !isset($GroupEnforceGroupPerms) || ($GroupEnforceGroupPerms != TRUE) )
+ {
+ return true;
+ }
+
+ if( !isset($requestingAgent) || ($requestingAgent == $uuidZero) )
+ {
+ return array('error' => 'Requesting agent was either not specified or not validated.'
+ , 'params' => var_export($params, TRUE));
+ }
+
+ $params = array('AgentID' => $requestingAgent, 'GroupID' => $GroupID);
+ $reqAgentMembership = getAgentGroupMembership($params);
+
+ if( isset($reqAgentMembership['error'] ) )
+ {
+ return array('error' => 'Could not get agent membership for group'
+ , 'params' => var_export($params, TRUE)
+ , 'nestederror' => $reqAgentMembership['error']);
+ }
+
+ if( $reqAgentMembership['GroupPowers'] & $Permission != $Permission )
+ {
+ return array('error' => 'Agent does not have group power to $Permission'
+ , 'params' => var_export($params, TRUE));
+ }
+ }
+
+ $s = new xmlrpc_server(array(
+ "test" => array("function" => "test")
+ , "groups.createGroup" => array("function" => "createGroup", "signature" => $common_sig)
+ , "groups.updateGroup" => array("function" => "updateGroup", "signature" => $common_sig)
+ , "groups.getGroup" => array("function" => "getGroup", "signature" => $common_sig)
+ , "groups.findGroups" => array("function" => "findGroups", "signature" => $common_sig)
+
+ , "groups.getGroupRoles" => array("function" => "getGroupRoles", "signature" => $common_sig)
+ , "groups.addRoleToGroup" => array("function" => "addRoleToGroup", "signature" => $common_sig)
+ , "groups.removeRoleFromGroup" => array("function" => "removeRoleFromGroup", "signature" => $common_sig)
+ , "groups.updateGroupRole" => array("function" => "updateGroupRole", "signature" => $common_sig)
+ , "groups.getGroupRoleMembers" => array("function" => "getGroupRoleMembers", "signature" => $common_sig)
+
+ , "groups.setAgentGroupSelectedRole" => array("function" => "setAgentGroupSelectedRole", "signature" => $common_sig)
+ , "groups.addAgentToGroupRole" => array("function" => "addAgentToGroupRole", "signature" => $common_sig)
+ , "groups.removeAgentFromGroupRole" => array("function" => "removeAgentFromGroupRole", "signature" => $common_sig)
+
+ , "groups.getGroupMembers" => array("function" => "getGroupMembers", "signature" => $common_sig)
+ , "groups.addAgentToGroup" => array("function" => "addAgentToGroup", "signature" => $common_sig)
+ , "groups.removeAgentFromGroup" => array("function" => "removeAgentFromGroup", "signature" => $common_sig)
+ , "groups.setAgentGroupInfo" => array("function" => "setAgentGroupInfo", "signature" => $common_sig)
+
+ , "groups.addAgentToGroupInvite" => array("function" => "addAgentToGroupInvite", "signature" => $common_sig)
+ , "groups.getAgentToGroupInvite" => array("function" => "getAgentToGroupInvite", "signature" => $common_sig)
+ , "groups.removeAgentToGroupInvite" => array("function" => "removeAgentToGroupInvite", "signature" => $common_sig)
+
+ , "groups.setAgentActiveGroup" => array("function" => "setAgentActiveGroup", "signature" => $common_sig)
+ , "groups.getAgentGroupMembership" => array("function" => "getAgentGroupMembership", "signature" => $common_sig)
+ , "groups.getAgentGroupMemberships" => array("function" => "getAgentGroupMemberships", "signature" => $common_sig)
+ , "groups.getAgentActiveMembership" => array("function" => "getAgentActiveMembership", "signature" => $common_sig)
+ , "groups.getAgentRoles" => array("function" => "getAgentRoles", "signature" => $common_sig)
+
+ , "groups.getGroupNotices" => array("function" => "getGroupNotices", "signature" => $common_sig)
+ , "groups.getGroupNotice" => array("function" => "getGroupNotice", "signature" => $common_sig)
+ , "groups.addGroupNotice" => array("function" => "addGroupNotice", "signature" => $common_sig)
+
+ ), false);
+
+ $s->functions_parameters_type = 'phpvals';
+ if (isset($debugXMLRPC) && $debugXMLRPC > 0 && isset($debugXMLRPCFile) && $debugXMLRPCFile != "")
+ {
+ $s->setDebug($debugXMLRPC);
+ }
+ $s->service();
+
+ if (isset($debugXMLRPC) && $debugXMLRPC > 0 && isset($debugXMLRPCFile) && $debugXMLRPCFile != "")
+ {
+ $f = fopen($debugXMLRPCFile,"a");
+ fwrite($f,"\n----- " . date("Y-m-d H:i:s") . " -----\n");
+ $debugInfo = $s->serializeDebug();
+ //$debugInfo = split("\n",$debugInfo);
+ $debugInfo = explode("\n",$debugInfo);
+ unset($debugInfo[0]);
+ unset($debugInfo[count($debugInfo) -1]);
+ $debugInfo = join("\n",$debugInfo);
+ fwrite($f,base64_decode($debugInfo));
+ fclose($f);
+ }
+
+ mysql_close($groupDBCon);
+
diff --git a/helper-php/DTLNSL_helper_scripts/helper/xmlrpci.php b/helper-php/DTLNSL_helper_scripts/helper/xmlrpci.php
new file mode 100644
index 0000000..1c25b76
--- /dev/null
+++ b/helper-php/DTLNSL_helper_scripts/helper/xmlrpci.php
@@ -0,0 +1,1688 @@
+ "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+
+ Methods that run without errors, but do not have the intended result should return as:
+
+ return array('succeed' => 'false', 'message' => 'No Groups Found', 'params' => var_export($params, TRUE));
+
+ or if applicable:
+
+ return array('succeed' => 'false', 'message' => 'What went wrong', 'params' => var_export($params, TRUE), 'sql' => $sql);
+ */
+
+
+ // Modified by Fumi.Iseki '09 5/31
+ // Modified by Fumi.Iseki '14 3/4
+ // Modified by Fumi.Iseki '14 5/15 for MySQLi
+ // Modified by Fumi.Iseki '16 7/14
+
+ include(dirname(__FILE__).'/phpxmlrpclib/xmlrpc.inc');
+ include(dirname(__FILE__).'/phpxmlrpclib/xmlrpcs.inc');
+
+ // Global
+ $osagent = XMLGROUP_ACTIVE_TBL;
+ $osgroup = XMLGROUP_LIST_TBL;
+ $osgroupinvite = XMLGROUP_INVITE_TBL;
+ $osgroupmembership = XMLGROUP_MEMBERSHIP_TBL;
+ $osgroupnotice = XMLGROUP_NOTICE_TBL;
+ $osgrouprolemembership = XMLGROUP_ROLE_MEMBER_TBL;
+ $osrole = XMLGROUP_ROLE_TBL;
+
+
+ $groupPowers = array(
+ 'None' => 0,
+ /// Can send invitations to groups default role
+ 'Invite' => 1,
+ /// Can eject members from group
+ 'Eject' => 2,
+ /// Can toggle 'Open Enrollment' and change 'Signup fee'
+ 'ChangeOptions' => 4,
+ /// Can create new roles
+ 'CreateRole' => 8,
+ /// Can delete existing roles
+ 'DeleteRole' => 16,
+ /// Can change Role names, titles and descriptions
+ 'RoleProperties' => 32,
+ /// Can assign other members to assigners role
+ 'AssignMemberLimited' => 64,
+ /// Can assign other members to any role
+ 'AssignMember' => 128,
+ /// Can remove members from roles
+ 'RemoveMember' => 256,
+ /// Can assign and remove abilities in roles
+ 'ChangeActions' => 512,
+ /// Can change group Charter, Insignia, 'Publish on the web' and which
+ /// members are publicly visible in group member listings
+ 'ChangeIdentity' => 1024,
+ /// Can buy land or deed land to group
+ 'LandDeed' => 2048,
+ /// Can abandon group owned land to Governor Linden on mainland, or Estate owner for
+ /// private estates
+ 'LandRelease' => 4096,
+ /// Can set land for-sale information on group owned parcels
+ 'LandSetSale' => 8192,
+ /// Can subdivide and join parcels
+ 'LandDivideJoin' => 16384,
+ /// Can join group chat sessions
+ 'JoinChat' => 32768,
+ /// Can toggle "Show in Find Places" and set search category
+ 'FindPlaces' => 65536,
+ /// Can change parcel name, description, and 'Publish on web' settings
+ 'LandChangeIdentity' => 131072,
+ /// Can set the landing point and teleport routing on group land
+ 'SetLandingPoint' => 262144,
+ /// Can change music and media settings
+ 'ChangeMedia' => 524288,
+ /// Can toggle 'Edit Terrain' option in Land settings
+ 'LandEdit' => 1048576,
+ /// Can toggle various About Land > Options settings
+ 'LandOptions' => 2097152,
+ /// Can always terraform land, even if parcel settings have it turned off
+ 'AllowEditLand' => 4194304,
+ /// Can always fly while over group owned land
+ 'AllowFly' => 8388608,
+ /// Can always rez objects on group owned land
+ 'AllowRez' => 16777216,
+ /// Can always create landmarks for group owned parcels
+ 'AllowLandmark' => 33554432,
+ /// Can use voice chat in Group Chat sessions
+ 'AllowVoiceChat' => 67108864,
+ /// Can set home location on any group owned parcel
+ 'AllowSetHome' => 134217728,
+ /// Can modify public access settings for group owned parcels
+ 'LandManageAllowed' => 268435456,
+ /// Can manager parcel ban lists on group owned land
+ 'LandManageBanned' => 536870912,
+ /// Can manage pass list sales information
+ 'LandManagePasses' => 1073741824,
+ /// Can eject and freeze other avatars on group owned land
+ 'LandEjectAndFreeze' => 2147483648,
+ /// Can return objects set to group
+ 'ReturnGroupSet' => 4294967296,
+ /// Can return non-group owned/set objects
+ 'ReturnNonGroup' => 8589934592,
+ /// Can landscape using Linden plants
+ 'LandGardening' => 17179869184,
+ /// Can deed objects to group
+ 'DeedObject' => 34359738368,
+ /// Can moderate group chat sessions
+ 'ModerateChat' => 68719476736,
+ /// Can move group owned objects
+ 'ObjectManipulate' => 137438953472,
+ /// Can set group owned objects for-sale
+ 'ObjectSetForSale' => 274877906944,
+ /// Pay group liabilities and receive group dividends
+ 'Accountable' => 549755813888,
+ /// Can send group notices
+ 'SendNotices' => 1099511627776,
+ /// Can receive group notices
+ 'ReceiveNotices' => 2199023255552,
+ /// Can create group proposals
+ 'StartProposal' => 4398046511104,
+ /// Can vote on group proposals
+ 'VoteOnProposal' => 8796093022208,
+ /// Can return group owned objects
+ 'ReturnGroupOwned' => 17592186044416
+ );
+
+
+ $uuidZero = "00000000-0000-0000-0000-000000000000";
+
+ $groupDBCon = mysqli_connect($XMLGRP_DB_HOST, $XMLGRP_DB_USER, $XMLGRP_DB_PASS, $XMLGRP_DB_NAME);
+ if (!$groupDBCon)
+ {
+ die('Could not connect: ' . mysqli_connect_error());
+ }
+
+ // This is filled in by secure()
+ $requestingAgent = $uuidZero;
+
+
+ function test()
+ {
+ return array('name' => 'Joe','age' => 27);
+ }
+
+ // Use a common signature for all the group functions -> struct foo($struct)
+ $common_sig = array(array($xmlrpcStruct, $xmlrpcStruct));
+
+
+ function createGroup($params)
+ {
+ if( is_array($error = secureRequest($params, TRUE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $groupID = $params["GroupID"];
+ $name = addslashes( $params["Name"] );
+ $charter = addslashes( $params["Charter"] );
+ $insigniaID = $params["InsigniaID"];
+ $founderID = $params["FounderID"];
+ $membershipFee = $params["MembershipFee"];
+ $openEnrollment = $params["OpenEnrollment"];
+ $showInList = $params["ShowInList"];
+ $allowPublish = $params["AllowPublish"];
+ $maturePublish = $params["MaturePublish"];
+ $ownerRoleID = $params["OwnerRoleID"];
+ $everyonePowers = $params["EveryonePowers"];
+ $ownersPowers = $params["OwnersPowers"];
+
+ // Create group
+ $sql = "INSERT INTO $osgroup
+ (GroupID, Name, Charter, InsigniaID, FounderID, MembershipFee, OpenEnrollment, ShowInList, AllowPublish, MaturePublish, OwnerRoleID)
+ VALUES
+ ('$groupID','$name','$charter','$insigniaID','$founderID',$membershipFee,$openEnrollment,$showInList,$allowPublish,$maturePublish,'$ownerRoleID')";
+
+ if (!mysqli_query($groupDBCon, $sql))
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+
+ // Create Everyone Role
+ // NOTE: FIXME: This is a temp fix until the libomv enum for group powers is fixed in OpenSim
+ $everyonePowers = 8796495740928;
+ $result = _addRoleToGroup(array('GroupID' => $groupID, 'RoleID' => $uuidZero, 'Name' => 'Everyone',
+ 'Description' => 'Everyone in the group is in the everyone role.', 'Title' => "Member of $name", 'Powers' => $everyonePowers));
+ if( isset($result['error']) )
+ {
+ return $result;
+ }
+
+ // Create Owner Role
+ $result = _addRoleToGroup(array('GroupID' => $groupID, 'RoleID' => $ownerRoleID, 'Name' => 'Owners',
+ 'Description' => "Owners of $name", 'Title' => "Owner of $name", 'Powers' => $ownersPowers));
+ if( isset($result['error']) )
+ {
+ return $result;
+ }
+
+ // Add founder to group, will automatically place them in the Everyone Role, also places them in specified Owner Role
+ $result = _addAgentToGroup(array('AgentID' => $founderID, 'GroupID' => $groupID, 'RoleID' => $ownerRoleID));
+ if( isset($result['error']) )
+ {
+ return $result;
+ }
+
+ // Select the owner's role for the founder
+ $result = _setAgentGroupSelectedRole(array('AgentID' => $founderID, 'RoleID' => $ownerRoleID, 'GroupID' => $groupID));
+ if( isset($result['error']) )
+ {
+ return $result;
+ }
+
+ // Set the new group as the founder's active group
+ $result = _setAgentActiveGroup(array('AgentID' => $founderID, 'GroupID' => $groupID));
+ if( isset($result['error']) )
+ {
+ return $result;
+ }
+
+
+ return getGroup(array("GroupID"=>$groupID));
+ }
+
+
+ // Private method, does not include security, to only be called from places that have already verified security
+ function _addRoleToGroup($params)
+ {
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $groupID = $params['GroupID'];
+ $roleID = $params['RoleID'];
+ $name = addslashes( $params['Name'] );
+ $desc = addslashes( $params['Description'] );
+ $title = addslashes( $params['Title'] );
+ $powers = $params['Powers'];
+
+ $sql = " INSERT INTO $osrole (GroupID, RoleID, Name, Description, Title, Powers) VALUES "
+ ." ('$groupID', '$roleID', '$name', '$desc', '$title', $powers)";
+
+ if (!mysqli_query($groupDBCon, $sql))
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon)
+ , 'method' => 'addRoleToGroup'
+ , 'params' => var_export($params, TRUE));
+ }
+
+ return array("success" => "true");
+ }
+
+
+ function addRoleToGroup($params)
+ {
+ if( is_array($error = secureRequest($params, TRUE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ $groupID = $params['GroupID'];
+
+ // Verify the requesting agent has permission
+ if( is_array($error = checkGroupPermission($groupID, $groupPowers['CreateRole'])) )
+ {
+ return $error;
+ }
+
+ return _addRoleToGroup($params);
+ }
+
+
+ function updateGroupRole($params)
+ {
+ if( is_array($error = secureRequest($params, TRUE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $groupID = $params['GroupID'];
+ $roleID = $params['RoleID'];
+ $name = addslashes( $params['Name'] );
+ $desc = addslashes( $params['Description'] );
+ $title = addslashes( $params['Title'] );
+ $powers = $params['Powers'];
+
+ // Verify the requesting agent has permission
+ if( is_array($error = checkGroupPermission($groupID, $groupPowers['RoleProperties'])) )
+ {
+ return $error;
+ }
+
+
+ $sql = " UPDATE $osrole SET RoleID = '$roleID' ";
+ if( isset($params['Name']) )
+ {
+ $sql .= ", Name = '$name'";
+ }
+ if( isset($params['Description']) )
+ {
+ $sql .= ", Description = '$desc'";
+ }
+ if( isset($params['Title']) )
+ {
+ $sql .= ", Title = '$title'";
+ }
+ if( isset($params['Powers']) )
+ {
+ $sql .= ", Powers = $powers";
+ }
+
+ $sql .= " WHERE GroupID = '$groupID' AND RoleID = '$roleID'";
+
+ if (!mysqli_query($groupDBCon, $sql))
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+
+ return array("success" => "true");
+ }
+
+
+ function removeRoleFromGroup($params)
+ {
+ if( is_array($error = secureRequest($params, TRUE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $groupID = $params['GroupID'];
+ $roleID = $params['RoleID'];
+
+ if( is_array($error = checkGroupPermission($groupID, $groupPowers['RoleProperties'])) )
+ {
+ return $error;
+ }
+
+ /// 1. Remove all members from Role
+ /// 2. Set selected Role to uuidZero for anyone that had the role selected
+ /// 3. Delete roll
+
+ $sql = "DELETE FROM $osgrouprolemembership WHERE GroupID = '$groupID' AND RoleID = '$roleID'";
+ if (!mysqli_query($groupDBCon, $sql))
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+
+ $sql = "UPDATE $osgroupmembership SET SelectedRoleID = '$uuidZero' WHERE GroupID = '$groupID' AND SelectedRoleID = '$roleID'";
+ if (!mysqli_query($groupDBCon, $sql))
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+
+ $sql = "DELETE FROM $osrole WHERE GroupID = '$groupID' AND RoleID = '$roleID'";
+ if (!mysqli_query($groupDBCon, $sql))
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+
+ return array("success" => "true");
+ }
+
+
+ function getGroup($params)
+ {
+ if( is_array($error = secureRequest($params, FALSE)) )
+ {
+ return $error;
+ }
+
+ return _getGroup($params);
+ }
+
+
+ function _getGroup($params)
+ {
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $sql = " SELECT $osgroup.GroupID, $osgroup.Name, Charter, InsigniaID, FounderID, MembershipFee, OpenEnrollment, ShowInList, AllowPublish, MaturePublish, OwnerRoleID"
+ ." , count($osrole.RoleID) as GroupRolesCount, count($osgroupmembership.AgentID) as GroupMembershipCount "
+ ." FROM $osgroup "
+ ." LEFT JOIN $osrole ON ($osgroup.GroupID = $osrole.GroupID)"
+ ." LEFT JOIN $osgroupmembership ON ($osgroup.GroupID = $osgroupmembership.GroupID)"
+ ." WHERE ";
+ if( isset($params['GroupID']) )
+ {
+ $sql .= "$osgroup.GroupID = '".$params['GroupID']."'";
+
+ } else if( isset($params['Name']) )
+ {
+ $sql .= "$osgroup.Name = '".addslashes($params['Name'])."'";
+ } else {
+ return array("error" => "Must specify GroupID or Name");
+ }
+
+ $sql .= " GROUP BY $osgroup.GroupID, $osgroup.name, charter, insigniaID, founderID, membershipFee, openEnrollment, showInList, allowPublish, maturePublish, ownerRoleID";
+
+ $result = mysqli_query($groupDBCon, $sql);
+
+ if (!$result)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+
+ if (mysqli_num_rows($result) == 0)
+ {
+ return array('succeed' => 'false', 'error' => 'Group Not Found', 'params' => var_export($params, TRUE), 'sql' => $sql);
+ }
+
+ return mysqli_fetch_assoc($result);
+ }
+
+
+ function updateGroup($params)
+ {
+ if( is_array($error = secureRequest($params, TRUE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $groupID = $params["GroupID"];
+ $charter = addslashes( $params["Charter"] );
+ $insigniaID = $params["InsigniaID"];
+ $membershipFee = $params["MembershipFee"];
+ $openEnrollment = $params["OpenEnrollment"];
+ $showInList = $params["ShowInList"];
+ $allowPublish = $params["AllowPublish"];
+ $maturePublish = $params["MaturePublish"];
+
+ if( is_array($error = checkGroupPermission($groupID, $groupPowers['ChangeOptions'])) )
+ {
+ return $error;
+ }
+
+ // Create group
+ $sql = "UPDATE $osgroup
+ SET
+ Charter = '$charter'
+ , InsigniaID = '$insigniaID'
+ , MembershipFee = $membershipFee
+ , OpenEnrollment= $openEnrollment
+ , ShowInList = $showInList
+ , AllowPublish = $allowPublish
+ , MaturePublish = $maturePublish
+ WHERE
+ GroupID = '$groupID'";
+
+ if (!mysqli_query($groupDBCon, $sql))
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+
+ return array('success' => 'true');
+ }
+
+
+ function findGroups($params)
+ {
+ if( is_array($error = secureRequest($params, FALSE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $search = addslashes( $params['Search'] );
+
+ // FULLTEXT indexes is not supported in InnoDB :(
+ $sql = " SELECT $osgroup.GroupID, $osgroup.Name, count($osgroupmembership.AgentID) as Members "
+ ." FROM $osgroup LEFT JOIN $osgroupmembership ON ($osgroup.GroupID = $osgroupmembership.GroupID) "
+ ." WHERE "
+ // ." ( MATCH ($osgroup.name) AGAINST ('$search' IN BOOLEAN MODE)"
+ // ." OR $osgroup.name LIKE '%$search%'"
+ // ." OR $osgroup.name REGEXP '$search'"
+ // ." ) AND ShowInList = 1"
+ ." ( $osgroup.name LIKE '%$search%'"
+ ." OR $osgroup.name REGEXP '$search'"
+ ." ) AND ShowInList = 1"
+ ." GROUP BY $osgroup.GroupID, $osgroup.Name";
+
+ $result = mysqli_query($groupDBCon, $sql);
+
+ if (!$result)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+
+ if( mysqli_num_rows($result) == 0 )
+ {
+ return array('succeed' => 'false', 'error' => 'No groups found.', 'params' => var_export($params, TRUE), 'sql' => $sql);
+ }
+
+ $results = array();
+
+ while ($row = mysqli_fetch_assoc($result))
+ {
+ $groupID = $row['GroupID'];
+ $results[$groupID] = $row;
+ }
+
+ return array('results' => $results, 'success' => TRUE);
+ }
+
+
+ function _setAgentActiveGroup($params)
+ {
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $agentID = $params['AgentID'];
+ $groupID = $params['GroupID'];
+
+ $sql = " UPDATE $osagent "
+ ." SET ActiveGroupID = '$groupID'"
+ ." WHERE AgentID = '$agentID'";
+
+ if (!mysqli_query($groupDBCon, $sql))
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+
+ if( mysqli_affected_rows($groupDBCon) == 0 )
+ {
+ $sql = " INSERT INTO $osagent (ActiveGroupID, AgentID) VALUES "
+ ." ('$groupID', '$agentID')";
+
+ if (!mysqli_query($groupDBCon, $sql))
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+ }
+
+ return array("success" => "true");
+ }
+
+
+ function setAgentActiveGroup($params)
+ {
+ if( is_array($error = secureRequest($params, TRUE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ $agentID = $params['AgentID'];
+ $groupID = $params['GroupID'];
+
+ if( isset($requestingAgent) && ($requestingAgent != $uuidZero) && ($requestingAgent != $agentID) )
+ {
+ return array('error' => "Agent can only change their own Selected Group Role", 'params' => var_export($params, TRUE));
+ }
+
+ return _setAgentActiveGroup($params);
+ }
+
+
+ function addAgentToGroup($params)
+ {
+ if( is_array($error = secureRequest($params, TRUE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $groupID = $params["GroupID"];
+ $agentID = $params["AgentID"];
+
+ if( is_array($error = checkGroupPermission($groupID, $groupPowers['AssignMember'])) )
+ {
+ // If they don't have direct permission, check to see if the group is marked for open enrollment
+ $groupInfo = _getGroup( array ('GroupID'=>$groupID) );
+
+ if( isset($groupInfo['error']))
+ {
+ return $groupInfo;
+ }
+
+ if($groupInfo['OpenEnrollment'] != 1)
+ {
+ // Group is not open enrollment, check if the specified agentid has an invite
+ $sql = " SELECT GroupID, RoleID, AgentID FROM $osgroupinvite"
+ ." WHERE $osgroupinvite.AgentID = '$agentID' AND $osgroupinvite.GroupID = '$groupID'";
+
+ $results = mysqli_query($groupDBCon, $sql);
+ if (!$results)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+
+ if( mysqli_num_rows($results) == 1 )
+ {
+ // if there is an invite, make sure we're adding the user to the role specified in the invite
+ $inviteInfo = mysqli_fetch_assoc($results);
+ $params['RoleID'] = $inviteInfo['RoleID'];
+ } else {
+ // Not openenrollment, not invited, return permission denied error
+ return $error;
+ }
+
+ }
+ }
+
+ return _addAgentToGroup($params);
+ }
+
+
+ // Private method, does not include security, to only be called from places that have already verified security
+ function _addAgentToGroup($params)
+ {
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $agentID = $params["AgentID"];
+ $groupID = $params["GroupID"];
+
+ $roleID = $uuidZero;
+ if( isset($params["RoleID"]) )
+ {
+ $roleID = $params["RoleID"];
+ }
+
+ // Check if agent already a member
+ $sql = " SELECT count(AgentID) as isMember FROM $osgroupmembership WHERE AgentID = '$agentID' AND GroupID = '$groupID'";
+ $result = mysqli_query($groupDBCon, $sql);
+ if (!$result)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+
+ // If not a member, add membership, select role (defaults to uuidZero, or everyone role)
+ //if( mysql_result($result, 0) == 0 )
+ $row = mysqli_fetch_row($result);
+ if(is_array($row) and $row[0]==0)
+ {
+ $sql = " INSERT INTO $osgroupmembership (GroupID, AgentID, Contribution, ListInProfile, AcceptNotices, SelectedRoleID) VALUES "
+ ."('$groupID','$agentID', 0, 1, 1,'$roleID')";
+
+ if (!mysqli_query($groupDBCon, $sql))
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+ }
+
+ // Make sure they're in the Everyone role
+ $result = _addAgentToGroupRole(array("GroupID" => $groupID, "RoleID" => $uuidZero, "AgentID" => $agentID));
+ if( isset($result['error']) )
+ {
+ return $result;
+ }
+
+ // Make sure they're in specified role, if they were invited
+ if( $roleID != $uuidZero )
+ {
+ $result = _addAgentToGroupRole(array("GroupID" => $groupID, "RoleID" => $roleID, "AgentID" => $agentID));
+ if( isset($result['error']) )
+ {
+ return $result;
+ }
+ }
+
+ return array("success" => "true");
+ }
+
+
+ function removeAgentFromGroup($params)
+ {
+ if( is_array($error = secureRequest($params, TRUE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $agentID = $params["AgentID"];
+ $groupID = $params["GroupID"];
+
+ if( is_array($error = checkGroupPermission($groupID, $groupPowers['RemoveMember'])) )
+ {
+ return $error;
+ }
+
+ // 1. If group is agent's active group, change active group to uuidZero
+ // 2. Remove Agent from group (osgroupmembership)
+ // 3. Remove Agent from all of the groups roles (osgrouprolemembership)
+
+ $sql = " UPDATE $osagent "
+ ." SET ActiveGroupID = '$uuidZero'"
+ ." WHERE AgentID = '$agentID' AND ActiveGroupID = '$groupID'";
+ if (!mysqli_query($groupDBCon, $sql))
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+
+ $sql = " DELETE FROM $osgroupmembership "
+ ." WHERE AgentID = '$agentID' AND GroupID = '$groupID'";
+ if (!mysqli_query($groupDBCon, $sql))
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+
+ $sql = " DELETE FROM $osgrouprolemembership "
+ ." WHERE AgentID = '$agentID' AND GroupID = '$groupID'";
+ if (!mysqli_query($groupDBCon, $sql))
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+
+ return array("success" => "true");
+ }
+
+
+ function _addAgentToGroupRole($params)
+ {
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $agentID = $params["AgentID"];
+ $groupID = $params["GroupID"];
+ $roleID = $params["RoleID"];
+
+ // Check if agent already a member
+ $sql = " SELECT count(AgentID) as isMember FROM $osgrouprolemembership WHERE AgentID = '$agentID' AND RoleID = '$roleID' AND GroupID = '$groupID'";
+ $result = mysqli_query($groupDBCon, $sql);
+ if (!$result)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+
+ //if( mysql_result($result, 0) == 0 )
+ $row = mysqli_fetch_row($result);
+ if(is_array($row) and $row[0]==0)
+ {
+ $sql = " INSERT INTO $osgrouprolemembership (GroupID, RoleID, AgentID) VALUES "
+ ."('$groupID', '$roleID', '$agentID')";
+
+ if (!mysqli_query($groupDBCon, $sql))
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+ }
+
+ return array("success" => "true");
+ }
+
+
+ function addAgentToGroupRole($params)
+ {
+ if( is_array($error = secureRequest($params, TRUE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $agentID = $params["AgentID"];
+ $groupID = $params["GroupID"];
+ $roleID = $params["RoleID"];
+
+ // Check if being assigned to Owners role, assignments to an owners role can only be requested by owners.
+ $sql = " SELECT OwnerRoleID, AgentID "
+ ." FROM $osgroup LEFT JOIN $osgrouprolemembership ON ($osgroup.GroupID = $osgrouprolemembership.GroupID AND $osgroup.OwnerRoleID = $osgrouprolemembership.RoleID) "
+ ." WHERE $osgrouprolemembership.AgentID = '$agentID' AND $osgroup.GroupID = '$groupID'";
+
+ $results = mysqli_query($groupDBCon, $sql);
+ if (!$results)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+
+ if( mysqli_num_rows($results) != 0 )
+ {
+ $ownerRoleInfo = mysqli_fetch_assoc($results);
+ if( ($ownerRoleInfo['OwnerRoleID'] == $roleID) && ($ownerRoleInfo['AgentID'] != $requestingAgent) )
+ {
+ return array('error' => "Requesting agent $requestingAgent is not a member of the Owners Role and cannot add members to the owners role.",
+ 'params' => var_export($params, TRUE));
+ }
+ }
+
+ if( is_array($error = checkGroupPermission($groupID, $groupPowers['AssignMember'])) )
+ {
+ return $error;
+ }
+
+ return _addAgentToGroupRole($params);
+ }
+
+
+ function removeAgentFromGroupRole($params)
+ {
+ if( is_array($error = secureRequest($params, TRUE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $agentID = $params["AgentID"];
+ $groupID = $params["GroupID"];
+ $roleID = $params["RoleID"];
+
+ if( is_array($error = checkGroupPermission($groupID, $groupPowers['AssignMember'])) )
+ {
+ return $error;
+ }
+
+ // If agent has this role selected, change their selection to everyone (uuidZero) role
+ $sql = " UPDATE $osgroupmembership SET SelectedRoleID = '$uuidZero' WHERE AgentID = '$agentID' AND GroupID = '$groupID' AND SelectedRoleID = '$roleID'";
+ $result = mysqli_query($groupDBCon, $sql);
+ if (!$result)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+
+ $sql = " DELETE FROM $osgrouprolemembership WHERE AgentID = '$agentID' AND GroupID = '$groupID' AND RoleID = '$roleID'";
+
+ if (!mysqli_query($groupDBCon, $sql))
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+
+ return array("success" => "true");
+ }
+
+
+ function _setAgentGroupSelectedRole($params)
+ {
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $agentID = $params["AgentID"];
+ $groupID = $params["GroupID"];
+ $roleID = $params["RoleID"];
+
+ $sql = " UPDATE $osgroupmembership SET SelectedRoleID = '$roleID' WHERE AgentID = '$agentID' AND GroupID = '$groupID'";
+ $result = mysqli_query($groupDBCon, $sql);
+ if (!$result)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+
+ return array('success' => 'true');
+ }
+
+
+ function setAgentGroupSelectedRole($params)
+ {
+ if( is_array($error = secureRequest($params, TRUE)) )
+ {
+ return $error;
+ }
+
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ $agentID = $params["AgentID"];
+ $groupID = $params["GroupID"];
+ $roleID = $params["RoleID"];
+
+ if( isset($requestingAgent) && ($requestingAgent != $uuidZero) && ($requestingAgent != $agentID) )
+ {
+ return array('error' => "Agent can only change their own Selected Group Role", 'params' => var_export($params, TRUE));
+ }
+
+ return _setAgentGroupSelectedRole($params);
+ }
+
+
+ function getAgentGroupMembership($params)
+ {
+ if( is_array($error = secureRequest($params, FALSE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $groupID = $params['GroupID'];
+ $agentID = $params['AgentID'];
+
+ $sql = " SELECT $osgroup.GroupID, $osgroup.Name as GroupName, $osgroup.Charter, $osgroup.InsigniaID, $osgroup.FounderID"
+ ." , $osgroup.MembershipFee, $osgroup.OpenEnrollment, $osgroup.ShowInList, $osgroup.AllowPublish, $osgroup.MaturePublish"
+ ." , $osgroupmembership.Contribution, $osgroupmembership.ListInProfile, $osgroupmembership.AcceptNotices"
+ ." , $osgroupmembership.SelectedRoleID, $osrole.Title"
+ ." , $osagent.ActiveGroupID "
+ ." FROM $osgroup JOIN $osgroupmembership ON ($osgroup.GroupID = $osgroupmembership.GroupID)"
+ ." JOIN $osrole ON ($osgroupmembership.SelectedRoleID = $osrole.RoleID AND $osgroupmembership.GroupID = $osrole.GroupID)"
+ ." JOIN $osagent ON ($osagent.AgentID = $osgroupmembership.AgentID)"
+ ." WHERE $osgroup.GroupID = '$groupID' AND $osgroupmembership.AgentID = '$agentID'";
+
+ $groupmembershipResult = mysqli_query($groupDBCon, $sql);
+ if (!$groupmembershipResult)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+
+ if( mysqli_num_rows($groupmembershipResult) == 0 )
+ {
+ return array('succeed' => 'false', 'error' => 'None Found', 'params' => var_export($params, TRUE), 'sql' => $sql);
+ }
+
+ $groupMembershipInfo = mysqli_fetch_assoc($groupmembershipResult);
+
+ $sql = " SELECT BIT_OR($osrole.Powers) AS GroupPowers"
+ ." FROM $osgrouprolemembership JOIN $osrole ON ($osgrouprolemembership.GroupID = $osrole.GroupID AND $osgrouprolemembership.RoleID = $osrole.RoleID)"
+ ." WHERE $osgrouprolemembership.GroupID = '$groupID' AND $osgrouprolemembership.AgentID = '$agentID'";
+ $groupPowersResult = mysqli_query($groupDBCon, $sql);
+ if (!$groupPowersResult)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+ $groupPowersInfo = mysqli_fetch_assoc($groupPowersResult);
+
+ return array_merge($groupMembershipInfo, $groupPowersInfo);
+ }
+
+
+ function getAgentGroupMemberships($params)
+ {
+ if( is_array($error = secureRequest($params, FALSE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+ $agentID = $params['AgentID'];
+
+ $sql = " SELECT $osgroup.GroupID, $osgroup.Name as GroupName, $osgroup.Charter, $osgroup.InsigniaID, $osgroup.FounderID"
+ ." , $osgroup.MembershipFee, $osgroup.OpenEnrollment, $osgroup.ShowInList, $osgroup.AllowPublish, $osgroup.MaturePublish"
+ ." , $osgroupmembership.Contribution, $osgroupmembership.ListInProfile, $osgroupmembership.AcceptNotices"
+ ." , $osgroupmembership.SelectedRoleID, $osrole.Title"
+ ." , IFNULL($osagent.ActiveGroupID, '$uuidZero') AS ActiveGroupID"
+ ." FROM $osgroup JOIN $osgroupmembership ON ($osgroup.GroupID = $osgroupmembership.GroupID)"
+ ." JOIN $osrole ON ($osgroupmembership.SelectedRoleID = $osrole.RoleID AND $osgroupmembership.GroupID = $osrole.GroupID)"
+ ." LEFT JOIN $osagent ON ($osagent.AgentID = $osgroupmembership.AgentID)"
+ ." WHERE $osgroupmembership.AgentID = '$agentID'";
+
+ $groupmembershipResults = mysqli_query($groupDBCon, $sql);
+ if (!$groupmembershipResults)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+
+ if( mysqli_num_rows($groupmembershipResults) == 0 )
+ {
+ return array('succeed' => 'false', 'error' => 'No Memberships', 'params' => var_export($params, TRUE), 'sql' => $sql);
+
+ }
+
+ $groupResults = array();
+ while($groupMembershipInfo = mysqli_fetch_assoc($groupmembershipResults))
+ {
+ $groupID = $groupMembershipInfo['GroupID'];
+ $sql = " SELECT BIT_OR($osrole.Powers) AS GroupPowers"
+ ." FROM $osgrouprolemembership JOIN $osrole ON ($osgrouprolemembership.GroupID = $osrole.GroupID AND $osgrouprolemembership.RoleID = $osrole.RoleID)"
+ ." WHERE $osgrouprolemembership.GroupID = '$groupID' AND $osgrouprolemembership.AgentID = '$agentID'";
+ $groupPowersResult = mysqli_query($groupDBCon, $sql);
+ if (!$groupPowersResult)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+ $groupPowersInfo = mysqli_fetch_assoc($groupPowersResult);
+ $groupResults[$groupID] = array_merge($groupMembershipInfo, $groupPowersInfo);
+ }
+
+ return $groupResults;
+ }
+
+
+ function getGroupMembers($params)
+ {
+ if( is_array($error = secureRequest($params, FALSE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $groupID = $params['GroupID'];
+
+ $sql = " SELECT $osgroupmembership.AgentID"
+ ." , $osgroupmembership.Contribution, $osgroupmembership.ListInProfile, $osgroupmembership.AcceptNotices"
+ ." , $osgroupmembership.SelectedRoleID, $osrole.Title"
+ ." , CASE WHEN OwnerRoleMembership.AgentID IS NOT NULL THEN 1 ELSE 0 END AS IsOwner"
+ ." FROM $osgroup JOIN $osgroupmembership ON ($osgroup.GroupID = $osgroupmembership.GroupID)"
+ ." JOIN $osrole ON ($osgroupmembership.SelectedRoleID = $osrole.RoleID AND $osgroupmembership.GroupID = $osrole.GroupID)"
+ ." JOIN $osrole AS OwnerRole ON ($osgroup.OwnerRoleID = OwnerRole.RoleID AND $osgroup.GroupID = OwnerRole.GroupID)"
+ ." LEFT JOIN $osgrouprolemembership AS OwnerRoleMembership ON ($osgroup.OwnerRoleID = OwnerRoleMembership.RoleID
+ AND ($osgroup.GroupID = OwnerRoleMembership.GroupID)
+ AND ($osgroupmembership.AgentID = OwnerRoleMembership.AgentID))"
+ ." WHERE $osgroup.GroupID = '$groupID'";
+
+ $groupmemberResults = mysqli_query($groupDBCon, $sql);
+ if (!$groupmemberResults)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+
+ if (mysqli_num_rows($groupmemberResults) == 0)
+ {
+ return array('succeed' => 'false', 'error' => 'No Group Members found', 'params' => var_export($params, TRUE), 'sql' => $sql);
+ }
+
+ $memberResults = array();
+ while($memberInfo = mysqli_fetch_assoc($groupmemberResults))
+ {
+ $agentID = $memberInfo['AgentID'];
+ $sql = " SELECT BIT_OR($osrole.Powers) AS AgentPowers"
+ ." FROM $osgrouprolemembership JOIN $osrole ON ($osgrouprolemembership.GroupID = $osrole.GroupID AND $osgrouprolemembership.RoleID = $osrole.RoleID)"
+ ." WHERE $osgrouprolemembership.GroupID = '$groupID' AND $osgrouprolemembership.AgentID = '$agentID'";
+ $memberPowersResult = mysqli_query($groupDBCon, $sql);
+ if (!$memberPowersResult)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+
+ if (mysqli_num_rows($groupmemberResults) == 0)
+ {
+ $memberResults[$agentID] = array_merge($memberInfo, array('AgentPowers' => 0));
+ } else {
+ $memberPowersInfo = mysqli_fetch_assoc($memberPowersResult);
+ $memberResults[$agentID] = array_merge($memberInfo, $memberPowersInfo);
+ }
+ }
+
+ return $memberResults;
+ }
+
+
+ function getAgentActiveMembership($params)
+ {
+ if( is_array($error = secureRequest($params, FALSE)) )
+ {
+ return $error;
+ }
+
+ secureRequest($params, FALSE);
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $agentID = $params['AgentID'];
+
+ $sql = " SELECT $osgroup.GroupID, $osgroup.Name as GroupName, $osgroup.Charter, $osgroup.InsigniaID, $osgroup.FounderID"
+ ." , $osgroup.MembershipFee, $osgroup.OpenEnrollment, $osgroup.ShowInList, $osgroup.AllowPublish, $osgroup.MaturePublish"
+ ." , $osgroupmembership.Contribution, $osgroupmembership.ListInProfile, $osgroupmembership.AcceptNotices"
+ ." , $osgroupmembership.SelectedRoleID, $osrole.Title"
+ ." , $osagent.ActiveGroupID "
+ ." FROM $osagent JOIN $osgroup ON ($osgroup.GroupID = $osagent.ActiveGroupID)"
+ ." JOIN $osgroupmembership ON ($osgroup.GroupID = $osgroupmembership.GroupID AND $osagent.AgentID = $osgroupmembership.AgentID)"
+ ." JOIN $osrole ON ($osgroupmembership.SelectedRoleID = $osrole.RoleID AND $osgroupmembership.GroupID = $osrole.GroupID)"
+ ." WHERE $osagent.AgentID = '$agentID'";
+
+ $groupmembershipResult = mysqli_query($groupDBCon, $sql);
+ if (!$groupmembershipResult)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+ if (mysqli_num_rows($groupmembershipResult) == 0)
+ {
+ return array('succeed' => 'false', 'error' => 'No Active Group Specified', 'params' => var_export($params, TRUE), 'sql' => $sql);
+ }
+ $groupMembershipInfo = mysqli_fetch_assoc($groupmembershipResult);
+
+ $groupID = $groupMembershipInfo['GroupID'];
+ $sql = " SELECT BIT_OR($osrole.Powers) AS GroupPowers"
+ ." FROM $osgrouprolemembership JOIN $osrole ON ($osgrouprolemembership.GroupID = $osrole.GroupID AND $osgrouprolemembership.RoleID = $osrole.RoleID)"
+ ." WHERE $osgrouprolemembership.GroupID = '$groupID' AND $osgrouprolemembership.AgentID = '$agentID'";
+ $groupPowersResult = mysqli_query($groupDBCon, $sql);
+ if (!$groupPowersResult)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+ $groupPowersInfo = mysqli_fetch_assoc($groupPowersResult);
+
+ return array_merge($groupMembershipInfo, $groupPowersInfo);
+ }
+
+
+ function getAgentRoles($params=null)
+ {
+ if( is_array($error = secureRequest($params, FALSE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $agentID = $params['AgentID'];
+
+ $sql = " SELECT "
+ ." $osrole.RoleID, $osrole.GroupID, $osrole.Title, $osrole.Name, $osrole.Description, $osrole.Powers"
+ ." , CASE WHEN $osgroupmembership.SelectedRoleID = $osrole.RoleID THEN 1 ELSE 0 END AS Selected"
+ ." FROM $osgroupmembership JOIN $osgrouprolemembership ON ($osgroupmembership.GroupID = $osgrouprolemembership.GroupID"
+ ." AND $osgroupmembership.AgentID = $osgrouprolemembership.AgentID)"
+ ." JOIN $osrole ON ( $osgrouprolemembership.RoleID = $osrole.RoleID AND $osgrouprolemembership.GroupID = $osrole.GroupID)"
+ ." LEFT JOIN $osagent ON ($osagent.AgentID = $osgroupmembership.AgentID)"
+ ." WHERE $osgroupmembership.AgentID = '$agentID'";
+
+ if( isset($params['GroupID']) )
+ {
+ $groupID = $params['GroupID'];
+ $sql .= " AND $osgroupmembership.GroupID = '$groupID'";
+ }
+
+ $roleResults = mysqli_query($groupDBCon, $sql);
+ if (!$roleResults)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+
+ if( mysqli_num_rows($roleResults) == 0 )
+ {
+ return array('succeed' => 'false', 'error' => 'None found', 'params' => var_export($params, TRUE), 'sql' => $sql);
+ }
+
+ $roles = array();
+ while($role = mysqli_fetch_assoc($roleResults))
+ {
+ $ID = $role['GroupID'].$role['RoleID'];
+ $roles[$ID] = $role;
+ }
+
+ return $roles;
+ }
+
+
+ function getGroupRoles($params)
+ {
+ if( is_array($error = secureRequest($params, FALSE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $groupID = $params['GroupID'];
+
+ $sql = " SELECT "
+ ." $osrole.RoleID, $osrole.Name, $osrole.Title, $osrole.Description, $osrole.Powers, count($osgrouprolemembership.AgentID) as Members"
+ ." FROM $osrole LEFT JOIN $osgrouprolemembership ON ($osrole.GroupID = $osgrouprolemembership.GroupID AND $osrole.RoleID = $osgrouprolemembership.RoleID)"
+ ." WHERE $osrole.GroupID = '$groupID'"
+ ." GROUP BY $osrole.RoleID, $osrole.Name, $osrole.Title, $osrole.Description, $osrole.Powers";
+
+ $roleResults = mysqli_query($groupDBCon, $sql);
+ if (!$roleResults)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+
+ if( mysqli_num_rows($roleResults) == 0 )
+ {
+ return array('succeed' => 'false', 'error' => 'No roles found for group', 'params' => var_export($params, TRUE), 'sql' => $sql);
+ }
+
+ $roles = array();
+ while($role = mysqli_fetch_assoc($roleResults))
+ {
+ $RoleID = $role['RoleID'];
+ $roles[$RoleID] = $role;
+ }
+
+ return $roles;
+ }
+
+
+ function getGroupRoleMembers($params)
+ {
+ if( is_array($error = secureRequest($params, FALSE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $groupID = $params['GroupID'];
+ // $roleID = $params['RoleID'];
+
+ $sql = " SELECT "
+ ." $osrole.RoleID, $osgrouprolemembership.AgentID"
+ ." FROM $osrole JOIN $osgrouprolemembership ON ($osrole.GroupID = $osgrouprolemembership.GroupID AND $osrole.RoleID = $osgrouprolemembership.RoleID)"
+ ." WHERE $osrole.GroupID = '$groupID'";
+// ." AND $osrole.RoleID = '$roleID'";
+
+ $memberResults = mysqli_query($groupDBCon, $sql);
+ if (!$memberResults)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+
+ $members = array();
+ while($member = mysqli_fetch_assoc($memberResults))
+ {
+ $Key = $member['AgentID'] . $member['RoleID'];
+ $members[$Key ] = $member;
+ }
+
+ return $members;
+ }
+
+
+ function setAgentGroupInfo($params)
+ {
+ if( is_array($error = secureRequest($params, TRUE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ if (isset($params['AgentID'])) {
+ $agentID = $params['AgentID'];
+ } else {
+ $agentID = "";
+ }
+ if (isset($params['GroupID'])) {
+ $groupID = $params['GroupID'];
+ } else {
+ $groupID = "";
+ }
+ if (isset($params['SelectedRoleID'])) {
+ $roleID = $params['SelectedRoleID'];
+ } else {
+ $roleID = "";
+ }
+ if (isset($params['AcceptNotice'])) {
+ $acceptNotices = $params['AcceptNotices'];
+ } else {
+ $acceptNotices = "";
+ }
+ if (isset($params['ListInProfile'])) {
+ $listInProfile = $params['ListInProfile'];
+ } else {
+ $listInProfile = "";
+ }
+
+ if( isset($requestingAgent) && ($requestingAgent != $uuidZero) && ($requestingAgent != $agentID) )
+ {
+ return array('error' => "Agent can only change their own group info", 'params' => var_export($params, TRUE));
+ }
+
+ $sql = " UPDATE "
+ ." $osgroupmembership"
+ ." SET "
+ ." AgentID = '$agentID'";
+
+ if( isset($params['SelectedRoleID']) )
+ {
+ $sql .=" , SelectedRoleID = '$roleID'";
+ }
+ if( isset($params['AcceptNotices']) )
+ {
+ $sql .=" , AcceptNotices = '$acceptNotices'";
+ }
+ if( isset($params['ListInProfile']) )
+ {
+ $sql .=" , ListInProfile = '$listInProfile'";
+ }
+
+ $sql .=" WHERE $osgroupmembership.GroupID = '$groupID' AND $osgroupmembership.AgentID = '$agentID'";
+
+ $memberResults = mysqli_query($groupDBCon, $sql);
+ if (!$memberResults)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+
+ return array('success'=> 'true');
+ }
+
+
+ function getGroupNotices($params)
+ {
+ if( is_array($error = secureRequest($params, FALSE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $groupID = $params['GroupID'];
+
+
+ $sql = " SELECT "
+ ." GroupID, NoticeID, Timestamp, FromName, Subject, Message, BinaryBucket"
+ ." FROM $osgroupnotice"
+ ." WHERE $osgroupnotice.GroupID = '$groupID'";
+
+ $results = mysqli_query($groupDBCon, $sql);
+ if (!$results)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+
+ if( mysqli_num_rows($results) == 0 )
+ {
+ return array('succeed' => 'false', 'error' => 'No Notices', 'params' => var_export($params, TRUE), 'sql' => $sql);
+ }
+
+ $notices = array();
+ while($notice = mysqli_fetch_assoc($results))
+ {
+ $NoticeID = $notice['NoticeID'];
+ $notices[$NoticeID] = $notice;
+ }
+
+ return $notices;
+ }
+
+
+ function getGroupNotice($params)
+ {
+ if( is_array($error = secureRequest($params, FALSE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $noticeID = $params['NoticeID'];
+
+
+ $sql = " SELECT "
+ ." GroupID, NoticeID, Timestamp, FromName, Subject, Message, BinaryBucket"
+ ." FROM $osgroupnotice"
+ ." WHERE $osgroupnotice.NoticeID = '$noticeID'";
+
+ $results = mysqli_query($groupDBCon, $sql);
+ if (!$results)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+
+ if( mysqli_num_rows($results) == 0 )
+ {
+ return array('succeed' => 'false', 'error' => 'Group Notice Not Found', 'params' => var_export($params, TRUE), 'sql' => $sql);
+ }
+
+ return mysqli_fetch_assoc($results);
+ }
+
+
+ function addGroupNotice($params)
+ {
+ if( is_array($error = secureRequest($params, TRUE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $groupID = $params['GroupID'];
+ $noticeID = $params['NoticeID'];
+ $fromName = addslashes($params['FromName']);
+ $subject = addslashes($params['Subject']);
+ $binaryBucket = $params['BinaryBucket'];
+ $message = addslashes($params['Message']);
+ $timeStamp = $params['TimeStamp'];
+
+ if( is_array($error = checkGroupPermission($groupID, $groupPowers['SendNotices'])) )
+ {
+ return $error;
+ }
+
+ $sql = " INSERT INTO $osgroupnotice"
+ ." (GroupID, NoticeID, Timestamp, FromName, Subject, Message, BinaryBucket)"
+ ." VALUES "
+ ." ('$groupID', '$noticeID', $timeStamp, '$fromName', '$subject', '$message', '$binaryBucket')";
+
+ $results = mysqli_query($groupDBCon, $sql);
+ if (!$results)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+
+ return array('success' => 'true');
+ }
+
+
+ function addAgentToGroupInvite($params)
+ {
+ if( is_array($error = secureRequest($params, TRUE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $inviteID = $params['InviteID'];
+ $groupID = $params['GroupID'];
+ $roleID = $params['RoleID'];
+ $agentID = $params['AgentID'];
+ //$tmStamp = time();
+ $tmStamp = 0;
+
+ if( is_array($error = checkGroupPermission($groupID, $groupPowers['AssignMember'])) )
+ {
+ return $error;
+ }
+
+ // Remove any existing invites for this agent to this group
+ $sql = " DELETE FROM $osgroupinvite"
+ ." WHERE $osgroupinvite.AgentID = '$agentID' AND $osgroupinvite.GroupID = '$groupID'";
+
+ $results = mysqli_query($groupDBCon, $sql);
+ if (!$results)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+
+ // Add new invite for this agent to this group for the specifide role
+ $sql = " INSERT INTO $osgroupinvite"
+ ." (InviteID, GroupID, RoleID, AgentID, tmstamp) VALUES ('$inviteID', '$groupID', '$roleID', '$agentID', '$tmStamp')";
+
+ $results = mysqli_query($groupDBCon, $sql);
+ if (!$results)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+
+ return array('success' => 'true');
+ }
+
+
+ function getAgentToGroupInvite($params)
+ {
+ if( is_array($error = secureRequest($params, FALSE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $inviteID = $params['InviteID'];
+
+
+ $sql = " SELECT GroupID, RoleID, AgentID FROM $osgroupinvite"
+ ." WHERE $osgroupinvite.InviteID = '$inviteID'";
+
+ $results = mysqli_query($groupDBCon, $sql);
+ if (!$results)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+
+ if( mysqli_num_rows($results) == 1 )
+ {
+ $inviteInfo = mysqli_fetch_assoc($results);
+ $groupID = $inviteInfo['GroupID'];
+ $roleID = $inviteInfo['RoleID'];
+ $agentID = $inviteInfo['AgentID'];
+
+ return array('success' => 'true', 'GroupID'=>$groupID, 'RoleID'=>$roleID, 'AgentID'=>$agentID);
+ } else {
+ return array('succeed' => 'false', 'error' => 'Invitation not found', 'params' => var_export($params, TRUE), 'sql' => $sql);
+ }
+ }
+
+
+ function removeAgentToGroupInvite($params)
+ {
+ if( is_array($error = secureRequest($params, TRUE)) )
+ {
+ return $error;
+ }
+
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+ global $osagent, $osgroup, $osgroupinvite, $osgroupmembership, $osgroupnotice, $osgrouprolemembership, $osrole;
+
+ $inviteID = $params['InviteID'];
+
+ $sql = " DELETE FROM $osgroupinvite"
+ ." WHERE $osgroupinvite.InviteID = '$inviteID'";
+
+ $results = mysqli_query($groupDBCon, $sql);
+ if (!$results)
+ {
+ return array('error' => "Could not successfully run query ($sql) from DB: " . mysqli_error($groupDBCon), 'params' => var_export($params, TRUE));
+ }
+
+ return array('success' => 'true');
+ }
+
+
+ function secureRequest($params, $write = FALSE)
+ {
+ global $GroupWriteKey, $GroupReadKey, $VerifiedReadKey, $VerifiedWriteKey, $GroupRequireAgentAuthForWrite, $requestingAgent;
+
+ if( isset($GroupReadKey) && ($GroupReadKey != '') && (!isset($VerifiedReadKey) || ($VerifiedReadKey !== TRUE)) )
+ {
+ if( !isset($params['ReadKey']) || ($params['ReadKey'] != $GroupReadKey ) )
+ {
+ return array('error' => "Invalid (or No) Read Key Specified", 'params' => var_export($params, TRUE));
+ } else {
+ $VerifiedReadKey = TRUE;
+ }
+ }
+
+ if( ($write == TRUE) && isset($GroupWriteKey) && ($GroupWriteKey != '') && (!isset($VerifiedWriteKey) || ($VerifiedWriteKey !== TRUE)) )
+ {
+ if( !isset($params['WriteKey']) || ($params['WriteKey'] != $GroupWriteKey ) )
+ {
+ return array('error' => "Invalid (or No) Write Key Specified", 'params' => var_export($params, TRUE));
+ } else {
+ $VerifiedWriteKey = TRUE;
+ }
+ }
+
+ if( ($write == TRUE) && isset($GroupRequireAgentAuthForWrite) && ($GroupRequireAgentAuthForWrite == TRUE) )
+ {
+ // Note: my brain can't do boolean logic this morning, so just putting this here instead of integrating with line above.
+ // If the write key has already been verified for this request, don't check it again.
+ // This comes into play with methods that call other methods, such as CreateGroup() which calls Addrole()
+ if( isset($VerifiedWriteKey) && ($VerifiedWriteKey !== TRUE))
+ {
+ return TRUE;
+ }
+
+ if( !isset($params['RequestingAgentID'])
+ || !isset($params['RequestingAgentUserService'])
+ || !isset($params['RequestingSessionID'])
+ )
+ {
+ return array('error' => "Requesting AgentID and SessionID must be specified", 'params' => var_export($params, TRUE));
+ }
+
+ $requestingAgent = $params['RequestingAgentID'];
+
+ // NOTE: an AgentID and SessionID of $uuidZero will likely be a region making a request, that is not tied to a specific agent making the request.
+
+ $client = new xmlrpc_client($params['RequestingAgentUserService']);
+ $client->return_type = 'phpvals';
+
+ $verifyParams = new xmlrpcval(array('avatar_uuid' => new xmlrpcval($params['RequestingAgentID'], 'string')
+ ,'session_id' => new xmlrpcval($params['RequestingSessionID'], 'string')), 'struct');
+
+ $message = new xmlrpcmsg("check_auth_session", array($verifyParams));
+ $resp = $client->send($message, 5);
+ if ($resp->faultCode())
+ {
+ return array('error' => "Error validating AgentID and SessionID"
+ , 'xmlrpcerror'=> $resp->faultString()
+ , 'params' => var_export($params, TRUE));
+ }
+
+ $verifyReturn = $resp->value();
+
+ if( !isset($verifyReturn['auth_session']) || ($verifyReturn['auth_session'] != 'TRUE') )
+ {
+ return array('error' => "UserService.check_auth_session() did not return TRUE"
+ , 'userservice' => var_export($verifyReturn, TRUE)
+ , 'params' => var_export($params, TRUE));
+
+ }
+ }
+
+ return TRUE;
+ }
+
+
+ function checkGroupPermission($GroupID, $Permission)
+ {
+ global $GroupEnforceGroupPerms, $requestingAgent, $uuidZero, $groupDBCon, $groupPowers;
+
+ // If it isn't set to true, then always return true, otherwise verify they have perms
+ if( !isset($GroupEnforceGroupPerms) || ($GroupEnforceGroupPerms != TRUE) )
+ {
+ return true;
+ }
+
+ if( !isset($requestingAgent) || ($requestingAgent == $uuidZero) )
+ {
+ return array('error' => 'Requesting agent was either not specified or not validated.'
+ , 'params' => var_export($params, TRUE));
+ }
+
+ $params = array('AgentID' => $requestingAgent, 'GroupID' => $GroupID);
+ $reqAgentMembership = getAgentGroupMembership($params);
+
+ if( isset($reqAgentMembership['error'] ) )
+ {
+ return array('error' => 'Could not get agent membership for group'
+ , 'params' => var_export($params, TRUE)
+ , 'nestederror' => $reqAgentMembership['error']);
+ }
+
+ if( $reqAgentMembership['GroupPowers'] & $Permission != $Permission )
+ {
+ return array('error' => 'Agent does not have group power to $Permission'
+ , 'params' => var_export($params, TRUE));
+ }
+ }
+
+ $s = new xmlrpc_server(array(
+ "test" => array("function" => "test")
+ , "groups.createGroup" => array("function" => "createGroup", "signature" => $common_sig)
+ , "groups.updateGroup" => array("function" => "updateGroup", "signature" => $common_sig)
+ , "groups.getGroup" => array("function" => "getGroup", "signature" => $common_sig)
+ , "groups.findGroups" => array("function" => "findGroups", "signature" => $common_sig)
+
+ , "groups.getGroupRoles" => array("function" => "getGroupRoles", "signature" => $common_sig)
+ , "groups.addRoleToGroup" => array("function" => "addRoleToGroup", "signature" => $common_sig)
+ , "groups.removeRoleFromGroup" => array("function" => "removeRoleFromGroup", "signature" => $common_sig)
+ , "groups.updateGroupRole" => array("function" => "updateGroupRole", "signature" => $common_sig)
+ , "groups.getGroupRoleMembers" => array("function" => "getGroupRoleMembers", "signature" => $common_sig)
+
+ , "groups.setAgentGroupSelectedRole" => array("function" => "setAgentGroupSelectedRole", "signature" => $common_sig)
+ , "groups.addAgentToGroupRole" => array("function" => "addAgentToGroupRole", "signature" => $common_sig)
+ , "groups.removeAgentFromGroupRole" => array("function" => "removeAgentFromGroupRole", "signature" => $common_sig)
+
+ , "groups.getGroupMembers" => array("function" => "getGroupMembers", "signature" => $common_sig)
+ , "groups.addAgentToGroup" => array("function" => "addAgentToGroup", "signature" => $common_sig)
+ , "groups.removeAgentFromGroup" => array("function" => "removeAgentFromGroup", "signature" => $common_sig)
+ , "groups.setAgentGroupInfo" => array("function" => "setAgentGroupInfo", "signature" => $common_sig)
+
+ , "groups.addAgentToGroupInvite" => array("function" => "addAgentToGroupInvite", "signature" => $common_sig)
+ , "groups.getAgentToGroupInvite" => array("function" => "getAgentToGroupInvite", "signature" => $common_sig)
+ , "groups.removeAgentToGroupInvite" => array("function" => "removeAgentToGroupInvite", "signature" => $common_sig)
+
+ , "groups.setAgentActiveGroup" => array("function" => "setAgentActiveGroup", "signature" => $common_sig)
+ , "groups.getAgentGroupMembership" => array("function" => "getAgentGroupMembership", "signature" => $common_sig)
+ , "groups.getAgentGroupMemberships" => array("function" => "getAgentGroupMemberships", "signature" => $common_sig)
+ , "groups.getAgentActiveMembership" => array("function" => "getAgentActiveMembership", "signature" => $common_sig)
+ , "groups.getAgentRoles" => array("function" => "getAgentRoles", "signature" => $common_sig)
+
+ , "groups.getGroupNotices" => array("function" => "getGroupNotices", "signature" => $common_sig)
+ , "groups.getGroupNotice" => array("function" => "getGroupNotice", "signature" => $common_sig)
+ , "groups.addGroupNotice" => array("function" => "addGroupNotice", "signature" => $common_sig)
+
+ ), false);
+
+ $s->functions_parameters_type = 'phpvals';
+ if (isset($debugXMLRPC) && $debugXMLRPC > 0 && isset($debugXMLRPCFile) && $debugXMLRPCFile != "")
+ {
+ $s->setDebug($debugXMLRPC);
+ }
+ $s->service();
+
+ if (isset($debugXMLRPC) && $debugXMLRPC > 0 && isset($debugXMLRPCFile) && $debugXMLRPCFile != "")
+ {
+ $f = fopen($debugXMLRPCFile,"a");
+ fwrite($f,"\n----- " . date("Y-m-d H:i:s") . " -----\n");
+ $debugInfo = $s->serializeDebug();
+ //$debugInfo = split("\n",$debugInfo);
+ $debugInfo = explode("\n",$debugInfo);
+ unset($debugInfo[0]);
+ unset($debugInfo[count($debugInfo) -1]);
+ $debugInfo = join("\n",$debugInfo);
+ fwrite($f,base64_decode($debugInfo));
+ fclose($f);
+ }
+
+ mysqli_close($groupDBCon);
+
diff --git a/helper-php/DTLNSL_helper_scripts/include/config.php b/helper-php/DTLNSL_helper_scripts/include/config.php
new file mode 100644
index 0000000..2eb3052
--- /dev/null
+++ b/helper-php/DTLNSL_helper_scripts/include/config.php
@@ -0,0 +1,78 @@
+history.go(-1);
diff --git a/helper-php/DTLNSL_helper_scripts/include/jbxl_tools.php b/helper-php/DTLNSL_helper_scripts/include/jbxl_tools.php
new file mode 100644
index 0000000..7714852
--- /dev/null
+++ b/helper-php/DTLNSL_helper_scripts/include/jbxl_tools.php
@@ -0,0 +1,309 @@
+ SubnetMask
+ $cider = $sub[0];
+ $nbyte = (int)($cider/8);
+ $nbit = $cider - $nbyte*8;
+ for ($i=0; $i<$nbyte; $i++) {
+ $sub[$i] = 255;
+ }
+ if ($nbyte!=4) {
+ $nsub = 0;
+ $base = 128;
+ for ($i=0; $i<$nbit; $i++) {
+ $nsub += $base;
+ $base = $base/2;
+ }
+ $sub[$nbyte] = $nsub;
+ }
+ }
+
+ for ($i=0; $i<4; $i++) {
+ if (!empty($ips[$i])) $return[$index]['ipaddr'][$i] = (int)$ips[$i];
+ else $return[$index]['ipaddr'][$i] = (int)0;
+ if (!empty($sub[$i])) $return[$index]['subnet'][$i] = (int)$sub[$i];
+ else $return[$index]['subnet'][$i] = (int)0;
+ }
+ $index++;
+ }
+
+ return $return;
+}
+
+
+//
+// $ip が $ipaddr_subnetsの中に含まれるか検査する.
+// $ipaddr_subnets は jbxl_to_subnetformats()が出力したものを使用すること.
+// $ip の内容の形式はチェックしない.これは呼び出し側の責任.
+//
+function jbxl_match_ipaddr($ip, array $ipaddr_subnets)
+{
+ $ipa = explode('.', $ip);
+ if (empty($ipa)) return false;
+
+ for ($i=1; $i<4; $i++) {
+ if (empty($ipa[$i])) $ipa[$i] = 0;
+ }
+
+ foreach($ipaddr_subnets as $ipaddr_subnet) {
+ $ips = $ipaddr_subnet['ipaddr'];
+ $sub = $ipaddr_subnet['subnet'];
+
+ $match_f = true;
+ for ($i=0; $i<4; $i++) {
+ $check1 = $ipa[$i] & $sub[$i];
+ $check2 = $ips[$i] & $sub[$i];
+ if ($check1 != $check2) {
+ $match_f = false;
+ break;
+ }
+ }
+
+ if ($match_f) {
+ //print_r($ips);
+ //print_r($sub);
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+$JBXLBaseChar = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+
+
+function jbxl_randstr($len=8, $lowcase=false)
+{
+ global $JBXLBaseChar;
+
+ if ($lowcase) $rndmax = 25;
+ else $rndmax = strlen($JBXLBaseChar) - 1;
+
+ $return = "";
+ for($i=0; $i<$len; $i++) {
+ $return .= $JBXLBaseChar{mt_rand(0, $rndmax)};
+ }
+ return $return;
+}
+
+
+function jbxl_get_ipresolv_url($ip, $region='APNIC')
+{
+ if (!preg_match('/(^\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/', $ip, $match)) return '';
+
+ if ($match[1]>255 or $match[2]>255 or $match[3]>255 or $match[4]>255) return '';
+ if ($match[1]=='127' or $match[1]=='10') return '';
+ if ($match[1]=='172' and $match[2]>='16' and $match[2]<='31') return '';
+ if ($match[1]=='192' and $match[2]=='168') return '';
+
+ if ($region=='JPNIC') {
+ $url = 'http://whois.nic.ad.jp/cgi-bin/whois_gw?type=NET&key='.$ip; // JPNIC
+ }
+ else {
+ $url = 'http://wq.apnic.net/apnic-bin/whois.pl?searchtext='.$ip; // APNIC
+ }
+
+ return $url;
+}
+
+
+function jbxl_get_url_params_array($urlstr)
+{
+ $strs = explode('?', $urlstr);
+ $parmstr = $strs[0];
+ if (array_key_exists(1, $strs)) $paramstr = $strs[1];
+
+ $ret = array();
+ $params = explode('&', $paramstr);
+ foreach($params as $param) {
+ if (substr($param, 0, 4)=='amp;') $param = substr($param, 5);
+ $temps = explode('=', $param);
+ $ret[$temps[0]] = '';
+ if (array_key_exists(1, $temps)) $ret[$temps[0]] = $temps[1];
+ }
+
+ return $ret;
+}
+
+
+//
+// $params: パラメータの入っている配列
+// $amp: 先頭文字を '&' にするか? false の場合は 先頭文字は '?'
+//
+function jbxl_get_url_params_str($params, $amp=false)
+{
+ $ret = '';
+ if (!is_array($params)) return $ret;
+
+ $no = 0;
+ foreach($params as $key => $param) {
+ if ($no==0 and !$amp) {
+ $ret .= '?'.$key.'='.$param;
+ }
+ else {
+ $ret .= '&'.$key.'='.$param;
+ }
+ $no++;
+ }
+ return $ret;
+}
+
+
+//
+// 入力された FSDN, URL に対して http(s)://ABC.EFG:#/ の形を生成する
+//
+function jbxl_make_url($serverURI, $portnum=0)
+{
+ $url = '';
+ $host = 'localhost';
+ $port = 80;
+ $protocol = 'http';
+
+ if ($serverURI!=null) {
+ $uri = preg_split("/[:\/]/", $serverURI);
+
+ // with http:// or https://
+ if (array_key_exists(3, $uri)) {
+ $protocol = $uri[0];
+ $host = $uri[3];
+ //
+ if (array_key_exists(4, $uri)) {
+ $port = $uri[4];
+ }
+ else {
+ if ($portnum!=0) {
+ $port = $portnum;
+ }
+ else {
+ if ($uri[0]=='http') $port = 80;
+ else if ($uri[0]=='https') $port = 443;
+ else if ($uri[0]=='ftp') $port = 21;
+ // else if ....
+ }
+ }
+ }
+
+ // with no http:// and https://
+ else {
+ $host = $uri[0];
+ if (array_key_exists(1, $uri)) {
+ $port = $uri[1];
+ }
+ else {
+ if ($portnum!=0) {
+ $port = $portnum;
+ }
+ else {
+ $port = 80;
+ }
+ }
+ }
+
+ //
+ if ($port==443) {
+ $url = 'https://'.$host.':'.$port.'/';
+ $protocol = 'https';
+ }
+ else if ($port==80) {
+ $url = 'http://'.$host.'/';
+ $protocol = 'http';
+ }
+ else if ($port==21) {
+ $url = 'ftp://'.$host.'/';
+ $protocol = 'ftp';
+ }
+ else {
+ $url = $protocol.'://'.$host.':'.$port.'/';
+ }
+ }
+
+ $server['url'] = $url;
+ $server['host'] = $host;
+ $server['port'] = $port;
+ $server['porotocol'] = $protocol;
+
+ return $server;
+}
+
+
+} // !defined('JBXL_TOOLS_VER')
diff --git a/helper-php/DTLNSL_helper_scripts/include/mysql.func.php b/helper-php/DTLNSL_helper_scripts/include/mysql.func.php
new file mode 100644
index 0000000..40f61ba
--- /dev/null
+++ b/helper-php/DTLNSL_helper_scripts/include/mysql.func.php
@@ -0,0 +1,382 @@
+Host = $dbhost;
+ $this->Database = $dbname;
+ $this->User = $dbuser;
+ $this->Password = $dbpass;
+
+ $this->UseMySQLi= $usemysqli;
+ $this->Timeout = $timeout;
+ ini_set('mysql.connect_timeout', $timeout);
+ }
+
+
+ function set_DB($dbhost, $dbname, $dbuser, $dbpass, $usemysqli=false)
+ {
+ $this->Host = $dbhost;
+ $this->Database = $dbname;
+ $this->User = $dbuser;
+ $this->Password = $dbpass;
+ $this->UseMySQLi= $usemysqli;
+ }
+
+
+ function halt($msg)
+ {
+ echo "DB ERROR : $msg
\n";
+ echo "MySQL ERROR: $this->Error ($this->Errno)
\n";
+ die('Session Halted.');
+ }
+
+
+ function connect()
+ {
+ if ($this->Link_ID==null) {
+ //
+ if (!$this->UseMySQLi) {
+ $this->Link_ID = mysql_connect($this->Host, $this->User, $this->Password);
+ if (!$this->Link_ID) {
+ $this->Errno = 999;
+ //error_log('cannot select database. 1/2');
+ return false;
+ }
+ mysql_set_charset('utf8');
+ $SelectResult = mysql_select_db($this->Database, $this->Link_ID);
+ if (!$SelectResult) {
+ $this->Errno = mysql_errno($this->Link_ID);
+ $this->Error = mysql_error($this->Link_ID);
+ $this->Link_ID = null;
+ //$this->halt('cannot select database '.$this->Database.'');
+ //error_log('cannot select database. 2/2');
+ return false;
+ }
+ }
+ //
+ else {
+ $this->Link_ID = mysqli_connect($this->Host, $this->User, $this->Password, $this->Database);
+ if (!$this->Link_ID) {
+ $this->Errno = 999;
+ $this->Error = mysqli_connect_error();
+ //$this->halt('cannot select database '.$this->Database.'');
+ //error_log('cannot select database.');
+ return false;
+ }
+ mysqli_set_charset($this->Link_ID, 'utf8');
+ }
+ }
+ return true;
+ }
+
+
+ function escape($String)
+ {
+ $this->connect();
+
+ if (!$this->UseMySQLi) return mysql_real_escape_string($String);
+ return mysqli_real_escape_string($this->Link_ID, $String);
+ }
+
+
+ function query($Query_String)
+ {
+ $this->connect();
+ if ($this->Errno!=0) return 0;
+
+ if (!$this->UseMySQLi) {
+ $this->Query_ID = mysql_query($Query_String, $this->Link_ID);
+ $this->Errno = mysql_errno($this->Link_ID);
+ $this->Error = mysql_error($this->Link_ID);
+ }
+ else {
+ $this->Query_ID = mysqli_query($this->Link_ID, $Query_String);
+ $this->Errno = mysqli_errno($this->Link_ID);
+ $this->Error = mysqli_error($this->Link_ID);
+ }
+ $this->Row = 0;
+ //
+ if (!$this->Query_ID) {
+ $this->halt('Invalid SQL: '.$Query_String);
+ }
+ return $this->Query_ID;
+ }
+
+
+ function next_record()
+ {
+ if (!$this->UseMySQLi) {
+ $this->Record = @mysql_fetch_array($this->Query_ID);
+ $this->Row += 1;
+ $this->Errno = mysql_errno($this->Link_ID);
+ $this->Error = mysql_error($this->Link_ID);
+ $stat = is_array($this->Record);
+ if (!$stat) {
+ @mysql_free_result($this->Query_ID);
+ $this->Query_ID = null;
+ }
+ }
+ else {
+ $this->Record = @mysqli_fetch_array($this->Query_ID);
+ $this->Row += 1;
+ $this->Errno = mysqli_errno($this->Link_ID);
+ $this->Error = mysqli_error($this->Link_ID);
+ $stat = is_array($this->Record);
+ if (!$stat) {
+ @mysqli_free_result($this->Query_ID);
+ $this->Query_ID = null;
+ }
+ }
+
+ return $this->Record;
+ }
+
+
+ function insert_record($table, $params)
+ {
+ if (!is_array($params)) return false;
+
+ $num = 0;
+ $keys = '';
+ $vals = '';
+ foreach ($params as $key => $value) {
+ if ($num==0) {
+ $keys = $key;
+ $vals = "'".$value."'";
+ }
+ else {
+ $keys .= ','.$key;
+ $vals .= ",'".$value."'";
+ }
+ $num++;
+ }
+
+ $this->query('INSERT INTO '.$table.' ('.$keys.') VALUES ('.$vals.')');
+
+ if ($this->Errno==0) return true;
+ return false;
+ }
+
+
+ // params配列の一番最初の要素が キー
+ function update_record($table, $params)
+ {
+ if (!is_array($params)) return false;
+
+ $num = 0;
+ $where = '';
+ $setval = '';
+ foreach ($params as $key => $value) {
+ if ($num==0) {
+ $where = $key."='".$value."'";
+ }
+ else if ($num==1) {
+ $setval = $key."='".$value."'";
+ }
+ else {
+ $setval .= ','.$key."='".$value."'";
+ }
+ $num++;
+ }
+
+ $this->query('UPDATE '.$table.' SET '.$setval.' WHERE '.$where);
+
+ if ($this->Errno==0) return true;
+ return false;
+ }
+
+
+ function num_rows()
+ {
+ if (!$this->UseMySQLi) return mysql_num_rows($this->Query_ID);
+ return mysqli_num_rows($this->Query_ID);
+ }
+
+
+ function affected_rows()
+ {
+ if (!$this->UseMySQLi) return mysql_affected_rows($this->Link_ID);
+ return mysqli_affected_rows($this->Link_ID);
+ }
+
+
+ function optimize($tbl_name)
+ {
+ $this->connect();
+ if ($this->Errno!=0) return;
+
+ if (!$this->UseMySQLi) {
+ $this->Query_ID = @mysql_query('OPTIMIZE TABLE '.$tbl_name, $this->Link_ID);
+ }
+ else {
+ $this->Query_ID = @mysqli_query($this->Link_ID, 'OPTIMIZE TABLE '.$tbl_name);
+ }
+ }
+
+
+ function clean_results()
+ {
+ if ($this->Query_ID!=null) {
+ if (!$this->UseMySQLi) {
+ mysql_freeresult($this->Query_ID);
+ }
+ else {
+ mysqli_freeresult($this->Query_ID);
+ }
+ $this->Query_ID = null;
+ }
+ }
+
+
+ function close()
+ {
+ /*
+ if ($this->Link_ID) {
+ if (!$this->UseMySQLi) mysql_close($this->Link_ID);
+ mysqli_close($this->Link_ID);
+ $this->Link_ID = null;
+ }
+ */
+ }
+
+
+ function exist_table($table, $lower_case=true)
+ {
+ $ret = false;
+
+ if ($lower_case) $table = strtolower($table);
+
+ $this->query('SHOW TABLES');
+ if ($this->Errno==0) {
+ while (list($db_tbl) = $this->next_record()) {
+ if ($lower_case) $db_tbl = strtolower($db_tbl);
+ if ($db_tbl==$table) {
+ $ret = true;
+ break;
+ }
+ }
+ }
+
+ return $ret;
+ }
+
+
+ function exist_field($table, $field, $lower_case=true)
+ {
+ $ret1 = false;
+ $ret2 = false;
+
+ if ($lower_case) $cmp_table = strtolower($table);
+ else $cmp_table = $table;
+
+ $this->query('SHOW TABLES');
+ if ($this->Errno==0) {
+ while (list($db_tbl) = $this->next_record()) {
+ if ($lower_case) $db_tbl = strtolower($db_tbl);
+ if ($db_tbl==$cmp_table) {
+ $ret1 = true;
+ break;
+ }
+ }
+ }
+
+ if ($ret1) {
+ $this->query('SHOW COLUMNS FROM '.$table);
+ if ($this->Errno==0) {
+ while (list($db_fld) = $this->next_record()) {
+ if ($db_fld==$field) {
+ $ret2 = true;
+ break;
+ }
+ }
+ }
+ }
+
+ return $ret2;
+ }
+
+
+ //
+ // InnoDB では Update_time は NULL になる!
+ //
+ function get_update_time($table, $unixtime=true)
+ {
+ $update = '';
+ if ($unixtime) $update = 0;
+
+ $this->query("SHOW TABLE STATUS WHERE name='$table'");
+
+ if ($this->Errno==0) {
+ $table_status = $this->next_record();
+ $update = $table_status['Update_time'];
+ if ($unixtime) {
+ if ($update!='') $update = strtotime($update);
+ else $update = 0;
+ }
+ }
+
+ return $update;
+ }
+
+
+ //
+ // Lock
+ //
+ function lock_table($table, $mode='write')
+ {
+ $this->query("LOCK TABLES ".$table." ".$mode);
+ }
+
+
+ function unlock_table()
+ {
+ $this->query("UNLOCK TABLES");
+ }
+
+
+ //
+ // Timeout
+ //
+ function set_default_timeout($tm)
+ {
+ ini_set('mysql.connect_timeout', $tm);
+ $this->Timeout = $tm;
+ }
+
+
+ function set_temp_timeout($tm)
+ {
+ ini_set('mysql.connect_timeout', $tm);
+ }
+
+
+ function reset_timeout()
+ {
+ ini_set('mysql.connect_timeout', $this->Timeout);
+ }
+}
diff --git a/helper-php/DTLNSL_helper_scripts/include/opensim.mysql.php b/helper-php/DTLNSL_helper_scripts/include/opensim.mysql.php
new file mode 100644
index 0000000..6eafaba
--- /dev/null
+++ b/helper-php/DTLNSL_helper_scripts/include/opensim.mysql.php
@@ -0,0 +1,2764 @@
+get_update_time('UserAccounts');
+ return $utime;
+}
+
+
+//
+// Check and get Basic Data of DB
+//
+function opensim_check_db(&$db=null)
+{
+ $ret['grid_status'] = false;
+ $ret['now_online'] = 0;
+ $ret['hg_online'] = 0;
+ $ret['lastmonth_online'] = 0;
+ $ret['user_count'] = 0;
+ $ret['region_count'] = 0;
+
+ if (!is_object($db)) $db = opensim_new_db(3);
+ if ($db==null) return $ret;
+
+ if ($db->exist_table('regions')) {
+ $db->query('SELECT COUNT(*) FROM regions');
+ if ($db->Errno==0) {
+ list($ret['region_count']) = $db->next_record();
+ }
+ }
+
+ $db->query('SELECT COUNT(*) FROM UserAccounts'); // Local User
+ list($ret['user_count']) = $db->next_record();
+ //
+ if ($db->exist_table('Presence')) {
+ $db->query("SELECT COUNT(DISTINCT Presence.UserID) FROM GridUser,Presence ".
+ //"WHERE GridUser.UserID=Presence.UserID AND Online='True' AND RegionID!='".UUID_ZERO."'");
+ "WHERE GridUser.UserID=Presence.UserID AND RegionID!='".UUID_ZERO."'");
+ list($loc_user) = $db->next_record();
+
+ $db->query("SELECT COUNT(*) FROM Presence WHERE RegionID!='".UUID_ZERO."'");
+ list($all_user) = $db->next_record();
+
+ $ret['now_online'] = $all_user;
+ $ret['hg_online'] = $all_user - $loc_user;
+ }
+ // Standalone
+ else {
+ $db->query("SELECT COUNT(*) FROM GridUser WHERE Online='True' AND UserID NOT LIKE '%;%'");
+ list($loc_user) = $db->next_record();
+
+ $db->query("SELECT COUNT(*) FROM GridUser WHERE Online='True'");
+ list($all_user) = $db->next_record();
+
+ $ret['now_online'] = $all_user;
+ $ret['hg_online'] = $all_user - $loc_user;
+ }
+ //
+ $db->query('SELECT COUNT(*) FROM GridUser WHERE Login>unix_timestamp(now())-2592000'); // Local and HG User
+ list($ret['lastmonth_online']) = $db->next_record();
+ //
+ $ret['grid_status'] = true;
+
+ return $ret;
+}
+
+
+function opensim_is_standalone(&$db=null)
+{
+ if (!is_object($db)) $db = opensim_new_db();
+
+ if ($db->exist_table('Presence')) return false;
+ return true;
+}
+
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+//
+// for Avatar
+//
+
+//
+// ローカルなアバター数
+//
+function opensim_get_avatars_num($condition='', &$db=null)
+{
+ if (!is_object($db)) $db = opensim_new_db();
+ if ($condition!='') $condition = 'WHERE '.$condition;
+
+ $num = 0;
+ $db->query('SELECT COUNT(*) FROM UserAccounts '.$condition);
+ list($num) = $db->next_record();
+
+ return $num;
+}
+
+
+//
+// HGユーザも含めた全アバター数
+//
+function opensim_allavatars_count_records(&$db=null)
+{
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $count = 0;
+ $db->query('SELECT COUNT(*) FROM GridUser');
+ list($count) = $db->next_record();
+
+ return $count;
+}
+
+
+function opensim_get_avatar_name($uuid, $hguser=true, &$db=null)
+{
+ $name = array();
+
+ if (!isGUID($uuid)) return $name;
+
+ if ($uuid==UUID_ZERO) {
+ $name['firstname'] = 'System';
+ $name['lastname'] = '';
+ $name['fullname'] = 'System';
+ return $name;
+ }
+
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $firstname = null;
+ $lastname = null;
+ $fullname = null;
+
+ $db->query("SELECT FirstName,LastName FROM UserAccounts WHERE PrincipalID='$uuid'");
+ list($firstname, $lastname) = $db->next_record();
+ $fullname = $firstname.' '.$lastname;
+ if ($fullname==' ') {
+ $fullname = null;
+ $firstname = null;
+ $lastname = null;
+ }
+
+ // HG
+ if ($hguser and $fullname==null) {
+ $db->query("SELECT UserID FROM GridUser WHERE UserID LIKE '".$uuid.";%' ORDER BY Login DESC");
+ list($hg_uuid) = $db->next_record();
+ $uuids = explode(';', $hg_uuid);
+ //
+ if (array_key_exists(2, $uuids)) {
+ $fullname = $uuids[2];
+ $firstname = $uuids[2];
+ $lastname = null;
+ $hg_name = explode(' ', $fullname);
+ $firstname = $hg_name[0];
+ if (array_key_exists(1, $hg_name)) $lastname = $hg_name[1];
+ }
+ }
+
+ $name['firstname'] = $firstname;
+ $name['lastname'] = $lastname;
+ $name['fullname'] = $fullname;
+
+ return $name;
+}
+
+
+function opensim_get_avatar_uuid($name, $hguser=true, &$db=null)
+{
+ if (!isAlphabetNumericSpecial($name)) return null;
+ if (!is_object($db)) $db = opensim_new_db();
+ if (mb_strtolower($name)=='system') return UUID_ZERO;
+
+ $avatar_name = preg_split("/ /", $name, 0, PREG_SPLIT_NO_EMPTY);
+ $firstname = $avatar_name[0];
+ $lastname = 'Resident';
+ if (array_key_exists(1, $avatar_name)) $lastname = $avatar_name[1];
+ if ($firstname=='') return null;
+
+ $uuid = null;
+ $db->query("SELECT PrincipalID FROM UserAccounts WHERE FirstName='$firstname' AND LastName='$lastname'");
+ list($uuid) = $db->next_record();
+
+ // HG
+ if ($hguser and $uuid==null) {
+ $db->query("SELECT UserID FROM GridUser WHERE UserID LIKE '%;%;".$firstname.' '.$lastname."' ORDER BY Login DESC");
+ list($hg_uuid) = $db->next_record();
+ $uuids = explode(';', $hg_uuid);
+ $uuid = $uuids[0];
+ }
+
+ return $uuid;
+}
+
+
+function opensim_get_avatar_session($uuid, &$db=null)
+{
+ if (!isGUID($uuid)) return null;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $avssn = array();
+ //
+ if ($db->exist_table('Presence')) {
+ $sql = "SELECT RegionID,SessionID,SecureSessionID FROM Presence WHERE UserID='".$uuid."'";
+ $db->query($sql);
+ list($RegionID, $SessionID, $SecureSessionID) = $db->next_record();
+ //
+ $avssn['regionID'] = $RegionID;
+ $avssn['sessionID'] = $SessionID;
+ $avssn['secureID'] = $SecureSessionID;
+ }
+ // Standalone
+ else {
+ $sql = "SELECT LastRegionID FROM GridUser WHERE UserID='".$uuid."'";
+ $db->query($sql);
+ list($RegionID) = $db->next_record();
+ //
+ $avssn['regionID'] = $RegionID;
+ $avssn['sessionID'] = UUID_ZERO;
+ $avssn['secureID'] = UUID_ZERO;
+ }
+
+ return $avssn;
+}
+
+
+/*
+ return:
+ $avinfo['UUID']
+ $avinfo['firstname']
+ $avinfo['lastname']
+ $avinfo['fullname']
+ $avinfo['created']
+ $avinfo['lastlogin']
+ $avinfo['regionUUID']
+ $avinfo['regionName']
+ $avinfo['serverIP']
+ $avinfo['serverHttpPort']
+ $avinfo['serverPort']
+ $avinfo['serverURI']
+ $avinfo['serverName']
+ //
+ $avinfo['hgURI']
+ $avinfo['hgName']
+ //
+ $avinfo['profileText']
+ $avinfo['profileImage']
+ $avinfo['firstText']
+ $avinfo['firstImage']
+ $avinfo['partner']
+*/
+function opensim_get_avatar_info($uuid, $hguser=true, &$db=null)
+{
+ if (!isGUID($uuid)) return null;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $created = 0;
+ $regionName = null;
+ $serverIP = null;
+ $serverHttpPort = null;
+ $serverURI = null;
+ $hgURI = null;
+
+ $profileText = null;
+ $profileImage = null;
+ $firstText = null;
+ $firstImage = null;
+ $partner = null;
+
+ $db->query('SELECT PrincipalID,FirstName,LastName,HomeRegionID,Created,Login FROM UserAccounts'.
+ " LEFT JOIN GridUser ON PrincipalID=UserID WHERE PrincipalID='$uuid'");
+ list($UUID, $firstname, $lastname, $regionUUID, $created, $lastlogin) = $db->next_record();
+ $fullname = $firstname.' '.$lastname;
+ if ($fullname==' ') {
+ $fullname = null;
+ $firstname = null;
+ $lastname = null;
+ }
+
+ if ($fullname!=null) {
+ $db->query("SELECT regionName,serverIP,serverHttpPort,serverURI FROM regions WHERE uuid='$regionUUID'");
+ list($regionName, $serverIP, $serverHttpPort, $serverURI) = $db->next_record();
+ }
+ // HG
+ else if ($hguser) {
+ $db->query("SELECT UserID,HomeRegionID,Login FROM GridUser WHERE UserID LIKE '".$uuid.";%' ORDER BY Login DESC");
+ list($hg_uuid, $regionUUID, $lastlogin) = $db->next_record();
+ $uuids = explode(';', $hg_uuid);
+ $UUID = $uuids[0];
+ if (array_key_exists(1, $uuids)) $hgURI = $uuids[1];
+ if (array_key_exists(2, $uuids)) {
+ $fullname = $uuids[2];
+ $hg_name = explode(' ', $fullname);
+ $firstname = $hg_name[0];
+ if (array_key_exists(1, $hg_name)) $lastname = $hg_name[1];
+ }
+ }
+
+ $avinfo['UUID'] = $UUID;
+ $avinfo['firstname'] = $firstname;
+ $avinfo['lastname'] = $lastname;
+ $avinfo['fullname'] = $fullname;
+ $avinfo['created'] = $created;
+ $avinfo['lastlogin'] = $lastlogin;
+ $avinfo['regionUUID'] = $regionUUID;
+ $avinfo['regionName'] = $regionName;
+ $avinfo['serverIP'] = $serverIP;
+ $avinfo['serverHttpPort'] = $serverHttpPort;
+ $avinfo['serverPort'] = $serverHttpPort;
+ $avinfo['serverURI'] = $serverURI;
+ $avinfo['serverName'] = '';
+ $avinfo['hgURI'] = $hgURI;
+ $avinfo['hgName'] = '';
+ //
+ $avinfo['profileText'] = $profileText;
+ $avinfo['profileImage'] = $profileImage;
+ $avinfo['firstText'] = $firstText;
+ $avinfo['firstImage'] = $firstImage;
+ $avinfo['partner'] = $partner;
+
+ $uri = preg_split("/[:\/]/", $serverURI);
+ if (array_key_exists(3, $uri)) {
+ $avinfo['serverName'] = $uri[3];
+// $avinfo['serverIP2'] = gethostbyname($uri[3]);
+ }
+ //
+ $uri = preg_split("/[:\/]/", $hgURI);
+ if (array_key_exists(3, $uri)) {
+ $avinfo['hgName'] = $uri[3];
+ }
+
+ return $avinfo;
+}
+
+
+/*
+ HG avatars are not supported.
+
+ return:
+ $avinfos[$UUID]['UUID'] ... UUID
+ $avinfos[$UUID]['firstname'] ... first name
+ $avinfos[$UUID]['lastname'] ... lasti name
+ $avinfos[$UUID]['created'] ... created time
+ $avinfos[$UUID]['lastlogin'] ... lastlogin time
+ $avinfos[$UUID]['hmregion'] ... uuid of home region
+*/
+function opensim_get_avatars_infos($condition='', $order='', $limit='', &$db=null)
+{
+ if (!is_object($db)) $db = opensim_new_db();
+ if ($condition!='') $condition = 'WHERE '.$condition;
+ if ($order!='') $order = ' ORDER BY '.$order;
+ if ($limit!='') $limit = ' LIMIT '. $limit;
+
+ $avinfos = array();
+ $query_str = 'SELECT PrincipalID,FirstName,LastName,Created,Login,homeRegionID FROM UserAccounts '.
+ 'LEFT JOIN GridUser ON PrincipalID=UserID '.$condition.$order.$limit;
+ $db->query($query_str);
+
+ if ($db->Errno==0) {
+ while (list($UUID,$firstname,$lastname,$created,$lastlogin,$hmregion) = $db->next_record()) {
+ $avinfos[$UUID]['UUID'] = $UUID;
+ $avinfos[$UUID]['firstname'] = $firstname;
+ $avinfos[$UUID]['lastname'] = $lastname;
+ $avinfos[$UUID]['created'] = $created;
+ $avinfos[$UUID]['lastlogin'] = $lastlogin;
+ $avinfos[$UUID]['hmregion_id'] = $hmregion;
+ }
+ }
+
+ return $avinfos;
+}
+
+
+/*
+ return:
+ $avinfos[$UUID]['UUID'] ... UUID
+ $avinfos[$UUID]['firstname'] ... first name
+ $avinfos[$UUID]['lastname'] ... lasti name
+ $avinfos[$UUID]['created'] ... always 0
+ $avinfos[$UUID]['lastlogin'] ... lastlogin time
+ $avinfos[$UUID]['hgURI'] ... Hyper Grid URI
+ $avinfos[$UUID]['hgName'] ... Hyper Grid name
+*/
+function opensim_get_hg_avatars_infos($condition='', $order='', $limit='', &$db=null)
+{
+ if (!is_object($db)) $db = opensim_new_db();
+ if ($condition!='') $condition = '('.$condition.') AND';
+ if ($order!='') $order = ' ORDER BY '.$order;
+ if ($limit!='') $limit = ' LIMIT '. $limit;
+
+ $avinfos = array();
+ $query_str = 'SELECT UserID,Login FROM GridUser WHERE '.$condition." UserID LIKE '%;%;%' ".$order.$limit;
+ $db->query($query_str);
+
+ if ($db->Errno==0) {
+ while (list($hg_uuid, $lastlogin) = $db->next_record()) {
+ $hgURI = '';
+ $fullname = '';
+ $firstname = '';
+ $lastname = '';
+
+ $uuids = explode(';', $hg_uuid);
+ $UUID = $uuids[0];
+ if (array_key_exists(1, $uuids)) $hgURI = $uuids[1];
+ if (array_key_exists(2, $uuids)) {
+ $fullname = $uuids[2];
+ $hg_name = explode(' ', $fullname);
+ $firstname = $hg_name[0];
+ if (array_key_exists(1, $hg_name)) $lastname = $hg_name[1];
+ }
+ //
+ if (!array_key_exists($UUID, $avinfos)) {
+ $avinfos[$UUID]['UUID'] = $UUID;
+ $avinfos[$UUID]['firstname'] = $firstname;
+ $avinfos[$UUID]['lastname'] = $lastname;
+ $avinfos[$UUID]['created'] = 0;
+ $avinfos[$UUID]['lastlogin'] = $lastlogin;
+ $avinfos[$UUID]['hgURI'] = $hgURI;
+ $avinfos[$UUID]['hgName'] = '';
+ //
+ $uri = preg_split("/[:\/]/", $hgURI);
+ if (array_key_exists(3, $uri)) {
+ $avinfos[$UUID]['hgName'] = $uri[3];
+ }
+ }
+ }
+ }
+
+ return $avinfos;
+}
+
+
+/*
+ return:
+ $ret['online']
+ $ret['regionUUID']
+ $ret['regionName']
+ $ret['timeStamp']
+*/
+function opensim_get_avatar_online($uuid, &$db=null)
+{
+ if (!isGUID($uuid)) return null;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $online = false;
+ $timestamp = 0;
+ $region = UUID_ZERO;
+ $rgn_name = '';
+
+ if ($db->exist_table('Presence')) {
+ $query_str = "SELECT RegionID,unix_timestamp(LastSeen) FROM Presence,GridUser WHERE Presence.UserID='$uuid'".
+ " AND RegionID!='".UUID_ZERO."' AND GridUser.UserID LIKE '".$uuid."%'";
+ $db->query($query_str);
+ if ($db->Errno==0) {
+ list($region, $timestamp) = $db->next_record();
+ if ($region!='') {
+ $rgn_name = opensim_get_region_name($region);
+ if ($rgn_name!='') $online = true;
+ else opensim_set_avatar_offline($uuid);
+ }
+ }
+ }
+ // Standalone
+ else {
+ $query_str = "SELECT LastRegionID,unix_timestamp(Login) FROM GridUser WHERE UserID LIKE '".$uuid."%' AND Online='True'";
+ $db->query($query_str);
+ if ($db->Errno==0) {
+ list($region, $timestamp) = $db->next_record();
+ if ($region!='') {
+ $rgn_name = opensim_get_region_name($region);
+ if ($rgn_name!='') $online = true;
+ else opensim_set_avatar_offline($uuid);
+ }
+ }
+ }
+
+ $ret['online'] = $online;
+ $ret['regionUUID'] = $region;
+ $ret['regionName'] = $rgn_name;
+ $ret['timeStamp'] = $timestamp;
+
+ return $ret;
+}
+
+
+/*
+ return:
+ $ret[$UUID]['UUID']
+ $ret[$UUID]['online']
+ $ret[$UUID]['regionUUID']
+ $ret[$UUID]['regionName']
+ $ret[$UUID]['timeStamp']
+*/
+function opensim_get_avatars_online($condition='', $order='', $limit='', $hg_avatar=true, &$db=null)
+{
+ if (!is_object($db)) $db = opensim_new_db();
+ if ($condition!='') $condition = 'AND ('.$condition.')';
+ if ($order!='') $order = ' ORDER BY '.$order;
+ if ($limit!='') $limit = ' LIMIT '. $limit;
+
+ $ret = array();
+
+ $condition .= $order.$limit;
+ if ($db->exist_table('Presence')) {
+ if ($hg_avatar) {
+ $query_str = 'SELECT UserID,RegionID,unix_timestamp(LastSeen) FROM Presence '.
+ " WHERE RegionID!='".UUID_ZERO."'".$condition;
+ }
+ else {
+ $query_str = 'SELECT Presence.UserID,RegionID,unix_timestamp(LastSeen) FROM Presence,GridUser '.
+ " WHERE Presence.UserID=GridUser.UserID AND GridUser.UserID NOT LIKE '%;%' AND RegionID!='".UUID_ZERO."'".$condition;
+ }
+
+ $db->query($query_str);
+
+ if ($db->Errno==0) {
+ while (list($UUID, $region, $lastlogin) = $db->next_record()) {
+ $ret[$UUID]['UUID'] = $UUID;
+ $ret[$UUID]['online'] = true;
+ $ret[$UUID]['regionUUID'] = $region;
+ $ret[$UUID]['timeStamp'] = $lastlogin;
+ //
+ $rgn_name = opensim_get_region_name($region);
+ if ($rgn_name!='') $ret[$UUID]['regionName'] = $rgn_name;
+ else opensim_set_avatar_offline($UUID);
+ }
+ }
+ }
+ // Standalone
+ else {
+ if (!$hg_avatar) $condition = " AND UserID NOT LIKE '%;%'".$condition;
+ $query_str = 'SELECT UserID,LastRegionID,Login FROM GridUser '.
+ " WHERE Online='True' AND LastRegionID!='".UUID_ZERO."'".$condition;
+ $db->query($query_str);
+
+ if ($db->Errno==0) {
+ while (list($UUID, $region, $lastlogin) = $db->next_record()) {
+ $uuids = explode(';', $UUID);
+ $ret[$UUID]['UUID'] = $uuids[0];
+ $ret[$UUID]['online'] = true;
+ $ret[$UUID]['regionUUID'] = $region;
+ $ret[$UUID]['timeStamp'] = $lastlogin;
+ //
+ $rgn_name = opensim_get_region_name($region);
+ if ($rgn_name!='') $ret[$UUID]['regionName'] = $rgn_name;
+ else opensim_set_avatar_offline($uuids[0]);
+ }
+ }
+ }
+
+ return $ret;
+}
+
+
+function opensim_get_avatars_online_num($hg_avatar=true, &$db=null)
+{
+ if (!is_object($db)) $db = opensim_new_db();
+
+ if ($db->exist_table('Presence')) {
+ if ($hg_avatar) {
+ $query_str = "SELECT COUNT(*) FROM Presence WHERE RegionID!='".UUID_ZERO."'";
+ }
+ else {
+ $query_str = "SELECT COUNT(*) FROM Presence,GridUser WHERE Presence.UserID=GridUser.UserID ".
+ "AND GridUser.UserID NOT LIKE '%;%' AND RegionID!='".UUID_ZERO."'";
+ }
+ }
+ // Standalone
+ else {
+ $query_str = "SELECT COUNT(*) FROM GridUser WHERE Online='True' AND LastRegionID!='".UUID_ZERO."'";
+ if (!$hg_avatar) $query_str .= " AND UserID NOT LIKE '%;%'";
+ }
+
+ $num = 0;
+ $db->query($query_str);
+ list($num) = $db->next_record();
+
+ return $num;
+}
+
+
+function opensim_get_avatar_flags($uuid, &$db=null)
+{
+ if (!isGUID($uuid)) return null;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $db->query("SELECT UserFlags FROM UserAccounts WHERE PrincipalID='$uuid'");
+ if ($db->Errno==0) {
+ list($flags) = $db->next_record();
+ return $flags;
+ }
+
+ return 0;
+}
+
+
+function opensim_set_avatar_flags($uuid, $flags=0, &$db=null)
+{
+ if (!isGUID($uuid)) return false;
+ if (!isNumeric($flags)) return false;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $query_str = "UPDATE UserAccounts SET UserFlags='$flags' WHERE PrincipalID='$uuid'";
+ $db->query($query_str);
+ if ($db->Errno==0) return true;
+
+ return false;
+}
+
+
+function opensim_set_avatar_offline($uuid, &$db=null)
+{
+ if (!isGUID($uuid)) return;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ if ($db->exist_table('Presence')) {
+ $db->query("DELETE FROM Presence WHERE UserID='".$uuid."'");
+ }
+ $db->query("UPDATE GridUser SET Online='False' WHERE UserID LIKE '". $uuid."%'");
+
+ return;
+}
+
+
+function opensim_create_avatar($UUID, $firstname, $lastname, $passwd, $homeregion, $base_avatar=UUID_ZERO, &$db=null)
+{
+ if (!isGUID($UUID)) return false;
+ if (!isAlphabetNumericSpecial($firstname)) return false;
+ if (!isAlphabetNumericSpecial($lastname)) return false;
+ if (!isAlphabetNumericSpecial($passwd)) return false;
+ if (!isAlphabetNumericSpecial($homeregion)) return false;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $nulluuid = UUID_ZERO;
+ $passwdsalt = make_random_hash();
+ $passwdhash = md5(md5($passwd).":".$passwdsalt);
+
+ $db->query("SELECT uuid,regionHandle FROM regions WHERE regionName='$homeregion'");
+ $errno = $db->Errno;
+ if ($errno==0) {
+ list($regionID,$regionHandle) = $db->next_record();
+
+ $serviceURLs = 'HomeURI= GatekeeperURI= InventoryServerURI= AssetServerURI=';
+ $db->query('INSERT INTO UserAccounts (PrincipalID,ScopeID,FirstName,LastName,Email,ServiceURLs,Created,UserLevel,UserFlags,UserTitle) '.
+ "VALUES ('$UUID','$nulluuid','$firstname','$lastname','','$serviceURLs','".time()."','0','0','')");
+ $errno = $db->Errno;
+ if ($errno==0) {
+ $db->query('INSERT INTO GridUser (UserID,HomeRegionID,HomePosition,HomeLookAt,LastRegionID,LastPosition,LastLookAt,Online,Login,Logout) '.
+ "VALUES ('$UUID','$regionID','<128,128,0>','<0,0,0>','$regionID','<128,128,0>','<0,0,0>','false','0','0')");
+ $errno = $db->Errno;
+ }
+ if ($errno==0) {
+ $db->query('INSERT INTO auth (UUID,passwordHash,passwordSalt,webLoginKey,accountType) '.
+ "VALUES ('$UUID','$passwdhash','$passwdsalt','$nulluuid','UserAccount')");
+ $errno = $db->Errno;
+ }
+ //
+ if ($errno==0) {
+ opensim_create_avatar_inventory($UUID, $base_avatar, $db);
+ }
+ else {
+ $db->query("DELETE FROM UserAccounts WHERE PrincipalID='$UUID'");
+ $db->query("DELETE FROM auth WHERE UUID='$UUID'");
+ $db->query("DELETE FROM inventoryfolders WHERE agentID='$UUID'");
+ $db->query("DELETE FROM GridUser WHERE UserID='$UUID'");
+ }
+ }
+
+ if ($errno!=0) return false;
+ return true;
+}
+
+
+//
+// データベースからアバタ情報を削除する.
+//
+function opensim_delete_avatar($uuid, &$db=null)
+{
+ if (!isGUID($uuid)) return false;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $db->query("DELETE FROM UserAccounts WHERE PrincipalID='$uuid'");
+ $db->query("DELETE FROM auth WHERE UUID='$uuid'");
+ $db->query("DELETE FROM Avatars WHERE PrincipalID='$uuid'");
+ $db->query("DELETE FROM Friends WHERE PrincipalID='$uuid'");
+ $db->query("DELETE FROM tokens WHERE UUID='$uuid'");
+ $db->query("DELETE FROM GridUser WHERE UserID='$uuid'");
+ if ($db->exist_table('Presence')) $db->query("DELETE FROM Presence WHERE UserID='$uuid'");
+ if ($db->exist_table('Avatars')) $db->query("DELETE FROM Avatars WHERE PrincipalID='$uuid'");
+
+ $db->query("DELETE FROM estate_managers WHERE uuid='$uuid'");
+ $db->query("DELETE FROM estate_users WHERE uuid='$uuid'");
+ $db->query("DELETE FROM estateban WHERE bannedUUID='$uuid'");
+ $db->query("DELETE FROM inventoryfolders WHERE agentID='$uuid'");
+ $db->query("DELETE FROM inventoryitems WHERE avatarID='$uuid'");
+ $db->query("DELETE FROM landaccesslist WHERE AccessUUID='$uuid'");
+ $db->query("DELETE FROM regionban WHERE bannedUUID='$uuid'");
+
+ // for DTL Money Server
+ if ($db->exist_table('balances')) {
+ $db->query("DELETE FROM balances WHERE user='$uuid'");
+ $db->query("DELETE FROM userinfo WHERE user='$uuid'");
+ }
+
+ return true;
+}
+
+
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+//
+// for Region
+//
+
+function opensim_get_regions_num($hg=false, $condition='', &$db=null)
+{
+ if (!is_object($db)) $db = opensim_new_db();
+ if ($condition!='') {
+ $condition = 'WHERE '.$condition;
+ if (!$hg) $condition .= " AND (regionName NOT LIKE 'http://%' and regionName NOT LIKE 'https://%') ";
+ }
+ else {
+ if (!$hg) $condition = " WHERE (regionName NOT LIKE 'http://%' and regionName NOT LIKE 'https://%') ";
+ }
+
+ $num = 0;
+ $db->query('SELECT COUNT(*) FROM regions '.$condition);
+ list($num) = $db->next_record();
+
+ return $num;
+}
+
+
+function opensim_get_region_uuid($name, &$db=null)
+{
+// $name = addslashes($name);
+// if (!isAlphabetNumericSpecial($name)) return false;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $uuid = '';
+ if ($name!='') {
+ $query = "SELECT uuid FROM regions WHERE regionName='$name'";
+ $db->query($query);
+ list($uuid) = $db->next_record();
+ }
+
+ return $uuid;
+}
+
+
+function opensim_get_regions_uuid($hg=false, &$db=null)
+{
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $uuids = array();
+ $query = "SELECT uuid FROM regions";
+ if (!$hg) $query .= " WHERE (regionName NOT LIKE 'http://%' and regionName NOT LIKE 'https://%') "; // for Standalone
+
+ $db->query($query);
+ if ($db->Errno==0) {
+ while (list($UUID) = $db->next_record()) $uuids[$UUID] = $UUID;
+ }
+
+ return $uuids;
+}
+
+
+function opensim_get_region_name($id, &$db=null)
+{
+ if (!isGUID($id) and !isNumeric($id)) return null;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ if (isGUID($id)) {
+ $db->query("SELECT regionName FROM regions WHERE uuid='$id'");
+ list($regionName) = $db->next_record();
+ }
+ else {
+ $db->query("SELECT regionName FROM regions WHERE regionHandle='$id'");
+ list($regionName) = $db->next_record();
+ }
+
+ return $regionName;
+}
+
+
+//
+function opensim_get_regions_names($hg=false, $condition='', $order='', $limit='', &$db=null)
+{
+ if (!is_object($db)) $db = opensim_new_db();
+ if ($condition!='') {
+ $condition = 'WHERE '.$condition;
+ if (!$hg) $condition .= " AND (regionName NOT LIKE 'http://%' and regionName NOT LIKE 'https://%') ";
+ }
+ else {
+ if (!$hg) $condition = " WHERE (regionName NOT LIKE 'http://%' and regionName NOT LIKE 'https://%') ";
+ }
+ if ($order!='') $order = ' ORDER BY '.$order;
+ if ($limit!='') $limit = ' LIMIT '. $limit;
+
+ $regions = array();
+ $db->query('SELECT regionName FROM regions '.$condition.$order.$limit);
+ while ($db->Errno==0 and list($region)=$db->next_record()) {
+ $regions[] = $region;
+ }
+
+ return $regions;
+}
+
+
+/*
+ return:
+ $rginfo[firstname]
+ $rginfo[lastname]
+ $rginfo[fullname]
+ $rginfo[owner_uuid]
+ $rginfo[estate_id]
+ $rginfo[estate_owner]
+ $rginfo[estate_name]
+ $rginfo[regionHandle]
+ $rginfo[regionName]
+ $rginfo[regionSecret]
+ $rginfo[serverIP]
+ $rginfo[serverHttpPort]
+ $rginfo[serverPort]
+ $rginfo[serverURI]
+ $rginfo[locX]
+ $rginfo[locY]
+ $rginfo[sizeX]
+ $rginfo[sizeY]
+ $rginfo[serverName]
+*/
+function opensim_get_region_info($region, &$db=null)
+{
+ if (!isGUID($region)) return null;
+ if ($region==UUID_ZERO) return null;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $sql = "SELECT regionHandle,regionName,regionSecret,serverIP,serverHttpPort,serverURI,owner_uuid,locX,locY,sizeX,sizeY FROM regions WHERE uuid='$region'";
+ $db->query($sql);
+ list($regionHandle, $regionName, $regionSecret, $serverIP, $serverHttpPort, $serverURI, $owner_uuid, $locX, $locY, $sizeX, $sizeY) = $db->next_record();
+
+ $rginfo = opensim_get_estate_info($region, $db);
+ $rginfo['regionHandle'] = $regionHandle;
+ $rginfo['regionName'] = $regionName;
+ $rginfo['regionSecret'] = $regionSecret;
+ $rginfo['serverIP'] = $serverIP;
+ $rginfo['serverHttpPort'] = $serverHttpPort;
+ $rginfo['serverPort'] = $serverHttpPort;
+ $rginfo['serverURI'] = $serverURI;
+ $rginfo['locX'] = $locX;
+ $rginfo['locY'] = $locY;
+ $rginfo['sizeX'] = $sizeX;
+ $rginfo['sizeY'] = $sizeY;
+ //
+ $uri = preg_split("/[:\/]/", $serverURI);
+ if (array_key_exists(3, $uri)) {
+ $rginfo['serverName'] = $uri[3];
+ //$rginfo['serverIP2'] = gethostbyname($uri[3]);
+ }
+ else {
+ $rginfo['serverName'] = '';
+ //$rginfo['serverIP2'] = '';
+ }
+
+ if ($rginfo['owner_uuid']=='') $rginfo['owner_uuid'] = $owner_uuid;
+
+ return $rginfo;
+}
+
+
+/*
+ return:
+ $rginfos[$UUID]['UUID'] ... UUID
+ $rginfos[$UUID]['regionName'] ... name of region
+ $rginfos[$UUID]['locX'] ... location X
+ $rginfos[$UUID]['locY'] ... location Y
+ $rginfos[$UUID]['sizeX'] ... size X
+ $rginfos[$UUID]['sizeY'] ... size Y
+ $rginfos[$UUID]['serverIP'] ... IP address of server
+ $rginfos[$UUID]['serverIP2'] ... IP address of server
+ $rginfos[$UUID]['serveName'] ... Name of server
+ $rginfos[$UUID]['serverPort'] ... port num of server
+ $rginfos[$UUID]['serverURI'] ... URI of server
+ $rginfos[$UUID]['owner_uuid'] ... UUID of region owner
+ $rginfos[$UUID]['estate_id'] ... ID of estate
+ $rginfos[$UUID]['estate_owner'] ... UUID of estate owner
+ $rginfos[$UUID]['estate_name'] ... estate name
+ $rginfos[$UUID]['est_firstname'] ... first name
+ $rginfos[$UUID]['est_lastname'] ... last name
+ $rginfos[$UUID]['est_fullname'] ... full name
+*/
+function opensim_get_regions_infos($hg=false, $condition='', $order='', $limit='', &$db=null)
+{
+ if (!is_object($db)) $db = opensim_new_db();
+ if ($condition!='') {
+ $condition = 'WHERE '.$condition;
+ if (!$hg) $condition .= " AND (regionName NOT LIKE 'http://%' and regionName NOT LIKE 'https://%') ";
+ }
+ else {
+ if (!$hg) $condition = " WHERE (regionName NOT LIKE 'http://%' and regionName NOT LIKE 'https://%') ";
+ }
+ if ($order!='') $order = ' ORDER BY '.$order;
+ if ($limit!='') $limit = ' LIMIT '. $limit;
+
+ $rginfos = array();
+
+ $items = ' regions.uuid,regionName,locX,locY,sizeX,sizeY,serverIP,serverURI,serverHttpPort,owner_uuid,estate_map.EstateID,EstateOwner,EstateName,';
+ $uname = ' FirstName,LastName ';
+ $from = ' FROM regions';
+ $join1 = ' LEFT JOIN estate_map ON RegionID=regions.uuid ';
+ $join2 = ' LEFT JOIN estate_settings ON estate_map.EstateID=estate_settings.EstateID ';
+ $join3 = ' LEFT JOIN UserAccounts ON owner_uuid=UserAccounts.PrincipalID ';
+ $frmwh = ' FROM UserAccounts WHERE UserAccounts.PrincipalID=';
+
+ $query_str = 'SELECT '.$items.$uname.$from.$join1.$join2.$join3.$condition.$order.$limit;
+ $db->query($query_str);
+ if ($db->Errno==0) {
+ while (list($UUID,$regionName,$locX,$locY,$sizeX,$sizeY,$serverIP,$serverURI,$serverPort,
+ $owneruuid,$estateid,$estateowner,$estatename,$firstname,$lastname) = $db->next_record()) {
+ $rginfos[$UUID]['UUID'] = $UUID;
+ $rginfos[$UUID]['regionName'] = $regionName;
+ $rginfos[$UUID]['locX'] = $locX;
+ $rginfos[$UUID]['locY'] = $locY;
+ $rginfos[$UUID]['sizeX'] = $sizeX;
+ $rginfos[$UUID]['sizeY'] = $sizeY;
+ $rginfos[$UUID]['serverIP'] = $serverIP;
+ $rginfos[$UUID]['serverPort'] = $serverPort;
+ $rginfos[$UUID]['serverURI'] = $serverURI;
+ $rginfos[$UUID]['owner_uuid'] = $owneruuid;
+ $rginfos[$UUID]['estate_id'] = $estateid;
+ $rginfos[$UUID]['estate_owner'] = $estateowner;
+ $rginfos[$UUID]['estate_name'] = $estatename;
+ $rginfos[$UUID]['est_firstname']= $firstname;
+ $rginfos[$UUID]['est_lastname'] = $lastname;
+ $rginfos[$UUID]['est_fullname'] = null;
+ //
+ if ($rginfos[$UUID]['estate_owner']==null) $rginfos[$UUID]['estate_owner'] = $owneruuid;
+
+ $uri = preg_split("/[:\/]/", $serverURI);
+ if (array_key_exists(3, $uri)) {
+ $rginfos[$UUID]['serverName'] = $uri[3];
+ //$rginfos[$UUID]['serverIP2'] = gethostbyname($uri[3]);
+ }
+ else {
+ $rginfo['serverName'] = '';
+ //$rginfo['serverIP2'] = '';
+ }
+ //
+ $fullname = $firstname.' '.$lastname;
+ if ($fullname!=' ') $rginfos[$UUID]['est_fullname'] = $fullname;
+ }
+ }
+
+ // Region Owner
+ foreach($rginfos as $region) {
+ $rginfos[$region['UUID']]['rgn_firstname'] = null;
+ $rginfos[$region['UUID']]['rgn_lastname'] = null;
+ $rginfos[$region['UUID']]['rgn_fullname'] = null;
+
+ if ($region['owner_uuid']!=null) {
+ $db->query('SELECT '.$uname.$frmwh."'".$region['owner_uuid']."'");
+ list($firstname,$lastname) = $db->next_record();
+ $rginfos[$region['UUID']]['rgn_firstname'] = $firstname;
+ $rginfos[$region['UUID']]['rgn_lastname'] = $lastname;
+ $fullname = $firstname.' '.$lastname;
+ if ($fullname!=' ') $rginfos[$region['UUID']]['rgn_fullname'] = $fullname;
+ }
+ }
+
+ return $rginfos;
+}
+
+
+function opensim_set_current_region($uuid, $regionid, &$db=null)
+{
+ if (!isGUID($uuid) or !isGUID($regionid)) return false;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ if ($db->exist_table('Presence')) {
+ $sql = "UPDATE Presence SET RegionID='".$regionid."' WHERE UserID='". $uuid."'";
+ }
+ // Standalone
+ else {
+ $sql = "UPDATE GridUser SET LastRegionID='".$regionid."' WHERE UserID='". $uuid."'";
+ }
+
+ $db->query($sql);
+ if ($db->Errno!=0) return false;
+ $db->next_record();
+
+ return true;
+}
+
+
+function opensim_delete_region($uuid, &$db=null)
+{
+ if (!isGUID($uuid)) return false;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $db->query("DELETE FROM regions WHERE uuid='$uuid'");
+ if ($db->Errno!=0) return false;
+
+ return true;
+}
+
+
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+//
+// for Home Region
+//
+
+function opensim_get_home_region($uuid, &$db=null)
+{
+ if (!isGUID($uuid)) return null;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $region_name = '';
+ $db->query("SELECT regionName FROM GridUser,regions WHERE HomeRegionID=uuid AND UserID='$uuid'");
+ list($region_name) = $db->next_record();
+
+ return $region_name;
+}
+
+
+function opensim_set_home_region($uuid, $hmregion, $pos_x='128', $pos_y='128', $pos_z='0', &$db=null)
+{
+ if (!isGUID($uuid)) return false;
+ if (!isNumeric($pos_x) or !isNumeric($pos_y) or !isNumeric($pos_z)) return false;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $db->query("SELECT uuid,regionHandle FROM regions WHERE regionName='$hmregion'");
+ $errno = $db->Errno;
+ if ($errno==0) {
+ list($regionID, $regionHandle) = $db->next_record();
+
+ $homePosition = "<$pos_x,$pos_y,$pos_z>";
+ $db->query("UPDATE GridUser SET HomeRegionID='$regionID',HomePosition='$homePosition' WHERE UserID='$uuid'");
+ $errno = $db->Errno;
+ }
+
+ if ($errno!=0) return false;
+ return true;
+}
+
+
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+//
+// for Estate
+//
+
+//
+// リージョンID $region のエステート名を $estate にし,オーナーを $owner(UUID) にする.
+// エステート名と オーナー(UUID) の組み合わせが存在しない場合は,新しくエステートを作成する.
+//
+function opensim_set_region_estate($region, $estate, $owner, &$db=null)
+{
+ if (!isGUID($region) or $estate=='' or !isGUID($owner)) return false;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $estate_id = opensim_create_estate($estate, $owner, $db);
+ if ($estate_id==0) return false;
+
+ $db->query("UPDATE estate_map SET EstateID='$estate_id' WHERE RegionID='$region'");
+
+ if ($db->Errno!=0) return false;
+ return true;
+}
+
+
+//
+// Estate名 $estate, オーナーUUID $owner のエステートを作成して ID を返す.
+// 既に有る場合も,そのエステートのIDを返す.
+// エラーの場合は 0を返す.
+//
+function opensim_create_estate($estate, $owner, &$db=null)
+{
+ if ($estate=='' or !isGUID($owner)) return 0;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $db->query("SELECT EstateID FROM estate_settings WHERE EstateName='$estate' AND EstateOwner='$owner'");
+ if ($db->Errno==0) {
+ list($eid) = $db->next_record();
+ if (intval($eid)>0) return $eid;
+ }
+
+ $insert_columns = 'EstateName,AbuseEmailToEstateOwner,DenyAnonymous,ResetHomeOnTeleport,FixedSun,DenyTransacted,BlockDwell,'.
+ 'DenyIdentified,AllowVoice,UseGlobalTime,PricePerMeter,TaxFree,AllowDirectTeleport,RedirectGridX,RedirectGridY,'.
+ 'ParentEstateID,SunPosition,EstateSkipScripts,BillableFactor,PublicAccess,AbuseEmail,EstateOwner,DenyMinors,'.
+ 'AllowLandmark,AllowParcelChanges,AllowSetHome';
+ $insert_values = "'$estate','0','0','0','0','0','0','0','1','1','1','0','1','0','0','1','0','0','0','1','','$owner','0','1','1','1'";
+
+ $db->query("INSERT INTO estate_settings ($insert_columns) VALUES ($insert_values)");
+ $db->query("SELECT EstateID FROM estate_settings WHERE EstateName='$estate' AND EstateOwner='$owner'");
+
+ if ($db->Errno==0) {
+ list($eid) = $db->next_record();
+ return $eid;
+ }
+
+ return 0;
+}
+
+
+
+function opensim_get_estates_infos(&$db=null)
+{
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $estates = array();
+ $db->query('SELECT EstateID,EstateOwner,EstateName FROM estate_settings ORDER BY EstateID');
+ if ($db->Errno==0) {
+ while (list($estateid, $estateown, $estatename) = $db->next_record()) {
+ $estates[$estateid]['estate_id'] = $estateid;
+ $estates[$estateid]['estate_owner'] = $estateown;
+ $estates[$estateid]['estate_name'] = $estatename;
+ $estates[$estateid]['firstname'] = '';
+ $estates[$estateid]['lastname'] = '';
+ $estates[$estateid]['fullname'] = '';
+ }
+ }
+
+ foreach($estates as $estate) {
+ $avatar = opensim_get_avatar_name($estate['estate_owner'], false);
+ if ($avatar!=null) {
+ $estateid = $estate['estate_id'];
+ $estates[$estateid]['firstname'] = $avatar['firstname'];
+ $estates[$estateid]['lastname'] = $avatar['lastname'];
+ $estates[$estateid]['fullname'] = $avatar['fullname'];
+ }
+ }
+
+ return $estates;
+}
+
+
+//
+// SIMのリージョンIDからエステートの情報を返す.
+//
+function opensim_get_estate_info($region, &$db=null)
+{
+ if (!isGUID($region)) return null;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $firstname = null;
+ $lastname = null;
+ $fullname = null;
+ $owneruuid = null;
+
+ $rqdt = 'PrincipalID,FirstName,LastName,estate_settings.EstateID,EstateOwner,EstateName';
+ $tbls = 'UserAccounts,estate_map,estate_settings';
+ $cndn = "RegionID='$region' AND estate_map.EstateID=estate_settings.EstateID AND EstateOwner=PrincipalID";
+
+ $db->query('SELECT '.$rqdt.' FROM '.$tbls.' WHERE '.$cndn);
+ list($owneruuid, $firstname, $lastname, $estateid, $estateowner, $estatename) = $db->next_record();
+
+ $fullname = $firstname.' '.$lastname;
+ if ($fullname==' ') $fullname = null;
+
+ // owner name
+ $name['firstname'] = $firstname;
+ $name['lastname'] = $lastname;
+ $name['fullname'] = $fullname;
+ //
+ $name['owner_uuid'] = $owneruuid;
+ $name['estate_id'] = $estateid;
+ $name['estate_owner']= $estateowner;
+ $name['estate_name'] = $estatename;
+
+ return $name;
+}
+
+
+//
+// リージョンのエステートを変更する.
+//
+function opensim_set_region_estateid($region, $estateid, &$db=null)
+{
+ if (!isGUID($region) or !isNumeric($estateid)) return false;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $db->query("SELECT EstateID FROM estate_settings WHERE EstateID='$estateid'");
+ list($esid) = $db->next_record();
+ if (intval($esid)==0) return false;
+
+ $db->query("SELECT EstateID FROM estate_map WHERE RegionID='$region'");
+ list($esid) = $db->next_record();
+
+ if (intval($esid)!=$estateid) {
+ $db->query("UPDATE estate_map SET EstateID='$estateid' WHERE RegionID='$region'");
+ }
+ else if (intval($esid)==0) {
+ $db->query("INSERT INTO estate_map (RegionID,EstateID) VALUES ('$region','$estateid')");
+ }
+
+ return true;
+}
+
+
+//
+// リージョンのエステートを変更せずに,オーナーのみ変更する.
+// 従って,同じエステートを持つ他のリージョンのオーナーも変更される.
+//
+function opensim_set_estate_owner($region, $owner, &$db=null)
+{
+ if (!isGUID($region) or !isGUID($owner)) return false;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $db->query("UPDATE estate_settings,estate_map SET EstateOwner='$owner' WHERE estate_settings.EstateID=estate_map.EstateID AND RegionID='$region'");
+ $errno = $db->Errno;
+
+ if ($errno==0) $db->query("UPDATE regions SET owner_uuid='$owner' WHERE uuid='$region'");
+ if ($errno!=0) return false;
+
+ return true;
+}
+
+
+function opensim_del_estate($id, &$db=null)
+{
+ if (!isNumeric($id)) return;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $db->query("DELETE from estate_settings WHERE EstateID=$id");
+
+ return;
+}
+
+
+function opensim_update_estate($id, $name, $owner, &$db=null)
+{
+ if (!isNumeric($id)) return false;
+ if (!$name and !$owner) return false;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ if ($name) {
+ $db->query("UPDATE estate_settings SET EstateName='$name' WHERE EstateID=$id");
+ }
+
+ $uuid = opensim_get_avatar_uuid($owner, false);
+ if ($uuid) {
+ $db->query("UPDATE estate_settings SET EstateOwner='$uuid' WHERE EstateID=$id");
+ }
+
+ return true;
+}
+
+
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+//
+// for Parcel
+//
+
+function opensim_get_parcel_name($parcel, &$db=null)
+{
+ if (!isGUID($parcel)) return null;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $name = null;
+ $db->query("SELECT name FROM land WHERE UUID='$parcel'");
+
+ if ($db->Errno==0) list($name) = $db->next_record();
+
+ return $name;
+}
+
+
+function opensim_get_parcel_info($parcel, &$db=null)
+{
+ if (!isGUID($parcel)) return null;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $info = array();
+
+ $items = "RegionUUID,Name,Description,OwnerUUID,Category,SalePrice,LandStatus,LandFlags,LandingType,Dwell";
+ $query_str = "SELECT ".$items." FROM land WHERE UUID='".$parcel."'";
+
+ $db->query($query_str);
+ if ($db->Errno==0) $info = $db->next_record();
+
+ return $info;
+}
+
+
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+//
+// for Assets
+//
+
+function opensim_get_asset_data($uuid, &$db=null)
+{
+ if (!isGUID($uuid)) return null;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $asset = array();
+
+ $db->query("SELECT name,description,assetType,data,asset_flags,CreatorID FROM assets WHERE id='$uuid'");
+ list($name, $desc, $type, $data, $flag, $creator) = $db->next_record();
+
+ $asset['UUID'] = $uuid;
+ $asset['name'] = $name;
+ $asset['desc'] = $desc;
+ $asset['type'] = $type;
+ $asset['data'] = $data;
+ $asset['flag'] = $flag;
+ $asset['creator'] = $creator;
+
+ return $asset;
+}
+
+
+function opensim_display_texture_data($uuid, $prog, $xsize='0', $ysize='0', $cachedir='', $use_tga=false)
+{
+ if (!isGuid($uuid)) return false;
+ if ($prog==null or $prog=='') return false;
+
+ if ($cachedir=='') $cachedir = '/tmp';
+ $cachefile = $cachedir.'/'.$uuid;
+ $win_com = '';
+
+ // PHP module
+ $imagick = null;
+ if ($prog=='imagick') {
+ if (class_exists('Imagick')) {
+ $imagick = new Imagick();
+ }
+ else {
+ echo 'PHP module Imagick is not installed!!
';
+ return false;
+ }
+ }
+
+ // Linux Command
+ else if ($prog=='convert' or $prog=='jasper') {
+ if (file_exists('/usr/bin/'.$prog)) $path = '/usr/bin/';
+ else if (file_exists('/usr/X11R6/bin/'.$prog)) $path = '/usr/X11R6/bin/';
+ else if (file_exists('/usr/local/bin/'.$prog)) $path = '/usr/local/bin/';
+ else {
+ echo 'program '.$prog.' is not found!!
';
+ return false;
+ }
+ if ($prog=='jasper') { // JasPer does not support Targa image format.
+ $use_tga = false;
+ }
+ }
+
+ // Windows Command
+ else if ($prog=='opj_decompress') {
+ $use_tga = false;
+ $win_com = CMS_MODULE_PATH."\\win\\".$prog.".exe";
+ if (!file_exists($win_com)) {
+ echo 'program '.$prog.' is not found!!
';
+ return false;
+ }
+ }
+
+ // Check j2k to TGA command
+ if ($use_tga) {
+ $tga_com = get_j2k_to_tga_command();
+ if ($tga_com=='') $use_tga = false;
+ }
+
+ // get and save image
+ if (! ((!$use_tga and file_exists($cachefile)) or ($use_tga and file_exists($cachefile.'.tga')))) {
+ $imgdata = '';
+
+ // from MySQL Server
+ $asset = opensim_get_asset_data($uuid);
+ if ($asset) {
+ if ($asset['type']==0) {
+ $imgdata = $asset['data'];
+ }
+ }
+ else {
+ echo 'asset uuid is not found!! ('.htmlspecialchars($uuid).')
';
+ return false;
+ }
+
+/* // from Asset Server
+ //$asset_url = $ASSET_SERVER_URL.'/assets/'.$uuid;
+ $asset_url = 'http://202.26.159.200:8003/assets/'.$uuid;
+ $fp = fopen($asset_url, "rb");
+ stream_set_timeout($fp, 5);
+ $content = stream_get_contents($fp);
+ fclose($fp);
+ if (!$content) {
+ echo 'asset uuid is not found!! ('.htmlspecialchars($uuid).')
';
+ return false;
+ }
+
+ $xml = new SimpleXMLElement($content);
+ $imgdata = base64_decode($xml->Data);
+*/
+ // Save Image Data
+ $fp = fopen($cachefile, 'wb');
+ fwrite($fp, $imgdata);
+ fclose($fp);
+
+ if ($use_tga) {
+ if (!j2k_to_tga($cachefile)) $use_tga = false;
+ }
+ }
+
+ if ($use_tga && file_exists($cachefile.'.tga')) $cachefile .= '.tga';
+
+ //
+ // program for image processing of jpeg2000
+ //
+
+ // Imagick of PHP
+ if ($prog=='imagick' and $imagick!=null) {
+ $ret = $imagick->readImage($cachefile);
+ if (!$ret) {
+ echo 'Imagick could not read '.$cachefile.'!!
';
+ return false;
+ }
+ $imagick->setImageFormat('JPEG');
+ if ($xsize>0 and $ysize>0) {
+ $imagick->scaleImage($xsize, $ysize);
+ }
+
+ header("Content-Type: image/jpeg");
+ echo $imagick;
+ }
+
+ // ImageMagic (convert)
+ else if ($prog=='convert') {
+ $imgsize = '';
+ if ($xsize>0 and $ysize>0) $imgsize = ' -resize '.$xsize.'x'.$ysize.'!';
+ $prog = $path.'convert '. $cachefile.$imgsize.' jpeg:-';
+
+ header("Content-Type: image/jpeg");
+ passthru($prog);
+ }
+
+ // Jasper
+ else if ($prog=='jasper') {
+ $conv = '';
+ if ($xsize>0 and $ysize>0) {
+ $conv = get_image_size_convert_command($xsize, $ysize);
+ if ($conv!='') $conv = ' | '.$conv;
+ }
+ $prog = $path.'jasper -f '.$cachefile.' -T jpg '.$conv;
+
+ header("Content-Type: image/jpeg");
+ passthru($prog);
+ }
+
+ // opj_decompress on Windows
+ else if ($prog=='opj_decompress') {
+ if (!file_exists($cachefile.'.bmp')) {
+ $prog = $win_com.' -i '.$cachefile.' -o '.$cachefile.'.bmp';
+ exec($prog);
+ }
+ header("Content-Type: image/bmp");
+ readfile($cachefile.'.bmp');
+ }
+
+ return true;
+}
+
+
+function opensim_get_object_name($uuid, &$db=null)
+{
+ $objName = '';
+ if (!isGuid($uuid)) return null;
+ if ($uuid==UUID_ZERO) return $objName;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $query_str = "SELECT Name FROM prims WHERE UUID='$uuid'";
+
+ $db->query($query_str);
+ if ($db->Errno==0) list($objName) = $db->next_record();
+
+ return $objName;
+}
+
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+//
+// for Inventory
+//
+
+function opensim_create_avatar_inventory($uuid, $base_uuid, &$db=null)
+{
+ if (!isGuid($uuid) or !isGuid($base_uuid)) return;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $name = array();
+ if ($base_uuid!=UUID_ZERO) $name = opensim_get_avatar_name($base_uuid, false, $db);
+
+ if (isset($name['fullname'])) {
+ $folder = opensim_create_inventory_folders_dup($uuid, $base_uuid, $db);
+ $invent = opensim_create_inventory_items_dup($uuid, $base_uuid, $folder, $db);
+ opensim_create_avatar_wear_dup($uuid, $base_uuid, $invent, $db);
+ }
+ else {
+ opensim_create_default_inventory_folders($uuid, $db);
+ $invent = opensim_create_default_inventory_items($uuid, $db);
+ opensim_create_default_avatar_wear($uuid, $invent, $db);
+ }
+
+ return;
+}
+
+
+function opensim_create_avatar_wear_dup($touuid, $fromid, $invent, &$db=null)
+{
+ if (!$invent or !is_array($invent)) return false;
+ if (!is_object($db)) $db = opensim_new_db();
+ if (!$db->exist_table('Avatars')) return false;
+
+ $db->query("SELECT * FROM Avatars WHERE PrincipalID='$fromid'");
+ $errno = $db->Errno;
+
+ if ($errno==0) {
+ $db2 = opensim_new_db();
+ while (list($PrincipalID,$Name,$Value) = $db->next_record()) {
+ if (!strncasecmp($Name, 'Wearable ', 9)) {
+ $id = explode(':', $Value);
+ if (array_key_exists(1, $id)) {
+ if (isGUID($id[0]) and isGUID($id[1])) {
+ if (isset($invent[$id[0]])) $Value = $invent[$id[0]].':'.$id[1];
+ }
+ }
+ }
+ else if (!strncasecmp($Name, '_ap_', 4)) {
+ if (isGUID($Value)) {
+ if (isset($invent[$Value])) $Value = $invent[$Value];
+ }
+ }
+
+ $Name = addslashes($Name);
+ $Value = addslashes($Value);
+ //
+ $db2->query("INSERT INTO Avatars (PrincipalID,Name,Value) VALUES ('$touuid','$Name','$Value')");
+ }
+ }
+
+ if ($errno!=0) return false;
+ return true;
+}
+
+
+//
+// コピーしたアイテムのIDのコピー元とコピー先の対応を格納した配列を返す.
+//
+function opensim_create_inventory_items_dup($touuid, $fromid, $folder, &$db=null)
+{
+ if (!$folder or !is_array($folder)) return null;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $invent = array();
+ $db->query("SELECT * FROM inventoryitems WHERE avatarID='$fromid'");
+ $errno = $db->Errno;
+
+ if ($errno==0) {
+ $db2 = opensim_new_db();
+ while (list($assetID,$assetType,$inventoryName,$inventoryDescription,$inventoryNextPermissions,$inventoryCurrentPermissions,
+ $invType,$creatorID,$inventoryBasePermissions,$inventoryEveryOnePermissions,$salePrice,$saleType,$creationDate,
+ $groupID,$groupOwned,$flags,$inventoryID,$avatarID,$parentFolderID,$inventoryGroupPermissions) = $db->next_record()) {
+
+ if (isset($folder[$parentFolderID]) and $folder[$parentFolderID]->type=='46') continue; // Current Outfit
+
+ $inventoryName = addslashes($inventoryName);
+ $inventoryDescription = addslashes($inventoryDescription);
+
+ $avatarID = $touuid;
+ $inventID = make_random_guid();
+ if (isset($folder[$parentFolderID])) $parent = $folder[$parentFolderID]->folderID;
+ else $parent = UUID_ZERO;
+ $invent[$inventoryID] = $inventID;
+ //
+ $db2->query('INSERT INTO inventoryitems (assetID,assetType,inventoryName,inventoryDescription,inventoryNextPermissions,'.
+ 'inventoryCurrentPermissions,invType,creatorID,inventoryBasePermissions,inventoryEveryOnePermissions,salePrice,'.
+ 'saleType,creationDate,groupID,groupOwned,flags,inventoryID,avatarID,parentFolderID,inventoryGroupPermissions) '.
+ "VALUES ('$assetID','$assetType','$inventoryName','$inventoryDescription','$inventoryNextPermissions','$inventoryCurrentPermissions',".
+ "'$invType','$creatorID','$inventoryBasePermissions','$inventoryEveryOnePermissions','$salePrice','$saleType','$creationDate',".
+ "'$groupID','$groupOwned','$flags','$inventID','$avatarID','$parent','$inventoryGroupPermissions')");
+ }
+ }
+
+ return $invent;
+}
+
+
+//
+// 作成したフォルダーの情報を返す.キーはコピー元フォルダーのフォルダーID
+//
+function opensim_create_inventory_folders_dup($touuid, $fromid, &$db=null)
+{
+ if (!isGUID($fromid)) return null;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $folder = array();
+
+ $db->query("SELECT * FROM inventoryfolders WHERE agentID='$fromid'");
+ $errno = $db->Errno;
+
+ if ($errno==0) {
+ while(list($folderName,$type,$version,$folderID,$agentID,$parentFolderID) = $db->next_record()) {
+ $folder[$folderID] = new stdClass();
+ $folder[$folderID]->folderName = $folderName;
+ $folder[$folderID]->type = $type;
+ $folder[$folderID]->version = $version;
+ $folder[$folderID]->folderID = make_random_guid();
+ $folder[$folderID]->agentID = $touuid;
+ $folder[$folderID]->parentFolderID = $parentFolderID;
+ }
+
+ foreach($folder as $fid=>$fld) {
+ $parent = UUID_ZERO;
+ if ($fld->parentFolderID) {
+ if (isset($folder[$fld->parentFolderID])) $parent = $folder[$fld->parentFolderID]->folderID;
+ }
+ $folder[$fid]->parentFolderID = $parent;
+
+ $folderName = addslashes($fld->folderName);
+ $folderType = $fld->type;
+ $version = $fld->version;
+ $folderID = $fld->folderID;
+ //
+ $db->query("INSERT INTO inventoryfolders (folderName,type,version,folderID,agentID,parentFolderID) ".
+ "VALUES ('$folderName','$folderType','$version','$folderID','$touuid','$parent')");
+ }
+ }
+
+ return $folder;
+}
+
+
+function opensim_create_default_avatar_wear($uuid, $invent, &$db=null)
+{
+ if (!is_object($db)) $db = opensim_new_db();
+ if (!$db->exist_table('Avatars')) return false;
+
+ $db->query("INSERT INTO Avatars (PrincipalID,Name,Value) VALUES ('$uuid','AvatarHeight','".DEFAULT_AVATAR_HEIGHT."')");
+ $db->query("INSERT INTO Avatars (PrincipalID,Name,Value) VALUES ('$uuid','AvatarType','1')");
+ $db->query("INSERT INTO Avatars (PrincipalID,Name,Value) VALUES ('$uuid','Serial','0')");
+ $db->query("INSERT INTO Avatars (PrincipalID,Name,Value) VALUES ('$uuid','VisualParams','".DEFAULT_AVATAR_PARAMS."')");
+
+ if (is_array($invent)) {
+ if (isset($invent['Shape']))
+ $db->query("INSERT INTO Avatars (PrincipalID,Name,Value) VALUES ('$uuid','Wearable 0:0','".$invent['Shape'].':'.DEFAULT_ASSET_SHAPE."')");
+ if (isset($invent['Skin']))
+ $db->query("INSERT INTO Avatars (PrincipalID,Name,Value) VALUES ('$uuid','Wearable 1:0','".$invent['Skin']. ':'.DEFAULT_ASSET_SKIN."')");
+ if (isset($invent['Hair']))
+ $db->query("INSERT INTO Avatars (PrincipalID,Name,Value) VALUES ('$uuid','Wearable 2:0','".$invent['Hair']. ':'.DEFAULT_ASSET_HAIR."')");
+ if (isset($invent['Eyes']))
+ $db->query("INSERT INTO Avatars (PrincipalID,Name,Value) VALUES ('$uuid','Wearable 3:0','".$invent['Eyes']. ':'.DEFAULT_ASSET_EYES."')");
+ if (isset($invent['Shirt']))
+ $db->query("INSERT INTO Avatars (PrincipalID,Name,Value) VALUES ('$uuid','Wearable 4:0','".$invent['Shirt'].':'.DEFAULT_ASSET_SHIRT."')");
+ if (isset($invent['Pants']))
+ $db->query("INSERT INTO Avatars (PrincipalID,Name,Value) VALUES ('$uuid','Wearable 5:0','".$invent['Pants'].':'.DEFAULT_ASSET_PANTS."')");
+ }
+
+ return true;
+}
+
+
+function opensim_create_default_inventory_items($uuid, &$db=null)
+{
+ if (!isGUID($uuid)) return false;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $db->query("SELECT folderID FROM inventoryfolders WHERE agentID='$uuid' AND type='13'"); // Body Parts Folder
+ list($body_folder) = $db->next_record();
+ $db->query("SELECT folderID FROM inventoryfolders WHERE agentID='$uuid' AND type='5'"); // Clothing Folder
+ list($cloth_folder) = $db->next_record();
+ if (!$body_folder or !$cloth_folder) return false;
+
+ $default_inv = array();
+
+ $create_time = time();
+ $insert_columns = 'assetID,assetType,inventoryName,inventoryDescription,inventoryNextPermissions,inventoryCurrentPermissions,invType,'.
+ 'creatorID,inventoryBasePermissions,inventoryEveryOnePermissions,creationDate,flags,inventoryID,avatarID,parentFolderID,'.
+ 'inventoryGroupPermissions';
+ $insert_common = "'','581632','581632','18','$uuid','581632','581632','$create_time'";
+
+ $invID = make_random_guid();
+ $db->query("INSERT INTO inventoryitems ($insert_columns) ".
+ "VALUES ('".DEFAULT_ASSET_SHAPE."','13','Default Shape',$insert_common,'0','$invID','$uuid','$body_folder', '581632')");
+ $errno = $db->Errno;
+
+ if ($errno==0) {
+ $default_inv['Shape'] = $invID;
+ $invID = make_random_guid();
+ $db->query("INSERT INTO inventoryitems ($insert_columns) ".
+ "VALUES ('".DEFAULT_ASSET_SKIN. "','13','Default Skin', $insert_common,'1','$invID','$uuid','$body_folder', '581632')");
+ $errno = $db->Errno;
+ }
+ if ($errno==0) {
+ $default_inv['Skin'] = $invID;
+ $invID = make_random_guid();
+ $db->query("INSERT INTO inventoryitems ($insert_columns) ".
+ "VALUES ('".DEFAULT_ASSET_HAIR. "','13','Default Hair', $insert_common,'2','$invID','$uuid','$body_folder', '581632')");
+ $errno = $db->Errno;
+ }
+ if ($errno==0) {
+ $default_inv['Hair'] = $invID;
+ $invID = make_random_guid();
+ $db->query("INSERT INTO inventoryitems ($insert_columns) ".
+ "VALUES ('".DEFAULT_ASSET_EYES. "','13','Default Eyes', $insert_common,'3','$invID','$uuid','$body_folder', '581632')");
+ $errno = $db->Errno;
+ }
+ if ($errno==0) {
+ $default_inv['Eyes'] = $invID;
+ $invID = make_random_guid();
+ $db->query("INSERT INTO inventoryitems ($insert_columns) ".
+ "VALUES ('".DEFAULT_ASSET_SHIRT. "','5','Default Shirt',$insert_common,'4','$invID','$uuid','$cloth_folder','581632')");
+ $errno = $db->Errno;
+ }
+ if ($errno==0) {
+ $default_inv['Shirt'] = $invID;
+ $invID = make_random_guid();
+ $db->query("INSERT INTO inventoryitems ($insert_columns) ".
+ "VALUES ('".DEFAULT_ASSET_PANTS. "','5','Default Pants',$insert_common,'5','$invID','$uuid','$cloth_folder','581632')");
+ $errno = $db->Errno;
+ }
+ if ($errno==0) {
+ $default_inv['Pants'] = $invID;
+ }
+
+ return $default_inv;
+}
+
+
+function opensim_create_default_inventory_folders($uuid, &$db=null)
+{
+ if (!isGUID($uuid)) return false;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $my_inventory = make_random_guid();
+ $db->query('INSERT INTO inventoryfolders (folderName,type,version,folderID,agentID,parentFolderID) '.
+ "VALUES ('My Inventory','8','1','$my_inventory','$uuid','".UUID_ZERO."')");
+ //
+ $db->query('INSERT INTO inventoryfolders (folderName,type,version,folderID,agentID,parentFolderID) '.
+ "VALUES ('Textures','0','1','".make_random_guid()."','$uuid','$my_inventory')");
+ $db->query('INSERT INTO inventoryfolders (folderName,type,version,folderID,agentID,parentFolderID) '.
+ "VALUES ('Sounds','1','1','".make_random_guid()."','$uuid','$my_inventory')");
+ $db->query('INSERT INTO inventoryfolders (folderName,type,version,folderID,agentID,parentFolderID) '.
+ "VALUES ('Calling Cards','2','1','".make_random_guid()."','$uuid','$my_inventory')");
+ $db->query('INSERT INTO inventoryfolders (folderName,type,version,folderID,agentID,parentFolderID) '.
+ "VALUES ('Landmarks','3','1','".make_random_guid()."','$uuid','$my_inventory')");
+ $db->query('INSERT INTO inventoryfolders (folderName,type,version,folderID,agentID,parentFolderID) '.
+ "VALUES ('Clothing','5','1','".make_random_guid()."','$uuid','$my_inventory')");
+ $db->query('INSERT INTO inventoryfolders (folderName,type,version,folderID,agentID,parentFolderID) '.
+ "VALUES ('Objects','6','1','".make_random_guid()."','$uuid','$my_inventory')");
+ $db->query('INSERT INTO inventoryfolders (folderName,type,version,folderID,agentID,parentFolderID) '.
+ "VALUES ('Notecards','7','1','".make_random_guid()."','$uuid','$my_inventory')");
+ $db->query('INSERT INTO inventoryfolders (folderName,type,version,folderID,agentID,parentFolderID) '.
+ "VALUES ('Scripts','10','1','".make_random_guid()."','$uuid','$my_inventory')");
+ $db->query('INSERT INTO inventoryfolders (folderName,type,version,folderID,agentID,parentFolderID) '.
+ "VALUES ('Body Parts','13','1','".make_random_guid()."','$uuid','$my_inventory')");
+ $db->query('INSERT INTO inventoryfolders (folderName,type,version,folderID,agentID,parentFolderID) '.
+ "VALUES ('Trash','14','1','".make_random_guid()."','$uuid','$my_inventory')");
+ $db->query('INSERT INTO inventoryfolders (folderName,type,version,folderID,agentID,parentFolderID) '.
+ "VALUES ('Photo Album','15','1','".make_random_guid()."','$uuid','$my_inventory')");
+ $db->query('INSERT INTO inventoryfolders (folderName,type,version,folderID,agentID,parentFolderID) '.
+ "VALUES ('Lost And Found','16','1','".make_random_guid()."','$uuid','$my_inventory')");
+ $db->query('INSERT INTO inventoryfolders (folderName,type,version,folderID,agentID,parentFolderID) '.
+ "VALUES ('Animations','20','1','".make_random_guid()."','$uuid','$my_inventory')");
+ $db->query('INSERT INTO inventoryfolders (folderName,type,version,folderID,agentID,parentFolderID) '.
+ "VALUES ('Gestures','21','1','".make_random_guid()."','$uuid','$my_inventory')");
+ return true;
+}
+
+
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+//
+// for Password
+//
+
+function opensim_get_password($uuid, $tbl='', &$db=null)
+{
+ if (!isGUID($uuid)) return null;
+ if (!isAlphabetNumeric($tbl, true)) return null;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $passwdhash = null;
+ $passwdsalt = null;
+
+ if ($tbl=='' or $tbl=='auth') {
+ if ($db->exist_table('auth')) {
+ $db->query("SELECT passwordHash,passwordSalt FROM auth WHERE UUID='$uuid'");
+ list($passwdhash, $passwdsalt) = $db->next_record();
+ }
+ }
+
+ if ($passwdhash==null and $passwdsalt==null) {
+ if ($tbl=='' or $tbl=='users') {
+ if ($db->exist_table('users')) {
+ $db->query("SELECT passwordHash,passwordSalt FROM users WHERE UUID='$uuid'");
+ list($passwdhash, $passwdsalt) = $db->next_record();
+ }
+ }
+ }
+
+ $ret['passwordHash'] = $passwdhash;
+ $ret['passwordSalt'] = $passwdsalt;
+ return $ret;
+}
+
+
+function opensim_set_password($uuid, $passwdhash, $passwdsalt='', $tbl='', &$db=null)
+{
+ if (!isGUID($uuid)) return false;
+ if (!isAlphabetNumeric($passwdhash)) return false;
+ if (!isAlphabetNumeric($passwdsalt, true)) return false;
+ if (!isAlphabetNumeric($tbl, true)) return false;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $setpasswd = "passwordHash='$passwdhash'";
+ if ($passwdsalt!='') {
+ $setpasswd .= ",passwordSalt='$passwdsalt'";
+ }
+
+ $errno = 0;
+ if ($tbl=='' or $tbl=='auth') {
+ if ($db->exist_table('auth')) {
+ $db->query("UPDATE auth SET ".$setpasswd." WHERE UUID='$uuid'");
+ $errno = $db->Errno;
+ }
+ }
+
+ if (($tbl=='' or $tbl=='users') and $errno==0) {
+ if ($db->exist_table('users')) {
+ $db->query("UPDATE users SET ".$setpasswd." WHERE UUID='$uuid'");
+ if ($db->Errno!=0) {
+ if (!$db->exist_table('auth')) $errno = 99;
+ }
+ }
+ }
+
+ if ($errno!=0) return false;
+ return true;
+}
+
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+//
+// for Voice (VoIP)
+//
+
+function opensim_get_voice_mode($region, &$db=null)
+{
+ if (!isGUID($region)) return -1;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $voiceflag = 0x60000000;
+
+ $count = 0;
+ $db->query("SELECT LandFlags FROM land WHERE RegionUUID='$region'");
+ while (list($flag) = $db->next_record()) {
+ $voiceflag &= $flag;
+ $count++;
+ }
+
+ if ($count>0) {
+ if ($voiceflag==0x20000000) return 1; // プライベート
+ else if ($voiceflag==0x40000000) return 2; // パーセル
+ else return 0; // 無効
+ }
+
+ return 9; // 不明
+}
+
+
+function opensim_set_voice_mode($region, $mode, &$db=null)
+{
+ if (!isGUID($region)) return false;
+ if (!preg_match('/^[0-2]$/', $mode)) return false;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $colum = 0;
+ $vflags = array();
+
+ $db->query("SELECT UUID,LandFlags FROM land WHERE RegionUUID='$region'");
+ while (list($UUID, $flag) = $db->next_record()) {
+ $flag &= 0x9fffffff;
+ if ($mode==1) $flag |= 0x20000000;
+ else if ($mode==2) $flag |= 0x40000000;
+
+ $vflags[$colum]['UUID'] = $UUID;
+ $vflags[$colum]['flag'] = $flag;
+ $colum++;
+ }
+
+ foreach($vflags as $vflag) {
+ $UUID = $vflag['UUID'];
+ $flag = $vflag['flag'];
+ $db->query("UPDATE land SET LandFlags='$flag' WHERE UUID='$UUID'");
+ }
+
+ return true;
+}
+
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+//
+// for Currency
+
+// Transaction Type
+$TransactionType['900'] = 'BirthGift';
+$TransactionType['901'] = 'AwardPoints';
+$TransactionType['1002'] = 'GroupCreate';
+$TransactionType['1004'] = 'GroupJoin';
+$TransactionType['1101'] = 'UploadCharge';
+$TransactionType['1102'] = 'LandAuction';
+$TransactionType['1103'] = 'ClassifiedCharge';
+$TransactionType['2003'] = 'ParcelDirFee';
+$TransactionType['2005'] = 'ClassifiedRenew';
+$TransactionType['2900'] = 'ScheduledFee';
+$TransactionType['3000'] = 'GiveInventory';
+$TransactionType['5000'] = 'ObjectSale';
+$TransactionType['5001'] = 'Gift';
+$TransactionType['5002'] = 'LandSale';
+$TransactionType['5003'] = 'ReferBonus';
+$TransactionType['5004'] = 'InvntorySale';
+$TransactionType['5005'] = 'RefundPurchase';
+$TransactionType['5006'] = 'LandPassSale';
+$TransactionType['5007'] = 'DwellBonus';
+$TransactionType['5008'] = 'PayObject';
+$TransactionType['5009'] = 'ObjectPays';
+$TransactionType['5010'] = 'BuyMoney';
+$TransactionType['5011'] = 'MoveMoney';
+$TransactionType['5012'] = 'SendMoney';
+$TransactionType['6003'] = 'GroupLiability';
+$TransactionType['6004'] = 'GroupDividend';
+$TransactionType['10000'] = 'StipendBasic';
+
+
+//
+function opensim_get_transaction_type($type)
+{
+ global $TransactionType;
+
+ if (!array_key_exists($type, $TransactionType)) return null;
+
+ return $TransactionType[$type];
+}
+
+
+//
+// status: 0-SUCCESS, 1-PENDING, 2-FAILED(EXPIRED), 9-ERROR
+//
+function opensim_set_currency_transaction($srcId, $dstId, $amount, $type, $status, $desc, &$db=null)
+{
+ if (!isNumeric($amount)) return false;
+ if (!isGUID($srcId)) $srcId = UUID_ZERO;
+ if (!isGUID($dstId)) $dstId = UUID_ZERO;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $handle = 0;
+ $secure = UUID_ZERO;
+ $client = $srcId;
+ $UUID = make_random_guid();
+ $srcID = $srcId;
+ $dstID = $dstId;
+ if ($client==UUID_ZERO) $client = $dstId;
+
+ $avt = opensim_get_avatar_session($client);
+ if ($avt!=null) {
+ $region = $avt['regionID'];
+ $secure = $avt['secureID'];
+
+ $rgn = opensim_get_region_info($region);
+ if ($rgn!=null) $handle = $rgn['regionHandle'];
+ }
+
+ $senderBalance = opensim_get_currency_balance($srcID) - $amount;
+ $receiverBalance = opensim_get_currency_balance($dstID) + $amount;
+
+ $sql = 'INSERT INTO transactions (UUID,sender,receiver,amount,senderBalance,receiverBalance,objectUUID,objectName'.
+ 'regionHandle,type,time,secure,status,description,commonName) '.
+ "VALUES ('".$UUID."','".
+ $srcID."','".
+ $dstID."','".
+ $amount."','".
+ $senderBalance."','".
+ $receiverBalance."','".
+ UUID_ZERO."','".
+ "','".
+ $handle."','".
+ $db->escape($type)."','".
+ time()."','".
+ $secure."','".
+ $db->escape($status)."','".
+ $db->escape($desc)."','".
+ "')";
+ $db->query($sql);
+
+ if ($db->Errno==0) return true;
+ return false;
+}
+
+
+function opensim_set_currency_balance($uuid, $amount, &$db=null)
+{
+ if (!isGUID($uuid) or !isNumeric($amount)) return false;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $userid = $db->escape($uuid);
+
+ $db->lock_table('balances');
+
+ $db->query("SELECT balance FROM balances WHERE user='$userid'");
+ if ($db->Errno==0) {
+ list($cash) = $db->next_record();
+ $balance = (integer)$cash + (integer)$amount;
+
+ $db->query("UPDATE balances SET balance='$balance' WHERE user='$userid'");
+ if ($db->Errno==0) $db->next_record();
+ }
+
+ $db->unlock_table();
+
+ return true;
+}
+
+
+function opensim_get_currency_balance($uuid, &$db=null)
+{
+ if (!isGUID($uuid)) return 0;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $userid = $db->escape($uuid);
+ $db->query("SELECT balance FROM balances WHERE user='$userid'");
+
+ $cash = 0;
+ if ($db->Errno==0) list($cash) = $db->next_record();
+
+ return (integer)$cash;
+}
+
+
+function opensim_del_currency_expired(&$db=null)
+{
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $db->query("DELETE FROM transactions WHERE status='2'");
+
+ return;
+}
+
+
+function opensim_get_currency_transactions($condition='', $order='', $limit='', &$db=null)
+{
+ if (!is_object($db)) $db = opensim_new_db();
+ if ($condition!='') $condition = 'WHERE '.$condition;
+ if ($order!='') $order = ' ORDER BY '.$order;
+ if ($limit!='') $limit = ' LIMIT '. $limit;
+
+ $query_str = 'SELECT UUID,sender,receiver,amount,senderBalance,receiverBalance,'.
+ 'objectUUID,objectName,type,time,status,commonName,description FROM transactions '.
+ $condition.$order.$limit;
+ $db->query($query_str);
+
+ $trans = array();
+ if ($db->Errno==0) {
+ while (list($UUID,$sender,$receiver,$amount,$sndBalance,$rcvBalance,
+ $objUUID,$objName,$type,$time,$status,$comName,$desc)=$db->next_record()) {
+ $trans[$UUID]['UUID'] = $UUID;
+ $trans[$UUID]['sender'] = $sender;
+ $trans[$UUID]['receiver'] = $receiver;
+ $trans[$UUID]['amount'] = $amount;
+ $trans[$UUID]['senderBalance'] = $sndBalance;
+ $trans[$UUID]['receiverBalance'] = $rcvBalance;
+ $trans[$UUID]['objectUUID'] = $objUUID;
+ $trans[$UUID]['objectName'] = $objName;
+ $trans[$UUID]['type'] = $type;
+ $trans[$UUID]['time'] = $time;
+ $trans[$UUID]['status'] = $status;
+ $trans[$UUID]['commonName'] = $comName;
+ $trans[$UUID]['description'] = $desc;
+ }
+ }
+ return $trans;
+}
+
+
+function opensim_get_currency_amounts_log($uuid, $condition='', $order='', $limit='', &$db=null)
+{
+ if (!isGUID($uuid)) return null;
+ if (!is_object($db)) $db = opensim_new_db();
+ if ($condition!='') $condition = ' AND ('.$condition.')';
+ if ($order!='') $order = ' ORDER BY '.$order;
+ if ($limit!='') $limit = ' LIMIT '. $limit;
+
+ $condition = " WHERE (sender='$uuid' OR receiver='$uuid') AND sender!=receiver AND (status='0' OR status='9') ".
+ $condition.$order.$limit;
+ $query_str = 'SELECT UUID,sender,receiver,amount,senderBalance,receiverBalance,objectUUID,objectName,'.
+ 'regionHandle,regionUUID,type,time,status,commonName,description FROM transactions '.$condition;
+ $db->query($query_str);
+
+ $trans = array();
+ if ($db->Errno==0) {
+ while (list($UUID,$sender,$receiver,$amount,$sndBalance,$rcvBalance,$objUUID,$objName,
+ $regionHandle,$regionUUID,$type,$time,$status,$comName,$desc)=$db->next_record()) {
+ $trans[$UUID]['UUID'] = $UUID;
+ $trans[$UUID]['sender'] = $sender;
+ $trans[$UUID]['receiver'] = $receiver;
+ $trans[$UUID]['amount'] = $amount;
+ $trans[$UUID]['senderBalance'] = $sndBalance;
+ $trans[$UUID]['receiverBalance'] = $rcvBalance;
+ $trans[$UUID]['objectUUID'] = $objUUID;
+ $trans[$UUID]['objectName'] = $objName;
+ $trans[$UUID]['regionHandle'] = $regionHandle;
+ $trans[$UUID]['regionUUID'] = $regionUUID;
+ $trans[$UUID]['type'] = $type;
+ $trans[$UUID]['time'] = $time;
+ $trans[$UUID]['status'] = $status;
+ $trans[$UUID]['commonName'] = $comName;
+ $trans[$UUID]['description'] = $desc;
+ }
+ }
+ return $trans;
+
+}
+
+
+function opensim_get_currency_amounts_num($uuid, $condition='', &$db=null)
+{
+ if (!isGUID($uuid)) return 0;
+ if (!is_object($db)) $db = opensim_new_db();
+ if ($condition!='') $condition = 'AND ('.$condition.')';
+
+ $count = 0;
+
+ $condition = "WHERE (sender='$uuid' OR receiver='$uuid') AND sender!=receiver AND (status='0' OR status='9') ".$condition;
+ $query_str = 'SELECT COUNT(*) FROM transactions '.$condition;
+ $db->query($query_str);
+ list($count) = $db->next_record();
+
+ return (integer)$count;
+
+}
+
+
+function opensim_set_userinfo($user, $simip, $avatar, $pass, &$db=null)
+{
+ if (!isGUID($user)) return false;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $db_user = null;
+ $db->query("SELECT user,simip,avatar,pass FROM userinfo WHERE user='$user'");
+ if ($db->Errno==0) {
+ list($db_user, $db_simip, $db_avatar, $db_pass) = $db->next_record();
+ }
+
+ if ($db_user) {
+ if ($simip !=null) $db_simip = $simip;
+ if ($avatar!=null) $db_avatar = $avatar;
+ if ($pass !=null) $db_pass = $pass;
+ $query_str = "UPDATE userinfo SET simip='$db_simip', avatar='$db_avatar', pass='$db_pass' WHERE user='$uuid'";
+ }
+ else {
+ $query_str = "INSERT INTO userinfo (user, simip, avatar, pass) VALUES ('$user','$simip','$avatar','$pass')";
+ }
+
+ $db->query($query_str);
+
+ if ($db->Errno==0) return true;
+ return false;
+}
+
+
+function opensim_get_userinfo($uuid, &$db=null)
+{
+ if (!isGUID($uuid)) return null;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $query_str = "SELECT user,simip,avatar,pass FROM userinfo WHERE user='$uuid'";
+ $db->query($query_str);
+
+ list($user, $simip, $avatar, $pass) = $db->next_record();
+
+ $info['UUID'] = $user;
+ $info['user'] = $user;
+ $info['simip'] = $simip;
+ $info['avatar'] = $avatar;
+ $info['pass'] = $pass;
+
+ return $info;
+}
+
+
+function opensim_get_userinfos($condition='', $order='', $limit='', &$db=null)
+{
+ if (!is_object($db)) $db = opensim_new_db();
+ if ($condition!='') $condition = 'WHERE '.$condition;
+ if ($order!='') $order = ' ORDER BY '.$order;
+ if ($limit!='') $limit = ' LIMIT '. $limit;
+
+ $infos = array();
+ $query_str = 'SELECT user,simip,avatar,pass,type,class FROM userinfo '.$condition.$order.$limit;
+
+ $db->query($query_str);
+ if ($db->Errno==0) {
+ while (list($UUID, $simip, $avatar, $pass, $type, $class) = $db->next_record()) {
+ $infos[$UUID]['UUID'] = $UUID;
+ $infos[$UUID]['user'] = $UUID;
+ $infos[$UUID]['simip'] = $simip;
+ $infos[$UUID]['avatar'] = $avatar;
+ $infos[$UUID]['pass'] = $pass;
+ $infos[$UUID]['type'] = $type;
+ $infos[$UUID]['class'] = $class;
+ }
+ }
+
+ return $infos;
+}
+
+
+function opensim_get_totalsales($condition='', $order='', $limit='', &$db=null)
+{
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $db->query('SELECT MIN(time) FROM totalsales');
+ list($mintime) = $db->next_record();
+
+ //
+ $sales = array();
+
+ if ($condition!='') $condition = 'WHERE '.$condition;
+ if ($order!='') $order = ' ORDER BY '.$order;
+ if ($limit!='') $limit = ' LIMIT '. $limit;
+
+ $query_str = 'SELECT user,objectUUID,type,TotalCount,TotalAmount FROM totalsales '.$condition.$order.$limit;
+
+ $db->query($query_str);
+ if ($db->Errno==0) {
+ $num = 0;
+ while (list($user, $objUUID, $type, $count, $amount) = $db->next_record()) {
+ $sales[$num]['user'] = $user;
+ $sales[$num]['object'] = opensim_get_object_name($objUUID);
+ $sales[$num]['type'] = $type;
+ $sales[$num]['count'] = $count;
+ $sales[$num]['amount'] = $amount;
+ $sales[$num]['time'] = $mintime;
+ $name = opensim_get_avatar_name($user);
+ $sales[$num]['name'] = $name['fullname'];
+ if ($sales[$num]['name'] =='') $sales[$num]['name'] = $user;
+ if ($sales[$num]['object']=='') $sales[$num]['object'] = $objUUID;
+ //
+ $num++;
+ }
+ }
+
+ return $sales;
+}
+
+
+function opensim_regenerate_totalsales(&$since=0, &$db=null)
+{
+ if (!is_object($db)) $db = opensim_new_db();
+ $time = $since;
+ if ($time==null) $time = 0;
+
+ $trans = array();
+
+ $query_str = 'SELECT receiver,objectUUID,type,COUNT(*),SUM(amount),MIN(time) FROM transactions '.
+ " WHERE sender != receiver AND status = '0' AND time>='$time' AND sender != '".UUID_ZERO."' ".
+ " GROUP BY receiver,objectUUID,type";
+
+ $db->query($query_str);
+ if ($db->Errno==0) {
+ $num = 0;
+ while (list($user, $objID, $type, $count, $amount, $time) = $db->next_record()) {
+ $trans[$num]['user'] = $user;
+ $trans[$num]['object'] = $objID;
+ $trans[$num]['type'] = $type;
+ $trans[$num]['count'] = $count;
+ $trans[$num]['amount'] = $amount;
+ $trans[$num]['time'] = $time;
+ $num++;
+ }
+ }
+ else return false;
+
+ //
+ $db->lock_table('totalsales');
+ $db->query('DELETE FROM totalsales');
+ if ($db->Errno!=0) return false;
+
+ $mintime = time();
+ for ($i=0; $i<$num; $i++) {
+ $UUID = make_random_guid();
+ $user = $trans[$i]['user'];
+ $objID = $trans[$i]['object'];
+ $type = $trans[$i]['type'];
+ $count = $trans[$i]['count'];
+ $amount = $trans[$i]['amount'];
+ $time = $trans[$i]['time'];
+
+ $query_str = 'INSERT INTO totalsales (UUID, user, objectUUID, type, TotalCount, TotalAmount, time) '.
+ "VALUES ('$UUID','$user','$objID','$type','$count','$amount','$time')";
+ $db->query($query_str);
+ if ($db->Errno!=0) break;
+
+ if ($time<$mintime) $mintime = $time;
+ }
+
+ $db->unlock_table();
+
+ if ($i!=$num) return false;
+
+ $since = $mintime;
+ return true;
+}
+
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+//
+// Tools
+//
+
+function opensim_get_servers_ip(&$db=null)
+{
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $ips = array();
+
+ $db->query("SELECT DISTINCT serverURI FROM regions");
+ if ($db->Errno==0) {
+ $count = 0;
+ while (list($url) = $db->next_record()) {
+ $item = preg_split("/[:\/]/", $url);
+ if (array_key_exists(3, $item)) {
+ $ips[$count] = gethostbyname($item[3]);
+ $count++;
+ }
+ }
+ }
+
+/*
+ $db->query("SELECT DISTINCT serverIP FROM regions");
+ if ($db->Errno==0) {
+ $count = 0;
+ while (list($server) = $db->next_record()) {
+ $ips[$count] = gethostbyname($server);
+ $count++;
+ }
+ }
+*/
+
+/*
+ $db->query("SELECT DISTINCT serverURI FROM regions");
+ if ($db->Errno==0) {
+ $count = 0;
+ while (list($server) = $db->next_record()) {
+ $uri = preg_split("/[:\/]/", $server);
+ if (array_key_exists(3, $uri)) {
+ $ips[$count] = gethostbyname($uri[3]);
+ $count++;
+ }
+ }
+ }
+*/
+ return $ips;
+}
+
+
+function opensim_get_servers_name(&$db=null)
+{
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $nms = array();
+
+ $db->query("SELECT DISTINCT serverURI FROM regions");
+ if ($db->Errno==0) {
+ $count = 0;
+ while (list($server) = $db->next_record()) {
+ $uri = preg_split("/[:\/]/", $server);
+ if (array_key_exists(3, $uri)) {
+ $nms[$count] = $uri[3];
+ $count++;
+ }
+ }
+ }
+
+ return $nms;
+}
+
+
+function opensim_get_server_info($uuid, &$db=null)
+{
+ if (!isGUID($uuid)) return null;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ $ret = array();
+
+ $sql = "SELECT serverIP,serverHttpPort,serverURI,regionSecret FROM GridUser ";
+ $sql.= "INNER JOIN regions ON regions.uuid=GridUser.LastRegionID WHERE GridUser.UserID='".$uuid."'";
+ $db->query($sql);
+ if ($db->Errno==0) list($serverip, $httpport, $serveruri, $secret) = $db->next_record();
+
+ if ($db->Errno==0) {
+ $ret["serverIP"] = $serverip;
+ $ret["serverHttpPort"] = $httpport;
+ $ret["serverURI"] = $serveruri;
+ $ret["regionSecret"] = $secret;
+ //
+ $uri = preg_split("/[:\/]/", $serveruri);
+ if (array_key_exists(3, $uri)) {
+ $ret['serverName'] = $uri[3];
+// $ret["serverIP2"] = gethostbyname($uri[3]);
+ }
+ }
+ return $ret;
+}
+
+
+//
+// DNSが引けないと長時間待たされる
+//
+function opensim_is_access_from_region_server()
+{
+ /////////////////////////
+ return true;
+ /////////////////////////
+
+ $ip_match = false;
+ $remote_addr = $_SERVER['REMOTE_ADDR'];
+ $server_addr = $_SERVER['SERVER_ADDR'];
+
+ if ($remote_addr==$server_addr or $remote_addr=="127.0.0.1") return true;
+
+ $ips = opensim_get_servers_ip();
+
+ foreach($ips as $ip) {
+ if ($ip==$remote_addr) {
+ $ip_match = true;
+ break;
+ }
+ }
+
+ return $ip_match;
+}
+
+
+//
+function opensim_check_secure_session($uuid, $regionid, $secure, &$db=null)
+{
+ if (!isGUID($uuid) or !isGUID($secure)) return false;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ if ($db->exist_table('Presence')) {
+ $sql = "SELECT UserID FROM Presence WHERE UserID='".$uuid."' AND SecureSessionID='".$secure."'";
+ if (isGUID($regionid)) $sql = $sql." AND RegionID='".$regionid."'";
+ }
+ // Standalone
+ else {
+ $sql = "SELECT UserID FROM GridUser WHERE UserID='".$uuid."' AND Online='True'";
+ if (isGUID($regionid)) $sql = $sql." AND LastRegionID='".$regionid."'";
+ }
+
+ $db->query($sql);
+ if ($db->Errno!=0) return false;
+
+ list($UUID) = $db->next_record();
+ if ($UUID!=$uuid) return false;
+ return true;
+}
+
+
+//
+function opensim_check_region_secret($uuid, $secret, &$db=null)
+{
+ if (!isGUID($uuid)) return false;
+ if (!is_object($db)) $db = opensim_new_db();
+
+ //
+ $sql = "SELECT UUID FROM regions WHERE UUID='".$uuid."' AND regionSecret='".$db->escape($secret)."'";
+ $db->query($sql);
+ if ($db->Errno==0) {
+ list($UUID) = $db->next_record();
+ if ($UUID==$uuid) return true;
+ }
+
+ return false;
+}
+
+
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+//
+// Management of System
+//
+
+function opensim_clear_login_table(&$db=null)
+{
+ if (!is_object($db)) $db = opensim_new_db();
+
+ if ($db->exist_table('Presence')) {
+ $db->query('DELETE FROM Presence');
+ }
+
+ // Standalone
+ else {
+ $userids = array();
+ $db->query("SELECT UserID FROM GridUser WHERE Online='True'");
+ while (list($uid) = $db->next_record()) {
+ $userids[] = $uid;
+ }
+ //
+ foreach($userids as $userid) {
+ $db->query("UPDATE GridUser SET Online='False' WHERE UserID='". $userid."'");
+ }
+ }
+
+ return true;
+}
+
+
+function opensim_cleanup_db(&$db=null)
+{
+ if (!is_object($db)) $db = opensim_new_db();
+
+ opensim_del_currency_expired($db);
+ opensim_del_terrainImages($db);
+
+ return;
+}
+
+
+function opensim_del_terrainImage($uuid, &$db=null)
+{
+ if (!is_object($db)) $db = opensim_new_db();
+ if (!isGuid($uuid)) return false;
+
+ $ret = false;
+
+ $query = "SELECT id,name FROM assets WHERE CreatorID='".$uuid."'";
+ $db->query($query);
+ if ($db->Errno==0) {
+ $db2 = opensim_new_db();
+ while (list($tex_id, $name) = $db->next_record()) {
+ if (isGuid($tex_id) and ($name=="terrainImage_".$uuid or $name=="parcelImage_".$uuid)) {
+ $del_query = "DELETE FROM assets WHERE id='".$tex_id."'";
+ $db2->query($del_query);
+ echo $del_query."
";
+ $ret = true;
+ }
+ }
+ }
+
+ return $ret;
+}
+
+
+function opensim_del_terrainImages(&$db=null)
+{
+ if (!is_object($db)) $db = opensim_new_db();
+ $uuids = opensim_get_regions_uuid(false, $db);
+
+ foreach($uuids as $uuid) {
+ echo "checking.... ".$uuid."
";
+ if (isGuid($uuid)) {
+ $ret = opensim_del_terrainImage($uuid, $db);
+ }
+ }
+}
+
+
+//
+// for TEST
+//
+function opensim_debug_command(&$db=null)
+{
+ if (!is_object($db)) $db = opensim_new_db();
+
+
+ //echo "Set your Debug Command at opensim_debug_command() in opensim.mysql.php
";
+
+/*
+ $db->query('SELECT name,assetType,id,asset_flags FROM assets');
+
+ while (list($name,$type,$id,$flags) = $db->next_record()) {
+ echo $name." ".$type." ".$id." ".$flags."
";
+ }
+*/
+}
+
diff --git a/helper-php/DTLNSL_helper_scripts/include/tools.func.php b/helper-php/DTLNSL_helper_scripts/include/tools.func.php
new file mode 100644
index 0000000..191a843
--- /dev/null
+++ b/helper-php/DTLNSL_helper_scripts/include/tools.func.php
@@ -0,0 +1,224 @@
+ [key1] => value1
+// [key2] => Array
+// (
+// [key3] => value3
+// )
+//
+
+function split_key_value($str)
+{
+ $info = array();
+ $str = trim($str);
+
+ if (substr($str, 0, 1)=='{' and substr($str, -1)=='}') {
+ $str = substr($str, 1, -1);
+ $inbrkt = 0;
+ $inquot = false;
+ $inkkko = false;
+ $isakey = true;
+ $key = "";
+ $val = "";
+
+ for ($i=0; $i file.tga
+//
+function j2k_to_tga($file, $iscopy=true)
+{
+ if (!file_exists($file)) return false;
+
+ $com_totga = get_j2k_to_tga_command();
+ if ($com_totga=='') return false;
+
+ if ($iscopy) $ret = copy ($file, $file.'.j2k');
+ else $ret = rename($file, $file.'.j2k');
+ if (!$ret) return false;
+
+ exec("$com_totga -i $file.j2k -o $file.tga 1>/dev/null 2>&1");
+ unlink($file.'.j2k');
+
+ return true;
+}
+
+
+function get_j2k_to_tga_command()
+{
+ $command = find_command_path('j2k_to_image');
+ return $command;
+}
+
+
+//
+// Image Size Convert Command String
+//
+function get_image_size_convert_command($xsize, $ysize)
+{
+ if (!isNumeric($xsize) or !isNumeric($ysize)) return '';
+
+ $command = find_command_path('convert');
+ if ($command=='') return '';
+
+ $prog = $command.' - -geometry '.$xsize.'x'.$ysize.'! -';
+ return $prog;
+}
+
+
+function find_command_path($command)
+{
+ $path = '';
+ if (file_exists('/usr/local/bin/'.$command)) $path = '/usr/local/bin/';
+ else if (file_exists('/usr/bin/'.$command)) $path = '/usr/bin/';
+ else if (file_exists('/usr/X11R6/bin/'.$command)) $path = '/usr/X11R6/bin/';
+ else if (file_exists('/bin/'.$command)) $path = '/bin/';
+ else return '';
+
+ return $path.$command;
+}
+
diff --git a/helper-php/DTLNSL_helper_scripts/include/xmlgroups_config.php b/helper-php/DTLNSL_helper_scripts/include/xmlgroups_config.php
new file mode 100644
index 0000000..0e6468b
--- /dev/null
+++ b/helper-php/DTLNSL_helper_scripts/include/xmlgroups_config.php
@@ -0,0 +1,54 @@
+ tableList = new Dictionary();
+ tableList = CheckTables();
+
+ //
+ // Balances Table
+ if (!tableList.ContainsKey(Table_of_Balances)) {
+ try {
+ CreateBalancesTable();
+ }
+ catch (Exception e) {
+ throw new Exception("[MONEY MANAGER]: Error creating balances table: " + e.ToString());
+ }
+ }
+ else {
+ string version = tableList[Table_of_Balances].Trim();
+ int nVer = getTableVersionNum(version);
+ balances_rev = nVer;
+ switch (nVer) {
+ case 1: //Rev.1
+ UpdateBalancesTable1();
+ UpdateBalancesTable2();
+ UpdateBalancesTable3();
+ break;
+ case 2: //Rev.2
+ UpdateBalancesTable2();
+ UpdateBalancesTable3();
+ break;
+ case 3: //Rev.3
+ UpdateBalancesTable3();
+ break;
+ }
+ }
+
+ //
+ // UserInfo Table
+ if (!tableList.ContainsKey(Table_of_UserInfo)) {
+ try {
+ CreateUserInfoTable();
+ }
+ catch (Exception e) {
+ throw new Exception("[MONEY MANAGER]: Error creating userinfo table: " + e.ToString());
+ }
+ }
+ else {
+ string version = tableList[Table_of_UserInfo].Trim();
+ int nVer = getTableVersionNum(version);
+ userinfo_rev = nVer;
+ switch (nVer) {
+ case 1: //Rev.1
+ UpdateUserInfoTable1();
+ UpdateUserInfoTable2();
+ break;
+ case 2: //Rev.2
+ UpdateUserInfoTable2();
+ break;
+ }
+ }
+
+ //
+ // Transactions Table
+ if (!tableList.ContainsKey(Table_of_Transactions)) {
+ try {
+ CreateTransactionsTable();
+ }
+ catch (Exception e) {
+ throw new Exception("[MONEY MANAGER]: Error creating transactions table: " + e.ToString());
+ }
+ }
+ // check transactions table version
+ else {
+ string version = tableList[Table_of_Transactions].Trim();
+ int nVer = getTableVersionNum(version);
+ switch (nVer) {
+ case 2: //Rev.2
+ UpdateTransactionsTable2();
+ UpdateTransactionsTable3();
+ UpdateTransactionsTable4();
+ UpdateTransactionsTable5();
+ UpdateTransactionsTable6();
+ UpdateTransactionsTable7();
+ UpdateTransactionsTable8();
+ UpdateTransactionsTable9();
+ UpdateTransactionsTable10();
+ UpdateTransactionsTable11();
+ break;
+ case 3: //Rev.3
+ UpdateTransactionsTable3();
+ UpdateTransactionsTable4();
+ UpdateTransactionsTable5();
+ UpdateTransactionsTable6();
+ UpdateTransactionsTable7();
+ UpdateTransactionsTable8();
+ UpdateTransactionsTable9();
+ UpdateTransactionsTable10();
+ UpdateTransactionsTable11();
+ break;
+ case 4: //Rev.4
+ UpdateTransactionsTable4();
+ UpdateTransactionsTable5();
+ UpdateTransactionsTable6();
+ UpdateTransactionsTable7();
+ UpdateTransactionsTable8();
+ UpdateTransactionsTable9();
+ UpdateTransactionsTable10();
+ UpdateTransactionsTable11();
+ break;
+ case 5: //Rev.5
+ UpdateTransactionsTable5();
+ UpdateTransactionsTable6();
+ UpdateTransactionsTable7();
+ UpdateTransactionsTable8();
+ UpdateTransactionsTable9();
+ UpdateTransactionsTable10();
+ UpdateTransactionsTable11();
+ break;
+ case 6: //Rev.6
+ UpdateTransactionsTable6();
+ UpdateTransactionsTable7();
+ UpdateTransactionsTable8();
+ UpdateTransactionsTable9();
+ UpdateTransactionsTable10();
+ UpdateTransactionsTable11();
+ break;
+ case 7: //Rev.7
+ UpdateTransactionsTable7();
+ UpdateTransactionsTable8();
+ UpdateTransactionsTable9();
+ UpdateTransactionsTable10();
+ UpdateTransactionsTable11();
+ break;
+ case 8: //Rev.8
+ UpdateTransactionsTable8();
+ UpdateTransactionsTable9();
+ UpdateTransactionsTable10();
+ UpdateTransactionsTable11();
+ break;
+ case 9: //Rev.9
+ UpdateTransactionsTable9();
+ UpdateTransactionsTable10();
+ UpdateTransactionsTable11();
+ break;
+ case 10: //Rev.10
+ UpdateTransactionsTable10();
+ UpdateTransactionsTable11();
+ break;
+ case 11: //Rev.11
+ UpdateTransactionsTable11();
+ break;
+ }
+ }
+
+ //
+ // TotalSales Table
+ if (!tableList.ContainsKey(Table_of_TotalSales)) {
+ try {
+ CreateTotalSalesTable();
+ }
+ catch (Exception e) {
+ throw new Exception("[MONEY MANAGER]: Error creating totalsales table: " + e.ToString());
+ }
+ }
+ else {
+ string version = tableList[Table_of_TotalSales].Trim();
+ int nVer = getTableVersionNum(version);
+ switch (nVer) {
+ case 1: //Rev.1
+ UpdateTotalSalesTable1();
+ UpdateTotalSalesTable2();
+ break;
+ case 2: //Rev.2
+ UpdateTotalSalesTable2();
+ break;
+ }
+ }
+ }
+ catch (Exception e) {
+ m_log.Error("[MONEY MANAGER]: Error checking or creating tables: " + e.ToString());
+ throw new Exception("[MONEY MANAGER]: Error checking or creating tables: " + e.ToString());
+ }
+ }
+
+
+ private int getTableVersionNum(string version)
+ {
+ int nVer = 0;
+
+ Regex _commentPattenRegex = new Regex(@"\w+\.(?\d+)");
+ Match m = _commentPattenRegex.Match(version);
+ if (m.Success) {
+ string ver = m.Groups["ver"].Value;
+ nVer = Convert.ToInt32(ver);
+ }
+ return nVer;
+ }
+
+
+
+ ///////////////////////////////////////////////////////////////////////
+ // create Tables
+
+ private void CreateBalancesTable()
+ {
+ string sql = string.Empty;
+
+ sql = "CREATE TABLE `" + Table_of_Balances + "` (";
+ sql += "`user` varchar(36) NOT NULL,";
+ sql += "`balance` int(10) NOT NULL,";
+ sql += "`status` tinyint(2) DEFAULT NULL,";
+ sql += "`type` tinyint(2) NOT NULL DEFAULT 0,";
+ sql += "PRIMARY KEY(`user`))";
+ sql += "Engine=InnoDB DEFAULT CHARSET=utf8 ";
+ ///////////////////////////////////////////////
+ sql += "COMMENT='Rev.4';";
+ MySqlCommand cmd = new MySqlCommand(sql, dbcon);
+ cmd.ExecuteNonQuery();
+ cmd.Dispose();
+ }
+
+
+ private void CreateUserInfoTable()
+ {
+ string sql = string.Empty;
+
+ sql = "CREATE TABLE `" + Table_of_UserInfo + "` (";
+ sql += "`user` varchar(36) NOT NULL,";
+ sql += "`simip` varchar(64) NOT NULL,";
+ sql += "`avatar` varchar(50) NOT NULL,";
+ sql += "`pass` varchar(36) NOT NULL DEFAULT '',";
+ sql += "`type` tinyint(2) NOT NULL DEFAULT 0,";
+ sql += "`class` tinyint(2) NOT NULL DEFAULT 0,";
+ sql += "`serverurl` varchar(255) NOT NULL DEFAULT '',";
+ sql += "PRIMARY KEY(`user`))";
+ sql += "Engine=InnoDB DEFAULT CHARSET=utf8 ";
+ ///////////////////////////////////////////////
+ sql += "COMMENT='Rev.3';";
+ MySqlCommand cmd = new MySqlCommand(sql, dbcon);
+ cmd.ExecuteNonQuery();
+ cmd.Dispose();
+ }
+
+
+ private void CreateTransactionsTable()
+ {
+ string sql = string.Empty;
+
+ sql = "CREATE TABLE `" + Table_of_Transactions + "`(";
+ sql += "`UUID` varchar(36) NOT NULL,";
+ sql += "`sender` varchar(36) NOT NULL,";
+ sql += "`receiver` varchar(36) NOT NULL,";
+ sql += "`amount` int(10) NOT NULL,";
+ sql += "`senderBalance` int(10) NOT NULL DEFAULT -1,";
+ sql += "`receiverBalance` int(10) NOT NULL DEFAULT -1,";
+ sql += "`objectUUID` varchar(36) DEFAULT NULL,";
+ sql += "`objectName` varchar(255) DEFAULT NULL,";
+ sql += "`regionHandle` varchar(36) NOT NULL,";
+ sql += "`regionUUID` varchar(36) NOT NULL,";
+ sql += "`type` int(10) NOT NULL,";
+ sql += "`time` int(11) NOT NULL,";
+ sql += "`secure` varchar(36) NOT NULL,";
+ sql += "`status` tinyint(1) NOT NULL,";
+ sql += "`commonName` varchar(128) NOT NULL,";
+ sql += "`description` varchar(255) DEFAULT NULL,";
+ sql += "PRIMARY KEY(`UUID`))";
+ sql += "Engine=InnoDB DEFAULT CHARSET=utf8 ";
+ ///////////////////////////////////////////////
+ sql += "COMMENT='Rev.12';";
+ MySqlCommand cmd = new MySqlCommand(sql, dbcon);
+ cmd.ExecuteNonQuery();
+ cmd.Dispose();
+ }
+
+
+ private void CreateTotalSalesTable()
+ {
+ string sql = string.Empty;
+
+ sql = "CREATE TABLE `" + Table_of_TotalSales + "` (";
+ sql += "`UUID` varchar(36) NOT NULL,";
+ sql += "`user` varchar(36) NOT NULL,";
+ sql += "`objectUUID` varchar(36) NOT NULL,";
+ sql += "`type` int(10) NOT NULL,";
+ sql += "`TotalCount` int(10) NOT NULL DEFAULT 0,";
+ sql += "`TotalAmount` int(10) NOT NULL DEFAULT 0,";
+ sql += "`time` int(11) NOT NULL,";
+ sql += "PRIMARY KEY(`UUID`))";
+ sql += "Engine=InnoDB DEFAULT CHARSET=utf8 ";
+ ///////////////////////////////////////////////
+ sql += "COMMENT='Rev.3';";
+ MySqlCommand cmd = new MySqlCommand(sql, dbcon);
+ cmd.ExecuteNonQuery();
+ cmd.Dispose();
+
+ initTotalSalesTable();
+ }
+
+
+
+ ///////////////////////////////////////////////////////////////////////
+ // update Balances Table
+
+ private void UpdateBalancesTable1()
+ {
+ m_log.Info("[MONEY MANAGER]: Converting Balance Table...");
+ string sql = string.Empty;
+
+ sql = "SELECT COUNT(*) FROM " + Table_of_Balances;
+ MySqlCommand cmd = new MySqlCommand(sql, dbcon);
+ int resultCount = int.Parse(cmd.ExecuteScalar().ToString());
+ cmd.Dispose();
+
+ sql = "SELECT * FROM " + Table_of_Balances;
+ cmd = new MySqlCommand(sql, dbcon);
+ MySqlDataReader dbReader = cmd.ExecuteReader();
+
+ int l = 0;
+ string[,] row = new string[resultCount, dbReader.FieldCount];
+ while (dbReader.Read()) {
+ for (int i=0; i=0) {
+ amount += balance;
+ updatedb = updateBalance(uuid, amount);
+ }
+ else {
+ updatedb = addUser(uuid, amount, int.Parse(row[i,2]), 0);
+ }
+ if (!updatedb) break;
+ }
+ }
+
+ // Delete
+ if (updatedb) {
+ for (int i=0; i uuid, url, name, pass
+ bool updatedb = true;
+ for (int i=0; i
+ /// update transactions table from Rev.2 to Rev.3
+ ///
+ private void UpdateTransactionsTable2()
+ {
+ string sql = string.Empty;
+
+ sql = "BEGIN;";
+ sql += "ALTER TABLE `" + Table_of_Transactions + "` ";
+ sql += "ADD(`objectUUID` varchar(36) DEFAULT NULL AFTER `amount`),";
+ sql += "COMMENT = 'Rev.3';";
+ sql += "COMMIT;";
+ MySqlCommand cmd = new MySqlCommand(sql, dbcon);
+ cmd.ExecuteNonQuery();
+ cmd.Dispose();
+ }
+
+
+ ///
+ /// update transactions table from Rev.3 to Rev.4
+ ///
+ private void UpdateTransactionsTable3()
+ {
+ string sql = string.Empty;
+
+ sql = "BEGIN;";
+ sql += "ALTER TABLE `" + Table_of_Transactions + "` ";
+ sql += "ADD(`secure` varchar(36) NOT NULL AFTER `time`),";
+ sql += "COMMENT = 'Rev.4';";
+ sql += "COMMIT;";
+ MySqlCommand cmd = new MySqlCommand(sql, dbcon);
+ cmd.ExecuteNonQuery();
+ cmd.Dispose();
+ }
+
+
+ ///
+ /// update transactions table from Rev.4 to Rev.5
+ ///
+ private void UpdateTransactionsTable4()
+ {
+ string sql = string.Empty;
+
+ sql = "BEGIN;";
+ sql += "ALTER TABLE `" + Table_of_Transactions + "` ";
+ sql += "ADD(`regionHandle` varchar(36) NOT NULL AFTER `objectUUID`),";
+ sql += "COMMENT = 'Rev.5';";
+ sql += "COMMIT;";
+ MySqlCommand cmd = new MySqlCommand(sql, dbcon);
+ cmd.ExecuteNonQuery();
+ cmd.Dispose();
+ }
+
+
+ ///
+ /// update transactions table from Rev.5 to Rev.6
+ ///
+ private void UpdateTransactionsTable5()
+ {
+ string sql = string.Empty;
+
+ sql = "BEGIN;";
+ sql += "ALTER TABLE `" + Table_of_Transactions + "` ";
+ sql += "ADD(`commonName` varchar(128) NOT NULL AFTER `status`),";
+ sql += "COMMENT = 'Rev.6';";
+ sql += "COMMIT;";
+ MySqlCommand cmd = new MySqlCommand(sql, dbcon);
+ cmd.ExecuteNonQuery();
+ cmd.Dispose();
+ }
+
+
+ ///
+ /// update transactions table from Rev.6 to Rev.7
+ ///
+ private void UpdateTransactionsTable6()
+ {
+ //m_log.Info("[MONEY MANAGER]: Converting Transaction Table...");
+ string sql = string.Empty;
+
+ sql = "SELECT COUNT(*) FROM " + Table_of_Transactions;
+ MySqlCommand cmd = new MySqlCommand(sql, dbcon);
+ int resultCount = int.Parse(cmd.ExecuteScalar().ToString());
+ cmd.Dispose();
+
+ sql = "SELECT UUID,sender,receiver FROM " + Table_of_Transactions;
+ cmd = new MySqlCommand(sql, dbcon);
+ MySqlDataReader dbReader = cmd.ExecuteReader();
+
+ int l = 0;
+ string[,] row = new string[resultCount, dbReader.FieldCount];
+ while (dbReader.Read()) {
+ for (int i=0; i
+ /// update transactions table from Rev.7 to Rev.8
+ ///
+ private void UpdateTransactionsTable7()
+ {
+ string sql = string.Empty;
+
+ sql = "BEGIN;";
+ sql += "ALTER TABLE `" + Table_of_Transactions + "` ";
+ sql += "ADD `objectName` varchar(255) DEFAULT NULL AFTER `objectUUID`,";
+ sql += "COMMENT = 'Rev.8';";
+ sql += "COMMIT;";
+ MySqlCommand cmd = new MySqlCommand(sql, dbcon);
+ cmd.ExecuteNonQuery();
+ cmd.Dispose();
+ }
+
+
+ ///
+ /// update transactions table from Rev.8 to Rev.9
+ ///
+ private void UpdateTransactionsTable8()
+ {
+ string sql = string.Empty;
+
+ sql = "BEGIN;";
+ sql += "ALTER TABLE `" + Table_of_Transactions + "` ";
+ sql += "ADD `senderBalance` int(10) NOT NULL DEFAULT -1 AFTER `amount`,";
+ sql += "ADD `receiverBalance` int(10) NOT NULL DEFAULT -1 AFTER `senderBalance`,";
+ sql += "COMMENT = 'Rev.9';";
+ sql += "COMMIT;";
+ MySqlCommand cmd = new MySqlCommand(sql, dbcon);
+ cmd.ExecuteNonQuery();
+ cmd.Dispose();
+ }
+
+
+ ///
+ /// update transactions table from Rev.9 to Rev.10
+ ///
+ private void UpdateTransactionsTable9()
+ {
+ string sql = string.Empty;
+
+ sql = "BEGIN;";
+ sql += "ALTER TABLE `" + Table_of_Transactions + "` ";
+ sql += "MODIFY COLUMN `sender` varchar(36) NOT NULL,";
+ sql += "MODIFY COLUMN `receiver` varchar(36) NOT NULL,";
+ sql += "COMMENT = 'Rev.10';";
+ sql += "COMMIT;";
+ MySqlCommand cmd = new MySqlCommand(sql, dbcon);
+ cmd.ExecuteNonQuery();
+ cmd.Dispose();
+ }
+
+
+ ///
+ /// update transactions table from Rev.10 to Rev.11
+ /// change type of BirthGift from 1000 to 900
+ ///
+ private void UpdateTransactionsTable10()
+ {
+ //m_log.Info("[MONEY MANAGER]: Converting Transaction Table...");
+ string sql = string.Empty;
+
+ sql = "SELECT COUNT(*) FROM `" + Table_of_Transactions + "` WHERE type=1000";
+ MySqlCommand cmd = new MySqlCommand(sql, dbcon);
+ int resultCount = int.Parse(cmd.ExecuteScalar().ToString());
+ cmd.Dispose();
+
+ if (resultCount>0) {
+ sql = "SELECT UUID FROM `" + Table_of_Transactions + "` WHERE type=1000";
+ cmd = new MySqlCommand(sql, dbcon);
+ MySqlDataReader dbReader = cmd.ExecuteReader();
+
+ int l = 0;
+ string[] row = new string[resultCount];
+ while (dbReader.Read()) {
+ row[l] = dbReader.GetString(0);
+ l++;
+ }
+ dbReader.Close();
+ cmd.Dispose();
+
+ sql = "UPDATE `" + Table_of_Transactions + "` SET type=900 WHERE UUID=?uuid";
+ for (int i=0; i
+ /// update transactions table from Rev.11 to Rev.12
+ ///
+ private void UpdateTransactionsTable11()
+ {
+ string sql = string.Empty;
+
+ sql = "BEGIN;";
+ sql += "ALTER TABLE `" + Table_of_Transactions + "` ";
+ sql += "ADD `regionUUID` varchar(36) NOT NULL AFTER `regionHandle`,";
+ sql += "COMMENT = 'Rev.12';";
+ sql += "COMMIT;";
+ MySqlCommand cmd = new MySqlCommand(sql, dbcon);
+ cmd.ExecuteNonQuery();
+ cmd.Dispose();
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////
+ // update Total Sales Table
+
+ private void UpdateTotalSalesTable1()
+ {
+ string sql = string.Empty;
+
+ sql = "BEGIN;";
+ sql += "ALTER TABLE `" + Table_of_TotalSales + "` ";
+ sql += "ADD `time` int(11) NOT NULL AFTER `TotalAmount`,";
+ sql += "COMMENT = 'Rev.2';";
+ sql += "COMMIT;";
+ MySqlCommand cmd = new MySqlCommand(sql, dbcon);
+ cmd.ExecuteNonQuery();
+ cmd.Dispose();
+
+ deleteTotalSalesTable();
+ initTotalSalesTable();
+ }
+
+
+ private void UpdateTotalSalesTable2()
+ {
+ string sql = string.Empty;
+
+ sql = "BEGIN;";
+ sql += "ALTER TABLE `" + Table_of_TotalSales + "` ";
+ sql += "MODIFY COLUMN `user` varchar(36) NOT NULL,";
+ sql += "COMMENT = 'Rev.3';";
+ sql += "COMMIT;";
+ MySqlCommand cmd = new MySqlCommand(sql, dbcon);
+ cmd.ExecuteNonQuery();
+ cmd.Dispose();
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////////////
+ //
+
+ private Dictionary CheckTables()
+ {
+ Dictionary tableDic = new Dictionary();
+
+ lock (dbcon) {
+ string sql = string.Empty;
+
+ sql = "SELECT TABLE_NAME,TABLE_COMMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=?dbname";
+ MySqlCommand cmd = new MySqlCommand(sql, dbcon);
+ cmd.Parameters.AddWithValue("?dbname", dbcon.Database);
+
+ using (MySqlDataReader r = cmd.ExecuteReader()) {
+ while (r.Read()) {
+ try {
+ string tableName = (string)r["TABLE_NAME"];
+ string comment = (string)r["TABLE_COMMENT"];
+ tableDic.Add(tableName, comment);
+ }
+ catch (Exception e) {
+ throw new Exception("[MONEY MANAGER]: Error checking tables" + e.ToString());
+ }
+ }
+ r.Close();
+ }
+
+ cmd.Dispose();
+ return tableDic;
+ }
+ }
+
+
+ ///
+ /// Reconnect to the database
+ ///
+ public void Reconnect()
+ {
+ m_log.Info("[MONEY MANAGER]: Reconnecting database");
+ lock (dbcon) {
+ try {
+ dbcon.Close();
+ dbcon = new MySqlConnection(connectString);
+ dbcon.Open();
+ m_log.Info("[MONEY MANAGER]: Reconnected database");
+ }
+ catch (Exception e) {
+ m_log.Error("[MONEY MANAGER]: Unable to reconnect to database: " + e.ToString());
+ }
+ }
+ }
+
+
+
+ ///////////////////////////////////////////////////////////////////////
+ //
+ // balances
+ //
+
+ ///
+ /// Get balance from database. returns -1 if failed.
+ ///
+ ///
+ ///
+ public int getBalance(string userID)
+ {
+ if (userID==UUID.Zero.ToString()) return 999999999; // System
+
+ int retValue = -1;
+ string sql = string.Empty;
+
+ sql = "SELECT balance FROM " + Table_of_Balances + " WHERE user = ?userid";
+ MySqlCommand cmd = new MySqlCommand(sql, dbcon);
+ cmd.Parameters.AddWithValue("?userid", userID);
+
+ using (MySqlDataReader dbReader = cmd.ExecuteReader(CommandBehavior.SingleRow)) {
+ try {
+ if (dbReader.Read()) {
+ retValue = Convert.ToInt32(dbReader["balance"]);
+ }
+ }
+ #pragma warning disable 0168
+ catch (Exception e)
+ #pragma warning restore 0168
+ {
+ m_log.ErrorFormat("[MoneyDB]: MySql failed to fetch balance {0}.", userID);
+ retValue = -2;
+ }
+ dbReader.Close();
+ }
+ cmd.Dispose();
+
+ return retValue;
+ }
+
+
+ public bool updateBalance(string userID, int amount)
+ {
+ if (userID==UUID.Zero.ToString()) return true; // System
+
+ bool bRet = false;
+ string sql = string.Empty;
+
+ sql = "UPDATE " + Table_of_Balances + " SET balance = ?amount WHERE user = ?userID;";
+ MySqlCommand cmd = new MySqlCommand(sql, dbcon);
+ cmd.Parameters.AddWithValue("?amount", amount);
+ cmd.Parameters.AddWithValue("?userID", userID);
+
+ if (cmd.ExecuteNonQuery() > 0) bRet = true;
+
+ cmd.Dispose();
+ return bRet;
+ }
+
+
+ public bool addUser(string userID, int balance, int status, int type)
+ {
+ if (userID==UUID.Zero.ToString()) return true; // System
+
+ bool bRet = false;
+ string sql = string.Empty;
+
+ if (balances_rev>=4) {
+ sql = "INSERT INTO " + Table_of_Balances + " (`user`,`balance`,`status`,`type`) VALUES ";
+ sql += " (?userID,?balance,?status,?type);";
+ }
+ else {
+ sql = "INSERT INTO " + Table_of_Balances + " (`user`,`balance`,`status`) VALUES ";
+ sql += " (?userID,?balance,?status);";
+ }
+ MySqlCommand cmd = new MySqlCommand(sql, dbcon);
+
+ cmd.Parameters.AddWithValue("?userID", userID);
+ cmd.Parameters.AddWithValue("?balance", balance);
+ cmd.Parameters.AddWithValue("?status", status);
+ if (balances_rev>=4) {
+ cmd.Parameters.AddWithValue("?type", type);
+ }
+
+ if (cmd.ExecuteNonQuery() > 0) bRet = true;
+ cmd.Dispose();
+
+ return bRet;
+ }
+
+
+ ///
+ /// Here we'll make a withdraw from the sender and update transaction status
+ ///
+ ///
+ ///
+ ///
+ ///
+ public bool withdrawMoney(UUID transactionID, string senderID, int amount)
+ {
+ bool bRet = false;
+ string sql = string.Empty;
+ MySqlCommand cmd = null;
+
+ // System
+ if (senderID==UUID.Zero.ToString()) {
+ sql = "BEGIN;";
+ sql += "UPDATE " + Table_of_Transactions;
+ sql += " SET senderBalance = 0, status = ?status WHERE UUID = ?tranid;";
+ sql += "COMMIT;";
+
+ cmd = new MySqlCommand(sql, dbcon);
+ cmd.Parameters.AddWithValue("?status", (int)Status.PENDING_STATUS); //pending
+ cmd.Parameters.AddWithValue("?tranid", transactionID.ToString());
+ }
+ else {
+ sql = "BEGIN;";
+ sql += "UPDATE " + Table_of_Transactions + "," + Table_of_Balances;
+ sql += " SET senderBalance = balance - ?amount, "+ Table_of_Transactions + ".status = ?status, balance = balance - ?amount ";
+ sql += " WHERE UUID = ?tranid AND user = sender AND user = ?userid;";
+ sql += "COMMIT;";
+
+ cmd = new MySqlCommand(sql, dbcon);
+ cmd.Parameters.AddWithValue("?amount", amount);
+ cmd.Parameters.AddWithValue("?userid", senderID);
+ cmd.Parameters.AddWithValue("?status", (int)Status.PENDING_STATUS); //pending
+ cmd.Parameters.AddWithValue("?tranid", transactionID.ToString());
+ }
+
+ if (cmd.ExecuteNonQuery() > 0) bRet = true;
+
+ cmd.Dispose();
+ return bRet;
+ }
+
+
+ ///
+ /// Give money to the receiver and change the transaction status to success.
+ ///
+ ///
+ ///
+ ///
+ ///
+ public bool giveMoney(UUID transactionID, string receiverID, int amount)
+ {
+ string sql = string.Empty;
+ bool bRet = false;
+ MySqlCommand cmd = null;
+
+ // System
+ if (receiverID==UUID.Zero.ToString()) {
+ sql = "BEGIN;";
+ sql += "UPDATE " + Table_of_Transactions;
+ sql += " SET receiverBalance = 0, status = ?status WHERE UUID = ?tranid;";
+ sql += "COMMIT;";
+
+ cmd = new MySqlCommand(sql, dbcon);
+ cmd.Parameters.AddWithValue("?status", (int)Status.SUCCESS_STATUS); //Success
+ cmd.Parameters.AddWithValue("?tranid", transactionID.ToString());
+ }
+ else {
+ sql = "BEGIN;";
+ sql += "UPDATE " + Table_of_Transactions + "," + Table_of_Balances;
+ sql += " SET receiverBalance = balance + ?amount, " + Table_of_Transactions + ".status = ?status, balance = balance + ?amount ";
+ sql += " WHERE UUID = ?tranid AND user = receiver AND user = ?userid;";
+ sql += "COMMIT;";
+
+ cmd = new MySqlCommand(sql, dbcon);
+ cmd.Parameters.AddWithValue("?amount", amount);
+ cmd.Parameters.AddWithValue("?userid", receiverID);
+ cmd.Parameters.AddWithValue("?status", (int)Status.SUCCESS_STATUS); //Success
+ cmd.Parameters.AddWithValue("?tranid", transactionID.ToString());
+ }
+
+ if (cmd.ExecuteNonQuery() > 0) bRet = true;
+
+ cmd.Dispose();
+ return bRet;
+ }
+
+
+
+ ///////////////////////////////////////////////////////////////////////
+ //
+ // totalsales
+ //
+ private void initTotalSalesTable()
+ {
+ m_log.Info("[MONEY MANAGER]: Initailising TotalSales Table...");
+ string sql = string.Empty;
+
+ sql = "SELECT SQL_CALC_FOUND_ROWS receiver,objectUUID,type,COUNT(*),SUM(amount),MIN(time) FROM "+ Table_of_Transactions;
+ sql += " WHERE sender != receiver AND status = ?status AND sender != ?system";
+ sql += " GROUP BY receiver,objectUUID,type;";
+
+ MySqlCommand cmd = new MySqlCommand(sql, dbcon);
+ cmd.Parameters.AddWithValue("?status", (int)Status.SUCCESS_STATUS);
+ cmd.Parameters.AddWithValue("?system", UUID.Zero.ToString());
+ cmd.ExecuteNonQuery();
+
+ MySqlCommand cmd2 = new MySqlCommand("SELECT FOUND_ROWS();", dbcon);
+ int lineCount = int.Parse(cmd2.ExecuteScalar().ToString());
+ cmd2.Dispose();
+
+ if (lineCount<=0) {
+ cmd.Dispose();
+ return;
+ }
+
+ MySqlDataReader r = cmd.ExecuteReader();
+ int l = 0;
+ string[,] row = new string[lineCount, r.FieldCount];
+ while (r.Read()) {
+ for (int i=0; i 0) bRet = true;
+
+ cmd.Dispose();
+ return bRet;
+ }
+
+
+ public bool updateTotalSale(UUID saleUUID, int count, int amount, int tmstamp)
+ {
+ bool bRet = false;
+ string sql = string.Empty;
+
+ sql = "UPDATE " + Table_of_TotalSales;
+ sql += " SET TotalCount = TotalCount + ?count, TotalAmount = TotalAmount + ?amount, time = ?time ";
+ sql += " WHERE UUID = ?uuid;";
+ MySqlCommand cmd = new MySqlCommand(sql, dbcon);
+
+ cmd.Parameters.AddWithValue("?uuid", saleUUID.ToString());
+ cmd.Parameters.AddWithValue("?count", count);
+ cmd.Parameters.AddWithValue("?amount", amount);
+ cmd.Parameters.AddWithValue("?time", tmstamp);
+
+ if (cmd.ExecuteNonQuery() > 0) bRet = true;
+
+ cmd.Dispose();
+ return bRet;
+
+ }
+
+
+ public bool setTotalSale(string userUUID, string objectUUID, int type, int count, int amount, int tmstamp)
+ {
+ bool bRet = false;
+ string sql = string.Empty;
+ string uuid = string.Empty;
+ int dbtm = 0;
+
+ sql = "SELECT UUID,time FROM " + Table_of_TotalSales;
+ sql += " WHERE user = ?userid AND objectUUID = ?objID AND type = ?type;";
+ MySqlCommand cmd = new MySqlCommand(sql, dbcon);
+
+ cmd.Parameters.AddWithValue("?userid", userUUID);
+ cmd.Parameters.AddWithValue("?objID", objectUUID);
+ cmd.Parameters.AddWithValue("?type", type);
+
+ using (MySqlDataReader r = cmd.ExecuteReader()) {
+ if(r.Read()) {
+ try {
+ uuid = (string)r["UUID"];
+ dbtm = Convert.ToInt32(r["time"]);
+ }
+ catch (Exception e) {
+ m_log.Error("[MONEY MANAGER]: Get sale data from DB failed: " + e.ToString());
+ r.Close();
+ cmd.Dispose();
+ return false;
+ }
+ }
+ r.Close();
+ }
+
+ if (uuid!=string.Empty) {
+ UUID saleUUID = UUID.Zero;
+ UUID.TryParse(uuid, out saleUUID);
+ if (dbtm 0) bRet = true;
+
+ cmd.Dispose();
+ return bRet;
+ }
+
+
+ public bool updateTransactionStatus(UUID transactionID, int status, string description)
+ {
+ bool bRet = false;
+ string sql = string.Empty;
+
+ sql = "UPDATE " + Table_of_Transactions + " SET status = ?status,description = ?desc WHERE UUID = ?tranid;";
+ MySqlCommand cmd = new MySqlCommand(sql, dbcon);
+ cmd.Parameters.AddWithValue("?status", status);
+ cmd.Parameters.AddWithValue("?desc", description);
+ cmd.Parameters.AddWithValue("?tranid", transactionID);
+
+ if (cmd.ExecuteNonQuery() > 0) bRet = true;
+
+ cmd.Dispose();
+ return bRet;
+ }
+
+
+ public bool SetTransExpired(int deadTime)
+ {
+ bool bRet = false;
+ string sql = string.Empty;
+
+ sql = "UPDATE " + Table_of_Transactions;
+ sql += " SET status = ?failedstatus,description = ?desc WHERE time <= ?deadTime AND status = ?pendingstatus;";
+ MySqlCommand cmd = new MySqlCommand(sql, dbcon);
+ cmd.Parameters.AddWithValue("?failedstatus", (int)Status.FAILED_STATUS);
+ cmd.Parameters.AddWithValue("?desc", "expired");
+ cmd.Parameters.AddWithValue("?deadTime", deadTime);
+ cmd.Parameters.AddWithValue("?pendingstatus", (int)Status.PENDING_STATUS);
+
+ if (cmd.ExecuteNonQuery() > 0) bRet = true;
+
+ cmd.Dispose();
+ return bRet;
+ }
+
+
+ ///
+ /// Validate if the transacion is legal
+ ///
+ ///
+ ///
+ ///
+ public bool ValidateTransfer(string secureCode, UUID transactionID)
+ {
+ bool bRet = false;
+ string secure = string.Empty;
+ string sql = string.Empty;
+
+ sql = "SELECT secure FROM " + Table_of_Transactions + " WHERE UUID = ?transID;";
+ MySqlCommand cmd = new MySqlCommand(sql, dbcon);
+ cmd.Parameters.AddWithValue("?transID", transactionID.ToString());
+
+ using (MySqlDataReader r = cmd.ExecuteReader()) {
+ if(r.Read()) {
+ try {
+ secure = (string)r["secure"];
+ }
+ catch (Exception e) {
+ m_log.Error("[MONEY MANAGER]: Get transaction from DB failed: " + e.ToString());
+ }
+ if (secureCode == secure) bRet = true;
+ else bRet = false;
+ }
+ r.Close();
+ }
+
+ cmd.Dispose();
+ return bRet;
+ }
+
+
+ public TransactionData FetchTransaction(UUID transactionID)
+ {
+ TransactionData transactionData = new TransactionData();
+ transactionData.TransUUID = transactionID;
+ string sql = string.Empty;
+
+ sql = "SELECT * FROM " + Table_of_Transactions + " WHERE UUID = ?transID;";
+ MySqlCommand cmd = new MySqlCommand(sql, dbcon);
+ cmd.Parameters.AddWithValue("?transID", transactionID.ToString());
+
+ using (MySqlDataReader r = cmd.ExecuteReader()) {
+ if (r.Read()) {
+ try {
+ transactionData.Sender = (string)r["sender"];
+ transactionData.Receiver = (string)r["receiver"];
+ transactionData.Amount = Convert.ToInt32(r["amount"]);
+ transactionData.SenderBalance = Convert.ToInt32(r["senderBalance"]);
+ transactionData.ReceiverBalance = Convert.ToInt32(r["receiverBalance"]);
+ transactionData.Type = Convert.ToInt32(r["type"]);
+ transactionData.Time = Convert.ToInt32(r["time"]);
+ transactionData.Status = Convert.ToInt32(r["status"]);
+ transactionData.CommonName = (string)r["commonName"];
+ transactionData.RegionHandle = (string)r["regionHandle"];
+ transactionData.RegionUUID = (string)r["regionUUID"];
+ //
+ if (r["objectUUID"] is System.DBNull) transactionData.ObjectUUID = UUID.Zero.ToString();
+ else transactionData.ObjectUUID = (string)r["objectUUID"];
+ if (r["objectName"] is System.DBNull) transactionData.ObjectName = string.Empty;
+ else transactionData.ObjectName = (string)r["objectName"];
+ if (r["description"] is System.DBNull) transactionData.Description = string.Empty;
+ else transactionData.Description = (string)r["description"];
+ }
+ catch (Exception e) {
+ m_log.Error("[MONEY MANAGER]: Fetching transaction failed 1: " + e.ToString());
+ r.Close();
+ cmd.Dispose();
+ return null;
+ }
+
+ }
+ r.Close();
+ }
+
+ cmd.Dispose();
+ return transactionData;
+ }
+
+
+ public TransactionData[] FetchTransaction(string userID, int startTime, int endTime, uint index, uint retNum)
+ {
+ List rows = new List();
+ string sql = string.Empty;
+
+ sql = "SELECT * FROM " + Table_of_Transactions + " WHERE time>=?start AND time<=?end ";
+ sql += "AND (sender=?user OR receiver=?user) ORDER BY time ASC LIMIT ?index,?num;";
+ MySqlCommand cmd = new MySqlCommand(sql, dbcon);
+
+ cmd.Parameters.AddWithValue("?start", startTime);
+ cmd.Parameters.AddWithValue("?end", endTime);
+ cmd.Parameters.AddWithValue("?user", userID);
+ cmd.Parameters.AddWithValue("?index", index);
+ cmd.Parameters.AddWithValue("?num", retNum);
+
+ using (MySqlDataReader r = cmd.ExecuteReader()) {
+ for (int i = 0; i < retNum; i++) {
+ if (r.Read()) {
+ try {
+ TransactionData transactionData = new TransactionData();
+ string uuid = (string)r["UUID"];
+ UUID transUUID;
+ UUID.TryParse(uuid,out transUUID);
+
+ transactionData.TransUUID = transUUID;
+ transactionData.Sender = (string)r["sender"];
+ transactionData.Receiver = (string)r["receiver"];
+ transactionData.Amount = Convert.ToInt32(r["amount"]);
+ transactionData.SenderBalance = Convert.ToInt32(r["senderBalance"]);
+ transactionData.ReceiverBalance = Convert.ToInt32(r["receiverBalance"]);
+ transactionData.Type = Convert.ToInt32(r["type"]);
+ transactionData.Time = Convert.ToInt32(r["time"]);
+ transactionData.Status = Convert.ToInt32(r["status"]);
+ transactionData.CommonName = (string)r["commonName"];
+ transactionData.RegionHandle = (string)r["regionHandle"];
+ transactionData.RegionUUID = (string)r["regionUUID"];
+ //
+ if (r["objectUUID"] is System.DBNull) transactionData.ObjectUUID = UUID.Zero.ToString();
+ else transactionData.ObjectUUID = (string)r["objectUUID"];
+ if (r["objectName"] is System.DBNull) transactionData.ObjectName = string.Empty;
+ else transactionData.ObjectName = (string)r["objectName"];
+ if (r["description"] is System.DBNull) transactionData.Description = string.Empty;
+ else transactionData.Description = (string)r["description"];
+ //
+ rows.Add(transactionData);
+ }
+ catch (Exception e) {
+ m_log.Error("[MONEY MANAGER]: Fetching transaction failed 2: " + e.ToString());
+ r.Close();
+ cmd.Dispose();
+ return null;
+ }
+ }
+ }
+ r.Close();
+ }
+
+ cmd.Dispose();
+ return rows.ToArray();
+ }
+
+
+ public int getTransactionNum(string userID, int startTime, int endTime)
+ {
+ int iRet = -1;
+ string sql = string.Empty;
+
+ sql = "SELECT COUNT(*) AS number FROM " + Table_of_Transactions + " WHERE time>=?start AND time<=?end ";
+ sql += "AND (sender=?user OR receiver=?user);";
+ MySqlCommand cmd = new MySqlCommand(sql, dbcon);
+
+ cmd.Parameters.AddWithValue("?start", startTime);
+ cmd.Parameters.AddWithValue("?end", endTime);
+ cmd.Parameters.AddWithValue("?user", userID);
+
+ using (MySqlDataReader r = cmd.ExecuteReader()) {
+ if(r.Read()) {
+ try {
+ iRet = Convert.ToInt32(r["number"]);
+ }
+ catch (Exception e) {
+ m_log.Error("[MONEY MANAGER]: Unable to get transaction info: " + e.ToString());
+ }
+ }
+ r.Close();
+ }
+
+ cmd.Dispose();
+ return iRet;
+ }
+
+
+
+ ///////////////////////////////////////////////////////////////////////
+ //
+ // userinfo
+ //
+ public bool addUserInfo(UserInfo userInfo)
+ {
+ //m_log.Error("[MONEY MANAGER]: Adding UserInfo: " + userInfo.UserID);
+
+ bool bRet = false;
+ string sql = string.Empty;
+
+ if (userInfo.Avatar==null) return false;
+
+ if (userinfo_rev>=3) {
+ sql = "INSERT INTO " + Table_of_UserInfo +"(`user`,`simip`,`avatar`,`pass`,`type`,`class`,`serverurl`) VALUES";
+ sql += "(?user,?simip,?avatar,?password,?type,?class,?serverurl);";
+ }
+ else {
+ sql = "INSERT INTO " + Table_of_UserInfo +"(`user`,`simip`,`avatar`,`pass`) VALUES";
+ sql += "(?user,?simip,?avatar,?password);";
+ }
+
+ MySqlCommand cmd = new MySqlCommand(sql, dbcon);
+ cmd.Parameters.AddWithValue("?user", userInfo.UserID);
+ cmd.Parameters.AddWithValue("?simip", userInfo.SimIP);
+ cmd.Parameters.AddWithValue("?avatar", userInfo.Avatar);
+ cmd.Parameters.AddWithValue("?password", userInfo.PswHash);
+ if (userinfo_rev>=3) {
+ cmd.Parameters.AddWithValue("?type", userInfo.Type);
+ cmd.Parameters.AddWithValue("?class", userInfo.Class);
+ cmd.Parameters.AddWithValue("?serverurl", userInfo.ServerURL);
+ }
+
+ if (cmd.ExecuteNonQuery()>0) bRet = true;
+
+ cmd.Dispose();
+ return bRet;
+ }
+
+
+ public UserInfo fetchUserInfo(string userID)
+ {
+ //m_log.Error("[MONEY MANAGER]: Fetching UserInfo: " + userID);
+
+ UserInfo userInfo = new UserInfo();
+ userInfo.UserID = null;
+ string sql = string.Empty;
+
+ sql = "SELECT * FROM " + Table_of_UserInfo + " WHERE user = ?userID;";
+ MySqlCommand cmd = new MySqlCommand(sql, dbcon);
+ cmd.Parameters.AddWithValue("?userID", userID);
+
+ using (MySqlDataReader r = cmd.ExecuteReader()) {
+ if (r.Read()) {
+ try {
+ userInfo.UserID = (string)r["user"];
+ userInfo.SimIP = (string)r["simip"];
+ userInfo.Avatar = (string)r["avatar"];
+ userInfo.PswHash = (string)r["pass"];
+ userInfo.Type = Convert.ToInt32(r["type"]);
+ userInfo.Class = Convert.ToInt32(r["class"]);
+ userInfo.ServerURL = (string)r["serverurl"];
+ }
+ catch (Exception e) {
+ m_log.Error("[MONEY MANAGER]: Fetching UserInfo failed: " + e.ToString());
+ r.Close();
+ cmd.Dispose();
+ return null;
+ }
+ }
+ r.Close();
+ }
+ cmd.Dispose();
+
+ if (userInfo.UserID!=userID) return null;
+ return userInfo;
+ }
+
+
+ public bool updateUserInfo(UserInfo userInfo)
+ {
+ //m_log.Error("[MONEY MANAGER]: Updating UserInfo: " + userInfo.UserID);
+
+ bool bRet = false;
+ string sql = string.Empty;
+
+ sql = "UPDATE " + Table_of_UserInfo + " SET simip=?simip,pass=?pass,class=?class,serverurl=?serverurl WHERE user=?user;";
+ MySqlCommand cmd = new MySqlCommand(sql, dbcon);
+ cmd.Parameters.AddWithValue("?simip", userInfo.SimIP);
+ cmd.Parameters.AddWithValue("?pass", userInfo.PswHash);
+ cmd.Parameters.AddWithValue("?class", userInfo.Class);
+ cmd.Parameters.AddWithValue("?serverurl", userInfo.ServerURL);
+ cmd.Parameters.AddWithValue("?user", userInfo.UserID);
+
+ if (cmd.ExecuteNonQuery()>0) bRet = true;
+
+ cmd.Dispose();
+ return bRet;
+ }
+
+ }
+}
diff --git a/source/ThirdParty/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/MySQLSuperManager.cs b/source/ThirdParty/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/MySQLSuperManager.cs
new file mode 100644
index 0000000..cd2bae4
--- /dev/null
+++ b/source/ThirdParty/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/MySQLSuperManager.cs
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Threading;
+
+namespace OpenSim.Data.MySQL.MySQLMoneyDataWrapper
+{
+ // This bit of code is from OpenSim.Data.MySQLSuperManager
+ public class MySQLSuperManager
+ {
+ public bool Locked;
+ private readonly Mutex m_lock = new Mutex(false);
+ public MySQLMoneyManager Manager;
+ public string Running;
+
+ public void GetLock()
+ {
+ Locked = true;
+ m_lock.WaitOne();
+ }
+
+ public void Release()
+ {
+ m_lock.ReleaseMutex();
+ Locked = false;
+ }
+ }
+}
diff --git a/source/ThirdParty/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/Properties/AssemblyInfo.cs b/source/ThirdParty/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..f4a2a82
--- /dev/null
+++ b/source/ThirdParty/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("OpenSim.Data.MySQL.MySQLMoneyDataWrapper")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("OpenSim.Data.MySQL.MySQLMoneyDataWrapper")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2009")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("03f4a266-2e30-47e4-b785-ff02cdb4bbb9")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/source/ThirdParty/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/TransactionData.cs b/source/ThirdParty/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/TransactionData.cs
new file mode 100644
index 0000000..e73b579
--- /dev/null
+++ b/source/ThirdParty/OpenSim.Data.MySQL.MySQLMoneyDataWrapper/TransactionData.cs
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSim Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using OpenMetaverse;
+
+
+namespace OpenSim.Data.MySQL.MySQLMoneyDataWrapper
+{
+ public class TransactionData
+ {
+ UUID m_uuid;
+ string m_sender = string.Empty;
+ string m_receiver = string.Empty;
+ int m_amount;
+ int m_senderBalance;
+ int m_receiverBalance;
+ int m_type;
+ int m_time;
+ int m_status;
+ string m_objectID = UUID.Zero.ToString();
+// string m_objectID = "00000000-0000-0000-0000-000000000000";
+ string m_objectName = string.Empty;
+ string m_regionHandle = string.Empty;
+ string m_regionUUID = string.Empty;
+ string m_secureCode = string.Empty;
+ string m_commonName = string.Empty;
+ string m_description = string.Empty;
+
+/*
+ public TransactionData(string uuid, string sender, string receiver,
+ int amount, int time, int status, string description)
+ {
+ this.m_uuid = uuid;
+ this.m_sender = sender;
+ this.m_receiver = receiver;
+ this.m_amount = amount;
+ }
+*/
+
+ public UUID TransUUID
+ {
+ get { return m_uuid; }
+ set { m_uuid = value; }
+ }
+
+ public string Sender
+ {
+ get { return m_sender; }
+ set { m_sender = value; }
+ }
+
+ public string Receiver
+ {
+ get { return m_receiver; }
+ set { m_receiver = value; }
+ }
+
+ public int Amount
+ {
+ get { return m_amount; }
+ set { m_amount = value; }
+ }
+
+ public int SenderBalance
+ {
+ get { return m_senderBalance; }
+ set { m_senderBalance = value; }
+ }
+
+ public int ReceiverBalance
+ {
+ get { return m_receiverBalance; }
+ set { m_receiverBalance = value; }
+ }
+
+ public int Type
+ {
+ get { return m_type; }
+ set { m_type = value; }
+ }
+
+ public int Time
+ {
+ get { return m_time; }
+ set { m_time = value; }
+ }
+
+ public int Status
+ {
+ get { return m_status; }
+ set { m_status = value; }
+ }
+
+ public string Description
+ {
+ get { return m_description; }
+ set { m_description = value; }
+ }
+
+ public string ObjectUUID
+ {
+ get { return m_objectID; }
+ set { m_objectID = value; }
+ }
+
+ public string ObjectName
+ {
+ get { return m_objectName; }
+ set { m_objectName = value; }
+ }
+
+ public string RegionHandle
+ {
+ get { return m_regionHandle; }
+ set { m_regionHandle = value; }
+ }
+
+ public string RegionUUID
+ {
+ get { return m_regionUUID; }
+ set { m_regionUUID = value; }
+ }
+
+ public string SecureCode
+ {
+ get { return m_secureCode; }
+ set { m_secureCode = value; }
+ }
+
+ public string CommonName
+ {
+ get { return m_commonName; }
+ set { m_commonName = value; }
+ }
+ }
+
+
+ public enum Status
+ {
+ SUCCESS_STATUS = 0,
+ PENDING_STATUS = 1,
+ FAILED_STATUS = 2,
+ ERROR_STATUS = 9
+ }
+
+
+ public enum AvatarType
+ {
+ LOCAL_AVATAR = 0,
+ HG_AVATAR = 1,
+ NPC_AVATAR = 2,
+ GUEST_AVATAR = 3,
+ FOREIGN_AVATAR = 8,
+ UNKNOWN_AVATAR = 9
+ }
+
+
+ public class UserInfo
+ {
+ string m_userID = string.Empty;
+ string m_simIP = string.Empty;
+ string m_avatarName = string.Empty;
+ string m_passwordHash = string.Empty;
+ int m_avatarType = (int)AvatarType.LOCAL_AVATAR;
+ int m_avatarClass = (int)AvatarType.LOCAL_AVATAR;
+ string m_serverURL = string.Empty;
+
+ public string UserID
+ {
+ get { return m_userID; }
+ set { m_userID = value; }
+ }
+
+ public string SimIP
+ {
+ get { return m_simIP; }
+ set { m_simIP = value; }
+ }
+
+ public string Avatar
+ {
+ get { return m_avatarName; }
+ set { m_avatarName = value; }
+ }
+
+ public string PswHash
+ {
+ get { return m_passwordHash; }
+ set { m_passwordHash = value; }
+ }
+
+ public int Type
+ {
+ get { return m_avatarType; }
+ set { m_avatarType = value; }
+ }
+
+ public int Class
+ {
+ get { return m_avatarClass; }
+ set { m_avatarClass = value; }
+ }
+
+ public string ServerURL
+ {
+ get { return m_serverURL; }
+ set { m_serverURL = value; }
+ }
+ }
+}
diff --git a/source/ThirdParty/OpenSim.Grid.MoneyServer/IMoneyDBService.cs b/source/ThirdParty/OpenSim.Grid.MoneyServer/IMoneyDBService.cs
new file mode 100644
index 0000000..7140c0f
--- /dev/null
+++ b/source/ThirdParty/OpenSim.Grid.MoneyServer/IMoneyDBService.cs
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/, http://www.nsl.tuis.ac.jp/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSim Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections.Generic;
+//using System.Linq;
+using System.Text;
+using OpenMetaverse;
+using OpenSim.Data.MySQL.MySQLMoneyDataWrapper;
+
+
+namespace OpenSim.Grid.MoneyServer
+{
+ public interface IMoneyDBService
+ {
+ int getBalance(string userID);
+
+ bool withdrawMoney(UUID transactionID, string senderID, int amount);
+
+ bool giveMoney(UUID transactionID, string receiverID, int amount);
+
+ bool addTransaction(TransactionData transaction);
+
+ bool addUser(string userID, int balance, int status, int type);
+
+ bool updateTransactionStatus(UUID transactionID, int status, string description);
+
+ bool SetTransExpired(int deadTime);
+
+ bool ValidateTransfer(string secureCode, UUID transactionID);
+
+ TransactionData FetchTransaction(UUID transactionID);
+
+ TransactionData FetchTransaction(string userID, int startTime, int endTime, int lastIndex);
+
+ int getTransactionNum(string userID, int startTime, int endTime);
+
+ bool DoTransfer(UUID transactionUUID);
+
+ bool DoAddMoney(UUID transactionUUID); // Added by Fumi.Iseki
+
+ bool TryAddUserInfo(UserInfo user);
+
+ UserInfo FetchUserInfo(string userID);
+ }
+}
diff --git a/source/ThirdParty/OpenSim.Grid.MoneyServer/IMoneyServiceCore.cs b/source/ThirdParty/OpenSim.Grid.MoneyServer/IMoneyServiceCore.cs
new file mode 100644
index 0000000..d6e3721
--- /dev/null
+++ b/source/ThirdParty/OpenSim.Grid.MoneyServer/IMoneyServiceCore.cs
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSim Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections.Generic;
+//using System.Linq;
+using System.Text;
+using OpenSim.Framework.Servers;
+using OpenSim.Framework.Servers.HttpServer;
+
+using Nini.Config;
+
+
+namespace OpenSim.Grid.MoneyServer
+{
+ public interface IMoneyServiceCore
+ {
+ BaseHttpServer GetHttpServer();
+ Dictionary GetSessionDic();
+ Dictionary GetSecureSessionDic();
+ Dictionary GetWebSessionDic();
+
+ //
+ IConfig GetServerConfig();
+ IConfig GetCertConfig();
+ bool IsCheckClientCert();
+ }
+}
diff --git a/source/ThirdParty/OpenSim.Grid.MoneyServer/MoneyDBService.cs b/source/ThirdParty/OpenSim.Grid.MoneyServer/MoneyDBService.cs
new file mode 100644
index 0000000..448ab19
--- /dev/null
+++ b/source/ThirdParty/OpenSim.Grid.MoneyServer/MoneyDBService.cs
@@ -0,0 +1,574 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/, http://www.nsl.tuis.ac.jp/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSim Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using OpenSim.Data.MySQL.MySQLMoneyDataWrapper;
+using OpenSim.Modules.Currency;
+using log4net;
+using System.Reflection;
+using OpenMetaverse;
+
+
+namespace OpenSim.Grid.MoneyServer
+{
+#pragma warning disable 0168
+
+ class MoneyDBService : IMoneyDBService
+ {
+ private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+ private string m_connect;
+ //private MySQLMoneyManager m_moneyManager;
+ private long TicksToEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks;
+
+ // DB manager pool
+ protected Dictionary m_dbconnections = new Dictionary(); // Lock付
+ private int m_maxConnections;
+
+ public int m_lastConnect = 0;
+
+
+ public MoneyDBService(string connect)
+ {
+ m_connect = connect;
+ Initialise(m_connect,10);
+ }
+
+
+ public MoneyDBService()
+ {
+ }
+
+
+ public void Initialise(string connectionString, int maxDBConnections)
+ {
+ m_connect = connectionString;
+ m_maxConnections = maxDBConnections;
+ if (connectionString != string.Empty) {
+ //m_moneyManager = new MySQLMoneyManager(connectionString);
+
+ //m_log.Info("Creating " + m_maxConnections + " DB connections...");
+ for (int i=0; im_maxConnections) {
+ lockedCons = 0;
+ System.Threading.Thread.Sleep(1000); // Wait some time before searching them again.
+ m_log.Debug("WARNING: All threads are in use. Probable cause: Something didnt release a mutex properly, or high volume of requests inbound.");
+ }
+ }
+ }
+
+
+
+ public int getBalance(string userID)
+ {
+ MySQLSuperManager dbm = GetLockedConnection();
+
+ try {
+ return dbm.Manager.getBalance(userID);
+ }
+ catch (MySql.Data.MySqlClient.MySqlException e) {
+ dbm.Manager.Reconnect();
+ return dbm.Manager.getBalance(userID);
+ }
+ catch(Exception e) {
+ m_log.Error(e.ToString());
+ return 0;
+ }
+ finally {
+ dbm.Release();
+ }
+ }
+
+
+ public bool withdrawMoney(UUID transactionID, string senderID, int amount)
+ {
+ MySQLSuperManager dbm = GetLockedConnection();
+
+ try {
+ return dbm.Manager.withdrawMoney(transactionID, senderID, amount);
+ }
+ catch (MySql.Data.MySqlClient.MySqlException e) {
+ dbm.Manager.Reconnect();
+ return dbm.Manager.withdrawMoney(transactionID, senderID, amount);
+ }
+ catch (Exception e) {
+ m_log.Error(e.ToString());
+ return false;
+ }
+ finally {
+ dbm.Release();
+ }
+ }
+
+
+ public bool giveMoney(UUID transactionID, string receiverID, int amount)
+ {
+ MySQLSuperManager dbm = GetLockedConnection();
+
+ try {
+ return dbm.Manager.giveMoney(transactionID, receiverID, amount);
+ }
+ catch (MySql.Data.MySqlClient.MySqlException e) {
+ dbm.Manager.Reconnect();
+ return dbm.Manager.giveMoney(transactionID, receiverID, amount);
+ }
+ catch (Exception e) {
+ m_log.Error(e.ToString());
+ return false;
+ }
+ finally {
+ dbm.Release();
+ }
+ }
+
+
+ public bool setTotalSale(TransactionData transaction)
+ {
+ if (transaction.Receiver==transaction.Sender) return false;
+ if (transaction.Sender==UUID.Zero.ToString()) return false;
+
+ MySQLSuperManager dbm = GetLockedConnection();
+
+ int time = (int)((DateTime.UtcNow.Ticks - TicksToEpoch) / 10000000);
+ try {
+ return dbm.Manager.setTotalSale(transaction.Receiver, transaction.ObjectUUID, transaction.Type, 1, transaction.Amount, time);
+ }
+ catch (MySql.Data.MySqlClient.MySqlException e) {
+ dbm.Manager.Reconnect();
+ return dbm.Manager.setTotalSale(transaction.Receiver, transaction.ObjectUUID, transaction.Type, 1, transaction.Amount, time);
+ }
+ catch (Exception e) {
+ m_log.Error(e.ToString());
+ return false;
+ }
+ finally {
+ dbm.Release();
+ }
+ }
+
+
+ public bool addTransaction(TransactionData transaction)
+ {
+ MySQLSuperManager dbm = GetLockedConnection();
+
+ try {
+ return dbm.Manager.addTransaction(transaction);
+ }
+ catch (MySql.Data.MySqlClient.MySqlException e) {
+ dbm.Manager.Reconnect();
+ return dbm.Manager.addTransaction(transaction);
+ }
+ catch (Exception e) {
+ m_log.Error(e.ToString());
+ return false;
+ }
+ finally {
+ dbm.Release();
+ }
+ }
+
+
+ public bool addUser(string userID, int balance, int status, int type)
+ {
+ TransactionData transaction = new TransactionData();
+ transaction.TransUUID = UUID.Random();
+ transaction.Sender = UUID.Zero.ToString();
+ transaction.Receiver = userID;
+ transaction.Amount = balance;
+ transaction.ObjectUUID = UUID.Zero.ToString();
+ transaction.ObjectName = string.Empty;
+ transaction.RegionHandle = string.Empty;
+ transaction.Type = (int)TransactionType.BirthGift;
+ transaction.Time = (int)((DateTime.UtcNow.Ticks - TicksToEpoch) / 10000000);;
+ transaction.Status = (int)Status.PENDING_STATUS;
+ transaction.SecureCode = UUID.Random().ToString();
+ transaction.CommonName = string.Empty;
+ transaction.Description = "addUser " + DateTime.UtcNow.ToString();
+
+ bool ret = addTransaction(transaction);
+ if (!ret) return false;
+
+ //
+ MySQLSuperManager dbm = GetLockedConnection();
+
+ try {
+ ret = dbm.Manager.addUser(userID, 0, status, type); // make Balance Table
+ }
+ catch (MySql.Data.MySqlClient.MySqlException e) {
+ dbm.Manager.Reconnect();
+ ret = dbm.Manager.addUser(userID, 0, status, type); // make Balance Table
+ }
+ catch (Exception e) {
+ m_log.Error(e.ToString());
+ return false;
+ }
+ finally {
+ dbm.Release();
+ }
+
+ //
+ if (ret) ret = giveMoney(transaction.TransUUID, userID, balance);
+ return ret;
+ }
+
+
+ public bool updateTransactionStatus(UUID transactionID, int status, string description)
+ {
+ MySQLSuperManager dbm = GetLockedConnection();
+
+ try {
+ return dbm.Manager.updateTransactionStatus(transactionID, status, description);
+ }
+ catch (MySql.Data.MySqlClient.MySqlException e) {
+ dbm.Manager.Reconnect();
+ return dbm.Manager.updateTransactionStatus(transactionID, status, description);
+ }
+ catch (Exception e) {
+ m_log.Error(e.ToString());
+ return false;
+ }
+ finally {
+ dbm.Release();
+ }
+ }
+
+
+ public bool SetTransExpired(int deadTime)
+ {
+ MySQLSuperManager dbm = GetLockedConnection();
+
+ try {
+ return dbm.Manager.SetTransExpired(deadTime);
+ }
+ catch (MySql.Data.MySqlClient.MySqlException e) {
+ dbm.Manager.Reconnect();
+ return dbm.Manager.SetTransExpired(deadTime);
+ }
+ catch (Exception e) {
+ m_log.Error(e.ToString());
+ return false;
+ }
+ finally {
+ dbm.Release();
+ }
+ }
+
+
+ public bool ValidateTransfer(string secureCode, UUID transactionID)
+ {
+ MySQLSuperManager dbm = GetLockedConnection();
+
+ try {
+ return dbm.Manager.ValidateTransfer(secureCode, transactionID);
+ }
+ catch (MySql.Data.MySqlClient.MySqlException e) {
+ dbm.Manager.Reconnect();
+ return dbm.Manager.ValidateTransfer(secureCode, transactionID);
+ }
+ catch (Exception e) {
+ m_log.Error(e.ToString());
+ return false;
+ }
+ finally {
+ dbm.Release();
+ }
+ }
+
+
+ public TransactionData FetchTransaction(UUID transactionID)
+ {
+ MySQLSuperManager dbm = GetLockedConnection();
+
+ try {
+ return dbm.Manager.FetchTransaction(transactionID);
+ }
+ catch (MySql.Data.MySqlClient.MySqlException e) {
+ dbm.Manager.Reconnect();
+ return dbm.Manager.FetchTransaction(transactionID);
+ }
+ catch (Exception e) {
+ m_log.Error(e.ToString());
+ return null;
+ }
+ finally {
+ dbm.Release();
+ }
+ }
+
+
+ public TransactionData FetchTransaction(string userID, int startTime, int endTime, int lastIndex)
+ {
+ MySQLSuperManager dbm = GetLockedConnection();
+ TransactionData[] arrTransaction;
+
+ uint index = 0;
+ if (lastIndex>=0) index = Convert.ToUInt32(lastIndex) + 1;
+
+ try {
+ arrTransaction = dbm.Manager.FetchTransaction(userID, startTime, endTime, index, 1);
+ }
+ catch (MySql.Data.MySqlClient.MySqlException e) {
+ dbm.Manager.Reconnect();
+ arrTransaction = dbm.Manager.FetchTransaction(userID, startTime, endTime, index, 1);
+ }
+ catch (Exception e) {
+ m_log.Error(e.ToString());
+ return null;
+ }
+ finally {
+ dbm.Release();
+ }
+
+ //
+ if (arrTransaction.Length > 0) {
+ return arrTransaction[0];
+ }
+ else {
+ return null;
+ }
+ }
+
+
+ public bool DoTransfer(UUID transactionUUID)
+ {
+ bool do_trans = false;
+
+ TransactionData transaction = new TransactionData();
+ transaction = FetchTransaction(transactionUUID);
+
+ if (transaction != null && transaction.Status == (int)Status.PENDING_STATUS) {
+ int balance = getBalance(transaction.Sender);
+
+ //check the amount
+ if (transaction.Amount >= 0 && balance >= transaction.Amount) {
+ if (withdrawMoney(transactionUUID, transaction.Sender, transaction.Amount)) {
+ //If receiver not found, add it to DB.
+ if (getBalance(transaction.Receiver) == -1) {
+ m_log.ErrorFormat("[MONEY DB]: DoTransfer: Receiver not found in balances DB. {0}", transaction.Receiver);
+ return false;
+ }
+
+ if (giveMoney(transactionUUID, transaction.Receiver, transaction.Amount)) {
+ do_trans = true;
+ }
+ else { // give money to receiver failed. 返金処理
+ m_log.ErrorFormat("[MONEY DB]: Give money to receiver {0} failed", transaction.Receiver);
+ //Return money to sender
+ if (giveMoney(transactionUUID, transaction.Sender, transaction.Amount)) {
+ m_log.ErrorFormat("[MONEY DB]: give money to receiver {0} failed but return it to sender {1} successfully",
+ transaction.Receiver, transaction.Sender);
+ updateTransactionStatus(transactionUUID, (int)Status.FAILED_STATUS, "give money to receiver failed but return it to sender successfully");
+ }
+ else {
+ m_log.ErrorFormat("[MONEY DB]: FATAL ERROR: Money withdrawn from sender: {0}, but failed to be given to receiver {1}",
+ transaction.Sender, transaction.Receiver);
+ updateTransactionStatus(transactionUUID, (int)Status.ERROR_STATUS, "give money to receiver failed, and return it to sender unsuccessfully!!!");
+ }
+ }
+ }
+ else { // withdraw money failed
+ m_log.ErrorFormat("[MONEY DB]: Withdraw money from sender {0} failed", transaction.Sender);
+ }
+ }
+ else { // not enough balance to finish the transaction
+ m_log.ErrorFormat("[MONEY DB]: Not enough balance for user: {0} to apply the transaction.", transaction.Sender);
+ }
+ }
+ else { // Can not fetch the transaction or it has expired
+ m_log.ErrorFormat("[MONEY DB]: The transaction:{0} has expired", transactionUUID.ToString());
+ }
+
+ //
+ if (do_trans) {
+ setTotalSale(transaction);
+ }
+
+ return do_trans;
+ }
+
+
+ // by Fumi.Iseki
+ public bool DoAddMoney(UUID transactionUUID)
+ {
+ TransactionData transaction = new TransactionData();
+ transaction = FetchTransaction(transactionUUID);
+
+ if (transaction!=null && transaction.Status==(int)Status.PENDING_STATUS) {
+ //If receiver not found, add it to DB.
+ if (getBalance(transaction.Receiver)==-1) {
+ m_log.ErrorFormat("[MONEY DB]: DoAddMoney: Receiver not found in balances DB. {0}", transaction.Receiver);
+ return false;
+ }
+ //
+ if (giveMoney(transactionUUID, transaction.Receiver, transaction.Amount)) {
+ setTotalSale(transaction);
+ return true;
+ }
+ else { // give money to receiver failed.
+ m_log.ErrorFormat("[MONEY DB]: Add money to receiver {0} failed", transaction.Receiver);
+ updateTransactionStatus(transactionUUID, (int)Status.FAILED_STATUS, "add money to receiver failed");
+ }
+ }
+ else { // Can not fetch the transaction or it has expired
+ m_log.ErrorFormat("[MONEY DB]: The transaction:{0} has expired", transactionUUID.ToString());
+ }
+
+ return false;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // userinfo
+ //
+
+ public bool TryAddUserInfo(UserInfo user)
+ {
+ MySQLSuperManager dbm = GetLockedConnection();
+
+ UserInfo userInfo = null;
+
+ try {
+ userInfo = dbm.Manager.fetchUserInfo(user.UserID);
+ }
+ catch (MySql.Data.MySqlClient.MySqlException e) {
+ dbm.Manager.Reconnect();
+ userInfo = dbm.Manager.fetchUserInfo(user.UserID);
+ }
+ catch (Exception e) {
+ m_log.Error(e.ToString());
+ dbm.Release();
+ return false;
+ }
+
+ try {
+ if (userInfo!=null) {
+ //m_log.InfoFormat("[MONEY DB]: Found user \"{0}\", now update information", user.Avatar);
+ if (dbm.Manager.updateUserInfo(user)) return true;
+ }
+ else if (dbm.Manager.addUserInfo(user)) {
+ //m_log.InfoFormat("[MONEY DB]: Unable to find user \"{0}\", add it to DB successfully", user.Avatar);
+ return true;
+ }
+ m_log.InfoFormat("[MONEY DB]: WARNNING: TryAddUserInfo: Unable to TryAddUserInfo.");
+ return false;
+ }
+ catch (Exception e) {
+ m_log.Error(e.ToString());
+ return false;
+ }
+ finally {
+ dbm.Release();
+ }
+ }
+
+
+ public UserInfo FetchUserInfo(string userID)
+ {
+ UserInfo userInfo = null;
+ MySQLSuperManager dbm = GetLockedConnection();
+
+ try {
+ userInfo = dbm.Manager.fetchUserInfo(userID);
+ return userInfo;
+ }
+ catch (MySql.Data.MySqlClient.MySqlException e) {
+ dbm.Manager.Reconnect();
+ userInfo = dbm.Manager.fetchUserInfo(userID);
+ return userInfo;
+ }
+ catch (Exception e) {
+ m_log.Error(e.ToString());
+ return null;
+ }
+ finally {
+ dbm.Release();
+ }
+ }
+
+
+ public int getTransactionNum(string userID, int startTime, int endTime)
+ {
+ MySQLSuperManager dbm = GetLockedConnection();
+
+ try {
+ return dbm.Manager.getTransactionNum(userID,startTime,endTime);
+ }
+ catch (MySql.Data.MySqlClient.MySqlException e) {
+ dbm.Manager.Reconnect();
+ return dbm.Manager.getTransactionNum(userID,startTime,endTime);
+ }
+ catch (Exception e) {
+ m_log.Error(e.ToString());
+ return -1;
+ }
+ finally {
+ dbm.Release();
+ }
+ }
+ }
+#pragma warning restore 0168
+}
diff --git a/source/ThirdParty/OpenSim.Grid.MoneyServer/MoneyServerBase.cs b/source/ThirdParty/OpenSim.Grid.MoneyServer/MoneyServerBase.cs
new file mode 100644
index 0000000..654e4d1
--- /dev/null
+++ b/source/ThirdParty/OpenSim.Grid.MoneyServer/MoneyServerBase.cs
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/, http://www.nsl.tuis.ac.jp/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSim Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.IO;
+using System.Collections.Generic;
+using System.Text;
+using System.Net;
+using System.Net.Security;
+using System.Reflection;
+using System.Timers;
+//using System.Security.Authentication;
+//using System.Security.Cryptography;
+//using System.Security.Cryptography.X509Certificates;
+
+using HttpServer;
+using Nini.Config;
+using log4net;
+
+using OpenSim.Framework;
+using OpenSim.Framework.Console;
+using OpenSim.Framework.Servers;
+using OpenSim.Framework.Servers.HttpServer;
+using OpenSim.Data;
+
+using NSL.Certificate.Tools;
+
+
+
+namespace OpenSim.Grid.MoneyServer
+{
+ class MoneyServerBase : BaseOpenSimServer, IMoneyServiceCore
+ {
+ private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
+ private string connectionString = string.Empty;
+ private uint m_moneyServerPort = 8008;
+
+ private string m_certFilename = "";
+ private string m_certPassword = "";
+ private string m_cacertFilename = "";
+ private string m_clcrlFilename = "";
+ private bool m_checkClientCert = false;
+
+ private int DEAD_TIME = 120;
+ private int MAX_DB_CONNECTION = 10;
+
+ private MoneyXmlRpcModule m_moneyXmlRpcModule;
+ private MoneyDBService m_moneyDBService;
+
+ private NSLCertificateVerify m_certVerify = new NSLCertificateVerify(); // クライアント認証用
+
+ private Dictionary m_sessionDic = new Dictionary();
+ private Dictionary m_secureSessionDic = new Dictionary();
+ private Dictionary m_webSessionDic = new Dictionary();
+
+ IConfig m_server_config;
+ IConfig m_cert_config;
+
+
+ public MoneyServerBase()
+ {
+ m_console = new LocalConsole("Money ");
+// m_console = new CommandConsole("Money ");
+ MainConsole.Instance = m_console;
+ }
+
+
+ public void Work()
+ {
+ //m_console.Notice("Enter help for a list of commands\n");
+
+ //The timer checks the transactions table every 60 seconds
+ Timer checkTimer = new Timer();
+ checkTimer.Interval = 60*1000;
+ checkTimer.Enabled = true;
+ checkTimer.Elapsed += new ElapsedEventHandler(CheckTransaction);
+ checkTimer.Start();
+
+ while (true) {
+ m_console.Prompt();
+ }
+ }
+
+
+ ///
+ /// Check the transactions table, set expired transaction state to failed
+ ///
+ private void CheckTransaction(object sender, ElapsedEventArgs e)
+ {
+ long ticksToEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks;
+ int unixEpochTime =(int) ((DateTime.UtcNow.Ticks - ticksToEpoch )/10000000);
+ int deadTime = unixEpochTime - DEAD_TIME;
+ m_moneyDBService.SetTransExpired(deadTime);
+ }
+
+
+ protected override void StartupSpecific()
+ {
+ m_log.Info("[MONEY SERVER]: Setup HTTP Server process");
+
+ ReadIniConfig();
+
+ try {
+ if (m_certFilename!="") {
+ m_httpServer = new BaseHttpServer(m_moneyServerPort, true, m_certFilename, m_certPassword);
+ if (m_checkClientCert) {
+ Type typeBaseHttpServer = typeof(BaseHttpServer); // BaseHttpServer.cs にパッチがあたっていない場合のため
+ PropertyInfo pinfo = typeBaseHttpServer.GetProperty("CertificateValidationCallback");
+
+ if (pinfo!=null) {
+ //m_httpServer.CertificateValidationCallback = (RemoteCertificateValidationCallback)m_certVerify.ValidateClientCertificate;
+ pinfo.SetValue(m_httpServer, (RemoteCertificateValidationCallback)m_certVerify.ValidateClientCertificate, null);
+ m_log.Info ("[MONEY SERVER]: Set RemoteCertificateValidationCallback");
+ }
+ else {
+ m_log.Error("[MONEY SERVER]: StartupSpecific: CheckClientCert is true. But this MoneyServer does not support CheckClientCert!!");
+ }
+ }
+ }
+ else {
+ m_httpServer = new BaseHttpServer(m_moneyServerPort);
+ }
+
+ SetupMoneyServices();
+ m_httpServer.Start();
+ base.StartupSpecific(); // OpenSim/Framework/Servers/BaseOpenSimServer.cs
+ }
+
+ catch (Exception e) {
+ m_log.ErrorFormat("[MONEY SERVER]: StartupSpecific: Fail to start HTTPS process");
+ m_log.ErrorFormat("[MONEY SERVER]: StartupSpecific: Please Check Certificate File or Password. Exit");
+ m_log.ErrorFormat("[MONEY SERVER]: StartupSpecific: {0}", e);
+ Environment.Exit(1);
+ }
+
+ //TODO : Add some console commands here
+ }
+
+
+ protected void ReadIniConfig()
+ {
+ MoneyServerConfigSource moneyConfig = new MoneyServerConfigSource();
+ Config = moneyConfig.m_config; // for base.StartupSpecific()
+
+ try {
+ // [Startup]
+ IConfig st_config = moneyConfig.m_config.Configs["Startup"];
+ string PIDFile = st_config.GetString("PIDFile", "");
+ if (PIDFile!="") Create_PIDFile(PIDFile);
+
+ // [MySql]
+ IConfig db_config = moneyConfig.m_config.Configs["MySql"];
+ string sqlserver = db_config.GetString("hostname", "localhost");
+ string database = db_config.GetString("database", "OpenSim");
+ string username = db_config.GetString("username", "root");
+ string password = db_config.GetString("password", "password");
+ string pooling = db_config.GetString("pooling", "false");
+ string port = db_config.GetString("port", "3306");
+ MAX_DB_CONNECTION = db_config.GetInt ("MaxConnection", MAX_DB_CONNECTION);
+
+ connectionString = "Server=" + sqlserver + ";Port=" + port + ";Database=" + database + ";User ID=" +
+ username + ";Password=" + password + ";Pooling=" + pooling + ";";
+
+ // [MoneyServer]
+ m_server_config = moneyConfig.m_config.Configs["MoneyServer"];
+ DEAD_TIME = m_server_config.GetInt("ExpiredTime", DEAD_TIME);
+
+ //
+ // [Certificate]
+ m_cert_config = moneyConfig.m_config.Configs["Certificate"];
+ if (m_cert_config==null) {
+ m_log.Info("[MONEY SERVER]: [Certificate] section is not found. Using [MoneyServer] section instead");
+ m_cert_config = m_server_config;
+ }
+
+ // HTTPS Server Cert (Server Mode)
+ // サーバ証明書
+ m_certFilename = m_cert_config.GetString("ServerCertFilename", m_certFilename);
+ m_certPassword = m_cert_config.GetString("ServerCertPassword", m_certPassword);
+ if (m_certFilename!="") {
+ m_log.Info("[MONEY SERVER]: ReadIniConfig: Execute HTTPS comunication. Cert file is " + m_certFilename);
+ }
+
+ // クライアント認証
+ m_checkClientCert = m_cert_config.GetBoolean("CheckClientCert", m_checkClientCert);
+ m_cacertFilename = m_cert_config.GetString("CACertFilename", m_cacertFilename);
+ m_clcrlFilename = m_cert_config.GetString("ClientCrlFilename", m_clcrlFilename);
+ //
+ if (m_checkClientCert && m_cacertFilename!="") {
+ m_certVerify.SetPrivateCA(m_cacertFilename);
+ m_log.Info("[MONEY SERVER]: ReadIniConfig: Execute Authentication of Clients. CA file is " + m_cacertFilename);
+ }
+ else {
+ m_checkClientCert = false;
+ }
+
+ if (m_checkClientCert) {
+ if (m_clcrlFilename!="") {
+ m_certVerify.SetPrivateCRL(m_clcrlFilename);
+ m_log.Info("[MONEY SERVER]: ReadIniConfig: Execute Authentication of Clients. CRL file is " + m_clcrlFilename);
+ }
+ }
+ }
+
+ catch (Exception) {
+ m_log.Error("[MONEY SERVER]: ReadIniConfig: Fail to setup configure. Please check MoneyServer.ini. Exit");
+ Environment.Exit(1);
+ }
+ }
+
+
+ // added by skidz
+ protected void Create_PIDFile(string path)
+ {
+ try {
+ string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString();
+ FileStream fs = File.Create(path);
+ System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
+ Byte[] buf = enc.GetBytes(pidstring);
+ fs.Write(buf, 0, buf.Length);
+ fs.Close();
+ m_pidFile = path;
+ }
+ catch (Exception) {
+ }
+ }
+
+
+ protected virtual void SetupMoneyServices()
+ {
+ m_log.Info("[MONEY SERVER]: Connecting to Money Storage Server");
+
+ m_moneyDBService = new MoneyDBService();
+ m_moneyDBService.Initialise(connectionString, MAX_DB_CONNECTION);
+
+ m_moneyXmlRpcModule = new MoneyXmlRpcModule();
+// m_moneyXmlRpcModule.Initialise(m_version, m_server_config, m_cert_config, m_moneyDBService, this);
+ m_moneyXmlRpcModule.Initialise(m_version, m_moneyDBService, this);
+ m_moneyXmlRpcModule.PostInitialise();
+ }
+
+
+ //
+ public bool IsCheckClientCert()
+ {
+ return m_checkClientCert;
+ }
+
+
+ public IConfig GetServerConfig()
+ {
+ return m_server_config;
+ }
+
+
+ public IConfig GetCertConfig()
+ {
+ return m_cert_config;
+ }
+
+
+ public BaseHttpServer GetHttpServer()
+ {
+ return m_httpServer;
+ }
+
+
+ public Dictionary GetSessionDic()
+ {
+ return m_sessionDic;
+ }
+
+
+ public Dictionary GetSecureSessionDic()
+ {
+ return m_secureSessionDic;
+ }
+
+
+ public Dictionary GetWebSessionDic()
+ {
+ return m_webSessionDic;
+ }
+
+ }
+
+
+
+ //
+ class MoneyServerConfigSource
+ {
+ public IniConfigSource m_config;
+
+ public MoneyServerConfigSource()
+ {
+ string configPath = Path.Combine(Directory.GetCurrentDirectory(), "MoneyServer.ini");
+ if (File.Exists(configPath)) {
+ m_config = new IniConfigSource(configPath);
+ }
+ else {
+ //TODO: create default configuration.
+ //m_config = DefaultConfig();
+ }
+ }
+
+
+ public void Save(string path)
+ {
+ m_config.Save(path);
+ }
+
+ }
+}
diff --git a/source/ThirdParty/OpenSim.Grid.MoneyServer/MoneyXmlRpcModule.cs b/source/ThirdParty/OpenSim.Grid.MoneyServer/MoneyXmlRpcModule.cs
new file mode 100644
index 0000000..1b52f86
--- /dev/null
+++ b/source/ThirdParty/OpenSim.Grid.MoneyServer/MoneyXmlRpcModule.cs
@@ -0,0 +1,1708 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/, http://www.nsl.tuis.ac.jp/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSim Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Reflection;
+using System.Collections;
+using System.Net;
+using System.Net.Security;
+using System.Security.Cryptography;
+using System.Security.Cryptography.X509Certificates;
+
+using log4net;
+using Nini.Config;
+using Nwc.XmlRpc;
+
+using OpenMetaverse;
+using OpenSim.Framework;
+using OpenSim.Framework.Servers;
+using OpenSim.Framework.Servers.HttpServer;
+using OpenSim.Data.MySQL.MySQLMoneyDataWrapper;
+using OpenSim.Modules.Currency;
+using OpenSim.Region.Framework.Scenes;
+
+using NSL.Network.XmlRpc;
+using NSL.Certificate.Tools;
+
+
+namespace OpenSim.Grid.MoneyServer
+{
+ class MoneyXmlRpcModule
+ {
+ private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
+ private int m_defaultBalance = 1000;
+ //
+ private bool m_forceTransfer = false;
+ private string m_bankerAvatar = "";
+
+ private bool m_scriptSendMoney = false;
+ private string m_scriptAccessKey = "";
+ private string m_scriptIPaddress = "127.0.0.1";
+
+ private bool m_hg_enable = false;
+ private bool m_gst_enable = false;
+ private int m_hg_defaultBalance = 0;
+ private int m_gst_defaultBalance = 0;
+
+ private bool m_checkServerCert = false;
+ private string m_cacertFilename = "";
+
+ private string m_certFilename = "";
+ private string m_certPassword = "";
+ private X509Certificate2 m_clientCert = null;
+
+ private string m_sslCommonName = "";
+
+ private NSLCertificateVerify m_certVerify = new NSLCertificateVerify(); // サーバ認証用
+
+
+ // Update Balance Messages
+ private string m_BalanceMessageLandSale = "Paid the Money L${0} for Land.";
+ private string m_BalanceMessageRcvLandSale = "";
+ private string m_BalanceMessageSendGift = "Sent Gift L${0} to {1}.";
+ private string m_BalanceMessageReceiveGift = "Received Gift L${0} from {1}.";
+ private string m_BalanceMessagePayCharge = "";
+ private string m_BalanceMessageBuyObject = "Bought the Object {2} from {1} by L${0}.";
+ private string m_BalanceMessageSellObject = "{1} bought the Object {2} by L${0}.";
+ private string m_BalanceMessageGetMoney = "Got the Money L${0} from {1}.";
+ private string m_BalanceMessageBuyMoney = "Bought the Money L${0}.";
+ private string m_BalanceMessageRollBack = "RollBack the Transaction: L${0} from/to {1}.";
+ private string m_BalanceMessageSendMoney = "Paid the Money L${0} to {1}.";
+ private string m_BalanceMessageReceiveMoney = "Received L${0} from {1}.";
+
+ private bool m_enableAmountZero = false;
+
+ const int MONEYMODULE_REQUEST_TIMEOUT = 30 * 1000; //30 seconds
+ private long TicksToEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks;
+
+ private IMoneyDBService m_moneyDBService;
+ private IMoneyServiceCore m_moneyCore;
+
+ protected IConfig m_server_config;
+ protected IConfig m_cert_config;
+
+ ///
+ /// Used to notify old regions as to which OpenSim version to upgrade to
+ ///
+ //private string m_opensimVersion;
+
+ private Dictionary m_sessionDic;
+ private Dictionary m_secureSessionDic;
+ private Dictionary m_webSessionDic;
+
+ protected BaseHttpServer m_httpServer;
+
+
+ public MoneyXmlRpcModule()
+ {
+ }
+
+
+ public void Initialise(string opensimVersion, IMoneyDBService moneyDBService, IMoneyServiceCore moneyCore)
+ {
+ //m_opensimVersion = opensimVersion;
+ m_moneyDBService = moneyDBService;
+ m_moneyCore = moneyCore;
+ m_server_config = m_moneyCore.GetServerConfig(); // [MoneyServer] Section
+ m_cert_config = m_moneyCore.GetCertConfig(); // [Certificate] Section
+
+ ////////////////////////////////////////////////////////////////////////
+ // [MoneyServer] Section
+ m_defaultBalance = m_server_config.GetInt("DefaultBalance", m_defaultBalance);
+
+ m_forceTransfer = m_server_config.GetBoolean("EnableForceTransfer", m_forceTransfer);
+
+ string banker = m_server_config.GetString("BankerAvatar", m_bankerAvatar);
+ m_bankerAvatar = banker.ToLower();
+
+ m_enableAmountZero = m_server_config.GetBoolean("EnableAmountZero", m_enableAmountZero);
+ m_scriptSendMoney = m_server_config.GetBoolean("EnableScriptSendMoney", m_scriptSendMoney);
+ m_scriptAccessKey = m_server_config.GetString("MoneyScriptAccessKey", m_scriptAccessKey);
+ m_scriptIPaddress = m_server_config.GetString("MoneyScriptIPaddress", m_scriptIPaddress);
+
+ // Hyper Grid Avatar
+ m_hg_enable = m_server_config.GetBoolean("EnableHGAvatar", m_hg_enable);
+ m_gst_enable = m_server_config.GetBoolean("EnableGuestAvatar", m_gst_enable);
+ m_hg_defaultBalance = m_server_config.GetInt("HGAvatarDefaultBalance", m_hg_defaultBalance);
+ m_gst_defaultBalance = m_server_config.GetInt("GuestAvatarDefaultBalance", m_gst_defaultBalance);
+
+ // Update Balance Messages
+ m_BalanceMessageLandSale = m_server_config.GetString("BalanceMessageLandSale", m_BalanceMessageLandSale);
+ m_BalanceMessageRcvLandSale = m_server_config.GetString("BalanceMessageRcvLandSale", m_BalanceMessageRcvLandSale);
+ m_BalanceMessageSendGift = m_server_config.GetString("BalanceMessageSendGift", m_BalanceMessageSendGift);
+ m_BalanceMessageReceiveGift = m_server_config.GetString("BalanceMessageReceiveGift", m_BalanceMessageReceiveGift);
+ m_BalanceMessagePayCharge = m_server_config.GetString("BalanceMessagePayCharge", m_BalanceMessagePayCharge);
+ m_BalanceMessageBuyObject = m_server_config.GetString("BalanceMessageBuyObject", m_BalanceMessageBuyObject);
+ m_BalanceMessageSellObject = m_server_config.GetString("BalanceMessageSellObject", m_BalanceMessageSellObject);
+ m_BalanceMessageGetMoney = m_server_config.GetString("BalanceMessageGetMoney", m_BalanceMessageGetMoney);
+ m_BalanceMessageBuyMoney = m_server_config.GetString("BalanceMessageBuyMoney", m_BalanceMessageBuyMoney);
+ m_BalanceMessageRollBack = m_server_config.GetString("BalanceMessageRollBack", m_BalanceMessageRollBack);
+ m_BalanceMessageSendMoney = m_server_config.GetString("BalanceMessageSendMoney", m_BalanceMessageSendMoney);
+ m_BalanceMessageReceiveMoney = m_server_config.GetString("BalanceMessageReceiveMoney", m_BalanceMessageReceiveMoney);
+
+
+ ////////////////////////////////////////////////////////////////////////
+ // [Certificate] Section
+
+ // XML RPC to Region Server (Client Mode)
+ // クライアント証明書
+ m_certFilename = m_cert_config.GetString("ClientCertFilename", m_certFilename);
+ m_certPassword = m_cert_config.GetString("ClientCertPassword", m_certPassword);
+ if (m_certFilename!="") {
+ m_clientCert = new X509Certificate2(m_certFilename, m_certPassword);
+ //m_clientCert = new X509Certificate2(m_certFilename, m_certPassword, X509KeyStorageFlags.MachineKeySet);
+ m_log.Info("[MONEY RPC]: Initialise: Issue Authentication of Client. Cert file is " + m_cacertFilename);
+ }
+
+ // サーバ認証
+ m_checkServerCert = m_cert_config.GetBoolean("CheckServerCert", m_checkServerCert);
+
+ // CA
+ m_cacertFilename = m_cert_config.GetString("CACertFilename", m_cacertFilename);
+ if (m_checkServerCert && m_cacertFilename!="") {
+ m_certVerify.SetPrivateCA(m_cacertFilename);
+ ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(m_certVerify.ValidateServerCertificate);
+ m_log.Info("[MONEY RPC]: Initialise: Execute Authentication of Server. CA file is " + m_cacertFilename);
+ }
+ else {
+ m_checkServerCert = false;
+ ServicePointManager.ServerCertificateValidationCallback = null;
+ }
+
+ m_sessionDic = m_moneyCore.GetSessionDic();
+ m_secureSessionDic = m_moneyCore.GetSecureSessionDic();
+ m_webSessionDic = m_moneyCore.GetWebSessionDic();
+ RegisterHandlers();
+ }
+
+
+ public void PostInitialise()
+ {
+ }
+
+
+ public void RegisterHandlers()
+ {
+ m_httpServer = m_moneyCore.GetHttpServer();
+ m_httpServer.AddXmlRPCHandler("ClientLogin", handleClientLogin);
+ m_httpServer.AddXmlRPCHandler("ClientLogout", handleClientLogout);
+ m_httpServer.AddXmlRPCHandler("GetBalance", handleGetBalance);
+ m_httpServer.AddXmlRPCHandler("GetTransaction", handleGetTransaction);
+
+ m_httpServer.AddXmlRPCHandler("CancelTransfer", handleCancelTransfer);
+ m_httpServer.AddXmlRPCHandler("TransferMoney", handleTransaction);
+ m_httpServer.AddXmlRPCHandler("ForceTransferMoney", handleForceTransaction); // added
+ m_httpServer.AddXmlRPCHandler("PayMoneyCharge", handlePayMoneyCharge); // added
+ m_httpServer.AddXmlRPCHandler("AddBankerMoney", handleAddBankerMoney); // added
+ m_httpServer.AddXmlRPCHandler("SendMoney", handleScriptTransaction); // added
+ m_httpServer.AddXmlRPCHandler("MoveMoney", handleScriptTransaction); // added
+
+ // this is from original DTL. not check yet.
+ m_httpServer.AddXmlRPCHandler("WebLogin", handleWebLogin);
+ m_httpServer.AddXmlRPCHandler("WebLogout", handleWebLogout);
+ m_httpServer.AddXmlRPCHandler("WebGetBalance", handleWebGetBalance);
+ m_httpServer.AddXmlRPCHandler("WebGetTransaction", handleWebGetTransaction);
+ m_httpServer.AddXmlRPCHandler("WebGetTransactionNum", handleWebGetTransactionNum);
+ }
+
+
+ //
+ public string GetSSLCommonName(XmlRpcRequest request)
+ {
+ if (request.Params.Count>5) {
+ m_sslCommonName = (string)request.Params[5];
+ }
+ else if (request.Params.Count==5) {
+ m_sslCommonName = (string)request.Params[4];
+ if (m_sslCommonName=="gridproxy") m_sslCommonName = "";
+ }
+ else {
+ m_sslCommonName = "";
+ }
+ return m_sslCommonName;
+ }
+
+
+ //
+ public string GetSSLCommonName()
+ {
+ return m_sslCommonName;
+ }
+
+
+ ///
+ /// Get the user balance when user entering a parcel.
+ ///
+ ///
+ ///
+ public XmlRpcResponse handleClientLogin(XmlRpcRequest request, IPEndPoint remoteClient)
+ {
+ //m_log.InfoFormat("[MONEY RPC]: handleClientLogin:");
+
+ GetSSLCommonName(request);
+
+ Hashtable requestData = (Hashtable)request.Params[0];
+ XmlRpcResponse response = new XmlRpcResponse();
+ Hashtable responseData = new Hashtable();
+ response.Value = responseData;
+
+ responseData["success"] = false;
+ responseData["clientBalance"] = 0;
+
+ // Check Client Cert
+ if (m_moneyCore.IsCheckClientCert()) {
+ string commonName = GetSSLCommonName();
+ if (commonName=="") {
+ m_log.ErrorFormat("[MONEY RPC]: handleClientLogin: Warnning: Check Client Cert is set, but SSL Common Name is empty.");
+ responseData["success"] = false;
+ responseData["description"] = "SSL Common Name is empty";
+ return response;
+ }
+ else {
+ m_log.InfoFormat("[MONEY RPC]: handleClientLogin: SSL Common Name is {0}", commonName);
+ }
+
+ }
+
+ string universalID = string.Empty;
+ string clientUUID = string.Empty;
+ string sessionID = string.Empty;
+ string secureID = string.Empty;
+ string simIP = string.Empty;
+ string userName = string.Empty;
+ int balance = 0;
+ int avatarType = (int)AvatarType.UNKNOWN_AVATAR;
+ int avatarClass = (int)AvatarType.UNKNOWN_AVATAR;
+
+ if (requestData.ContainsKey("clientUUID")) clientUUID = (string)requestData["clientUUID"];
+ if (requestData.ContainsKey("clientSessionID")) sessionID = (string)requestData["clientSessionID"];
+ if (requestData.ContainsKey("clientSecureSessionID")) secureID = (string)requestData["clientSecureSessionID"];
+ if (requestData.ContainsKey("universalID")) universalID = (string)requestData["universalID"];
+ if (requestData.ContainsKey("userName")) userName = (string)requestData["userName"];
+ if (requestData.ContainsKey("openSimServIP")) simIP = (string)requestData["openSimServIP"];
+ if (requestData.ContainsKey("avatarType")) avatarType = Convert.ToInt32(requestData["avatarType"]);
+ if (requestData.ContainsKey("avatarClass")) avatarClass = Convert.ToInt32(requestData["avatarClass"]);
+
+ //
+ string firstName = string.Empty;
+ string lastName = string.Empty;
+ string serverURL = string.Empty;
+ string securePsw = string.Empty;
+ //
+ if (!String.IsNullOrEmpty(universalID)) {
+ UUID uuid;
+ Util.ParseUniversalUserIdentifier(universalID, out uuid, out serverURL, out firstName, out lastName, out securePsw);
+ }
+ if (String.IsNullOrEmpty(userName)) {
+ userName = firstName + " " + lastName;
+ }
+
+ // Information from DB
+ UserInfo userInfo = m_moneyDBService.FetchUserInfo(clientUUID);
+ if (userInfo!=null) {
+ avatarType = userInfo.Type; // Avatar Type is not updated
+ if (avatarType ==(int)AvatarType.LOCAL_AVATAR) avatarClass = (int)AvatarType.LOCAL_AVATAR;
+ if (avatarClass==(int)AvatarType.UNKNOWN_AVATAR) avatarClass = userInfo.Class;
+ if (String.IsNullOrEmpty(userName)) userName = userInfo.Avatar;
+ }
+ if (avatarType==(int)AvatarType.UNKNOWN_AVATAR) avatarType = avatarClass;
+
+ m_log.InfoFormat("[MONEY RPC]: handleClientLogon: Avatar {0} ({1}) is logged on.", userName, clientUUID);
+ m_log.InfoFormat("[MONEY RPC]: handleClientLogon: Avatar Type is {0} and Avatar Class is {1}", avatarType, avatarClass);
+
+
+ //
+ //Update the session and secure session dictionary
+ lock (m_sessionDic) {
+ if (!m_sessionDic.ContainsKey(clientUUID)) {
+ m_sessionDic.Add(clientUUID, sessionID);
+ }
+ else m_sessionDic[clientUUID] = sessionID;
+ }
+ lock (m_secureSessionDic) {
+ if (!m_secureSessionDic.ContainsKey(clientUUID)) {
+ m_secureSessionDic.Add(clientUUID, secureID);
+ }
+ else m_secureSessionDic[clientUUID] = secureID;
+ }
+
+ //
+ try {
+ if (userInfo==null) userInfo = new UserInfo();
+ userInfo.UserID = clientUUID;
+ userInfo.SimIP = simIP;
+ userInfo.Avatar = userName;
+ userInfo.PswHash = UUID.Zero.ToString();
+ userInfo.Type = avatarType;
+ userInfo.Class = avatarClass;
+ userInfo.ServerURL = serverURL;
+ if (!String.IsNullOrEmpty(securePsw)) userInfo.PswHash = securePsw;
+
+ if (!m_moneyDBService.TryAddUserInfo(userInfo)) {
+ m_log.ErrorFormat("[MONEY RPC]: handleClientLogin: Unable to refresh information for user \"{0}\" in DB.", userName);
+ responseData["success"] = true; // for FireStorm
+ responseData["description"] = "Update or add user information to db failed";
+ return response;
+ }
+ }
+ catch (Exception e) {
+ m_log.ErrorFormat("[MONEY RPC]: handleClientLogin: Can't update userinfo for user {0}: {1}", clientUUID, e.ToString());
+ responseData["description"] = "Exception occured" + e.ToString();
+ return response;
+ }
+
+ //
+ try {
+ balance = m_moneyDBService.getBalance(clientUUID);
+
+ //add user to balances table if not exist. (if balance is -1, it means avatar is not exist at balances table)
+ if (balance==-1) {
+ int default_balance = m_defaultBalance;
+ if (avatarClass==(int)AvatarType.HG_AVATAR) default_balance = m_hg_defaultBalance;
+ if (avatarClass==(int)AvatarType.GUEST_AVATAR) default_balance = m_gst_defaultBalance;
+
+ if (m_moneyDBService.addUser(clientUUID, default_balance, 0, avatarType)) {
+ responseData["success"] = true;
+ responseData["description"] = "add user successfully";
+ responseData["clientBalance"] = default_balance;
+ }
+ else {
+ responseData["description"] = "add user failed";
+ }
+ }
+ //Success
+ else if (balance >= 0) {
+ responseData["success"] = true;
+ responseData["description"] = "get user balance successfully";
+ responseData["clientBalance"] = balance;
+ }
+
+ return response;
+ }
+ catch (Exception e) {
+ m_log.ErrorFormat("[MONEY RPC]: handleClientLogin: Can't get balance of user {0}: {1}", clientUUID, e.ToString());
+ responseData["description"] = "Exception occured" + e.ToString();
+ }
+
+ return response;
+ }
+
+
+ //
+ public XmlRpcResponse handleClientLogout(XmlRpcRequest request, IPEndPoint remoteClient)
+ {
+ //m_log.InfoFormat("[MONEY RPC]: handleClientLogout:");
+
+ GetSSLCommonName(request);
+
+ Hashtable requestData = (Hashtable)request.Params[0];
+ XmlRpcResponse response = new XmlRpcResponse();
+ Hashtable responseData = new Hashtable();
+ response.Value = responseData;
+
+ string clientUUID = string.Empty;
+ if (requestData.ContainsKey("clientUUID")) clientUUID = (string)requestData["clientUUID"];
+
+ m_log.InfoFormat("[MONEY RPC]: handleClientLogout: User {0} is logging off.", clientUUID);
+ try {
+ lock (m_sessionDic) {
+ if (m_sessionDic.ContainsKey(clientUUID)) {
+ m_sessionDic.Remove(clientUUID);
+ }
+ }
+
+ lock (m_secureSessionDic) {
+ if (m_secureSessionDic.ContainsKey(clientUUID)) {
+ m_secureSessionDic.Remove(clientUUID);
+ }
+ }
+ }
+ catch (Exception e) {
+ m_log.Error("[MONEY RPC]: handleClientLogout: Failed to delete user session: " + e.ToString() );
+ responseData["success"] = false;
+ return response;
+ }
+
+ responseData["success"] = true;
+ return response;
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ //
+ ///
+ /// handle incoming transaction
+ ///
+ ///
+ ///
+ public XmlRpcResponse handleTransaction(XmlRpcRequest request, IPEndPoint remoteClient)
+ {
+ //m_log.InfoFormat("[MONEY RPC]: handleTransaction:");
+
+ GetSSLCommonName(request);
+
+ Hashtable requestData = (Hashtable)request.Params[0];
+ XmlRpcResponse response = new XmlRpcResponse();
+ Hashtable responseData = new Hashtable();
+ response.Value = responseData;
+
+ int amount = 0;
+ int transactionType = 0;
+ string senderID = string.Empty;
+ string receiverID = string.Empty;
+ string senderSessionID = string.Empty;
+ string senderSecureSessionID = string.Empty;
+ string objectID = string.Empty;
+ string objectName = string.Empty;
+ string regionHandle = string.Empty;
+ string regionUUID = string.Empty;
+ string description = "Newly added on";
+
+ responseData["success"] = false;
+ UUID transactionUUID = UUID.Random();
+
+ if (requestData.ContainsKey("senderID")) senderID = (string)requestData["senderID"];
+ if (requestData.ContainsKey("receiverID")) receiverID = (string)requestData["receiverID"];
+ if (requestData.ContainsKey("senderSessionID")) senderSessionID = (string)requestData["senderSessionID"];
+ if (requestData.ContainsKey("senderSecureSessionID")) senderSecureSessionID = (string)requestData["senderSecureSessionID"];
+ if (requestData.ContainsKey("amount")) amount = Convert.ToInt32(requestData["amount"]);
+ if (requestData.ContainsKey("objectID")) objectID = (string)requestData["objectID"];
+ if (requestData.ContainsKey("objectName")) objectName = (string)requestData["objectName"];
+ if (requestData.ContainsKey("regionHandle")) regionHandle = (string)requestData["regionHandle"];
+ if (requestData.ContainsKey("regionUUID")) regionUUID = (string)requestData["regionUUID"];
+ if (requestData.ContainsKey("transactionType")) transactionType = Convert.ToInt32(requestData["transactionType"]);
+ if (requestData.ContainsKey("description")) description = (string)requestData["description"];
+
+ if (m_sessionDic.ContainsKey(senderID) && m_secureSessionDic.ContainsKey(senderID)) {
+ if (m_sessionDic[senderID]==senderSessionID && m_secureSessionDic[senderID]==senderSecureSessionID) {
+ m_log.InfoFormat("[MONEY RPC]: handleTransaction: Transfering money from {0} to {1}", senderID, receiverID);
+ int time = (int)((DateTime.UtcNow.Ticks - TicksToEpoch) / 10000000);
+ try {
+ TransactionData transaction = new TransactionData();
+ transaction.TransUUID = transactionUUID;
+ transaction.Sender = senderID;
+ transaction.Receiver = receiverID;
+ transaction.Amount = amount;
+ transaction.ObjectUUID = objectID;
+ transaction.ObjectName = objectName;
+ transaction.RegionHandle = regionHandle;
+ transaction.RegionUUID = regionUUID;
+ transaction.Type = transactionType;
+ transaction.Time = time;
+ transaction.SecureCode = UUID.Random().ToString();
+ transaction.Status = (int)Status.PENDING_STATUS;
+ transaction.CommonName = GetSSLCommonName();
+ transaction.Description = description + " " + DateTime.UtcNow.ToString();
+
+ UserInfo rcvr = m_moneyDBService.FetchUserInfo(receiverID);
+ if (rcvr==null) {
+ m_log.ErrorFormat("[MONEY RPC]: handleTransaction: Receive User is not yet in DB {0}", receiverID);
+ return response;
+ }
+
+ bool result = m_moneyDBService.addTransaction(transaction);
+ if (result) {
+ UserInfo user = m_moneyDBService.FetchUserInfo(senderID);
+ if (user!=null) {
+ if (amount>0 || (m_enableAmountZero&&amount==0)) {
+ string snd_message = "";
+ string rcv_message = "";
+
+ if (transaction.Type==(int)TransactionType.Gift) {
+ snd_message = m_BalanceMessageSendGift;
+ rcv_message = m_BalanceMessageReceiveGift;
+ }
+ else if (transaction.Type==(int)TransactionType.LandSale) {
+ snd_message = m_BalanceMessageLandSale;
+ rcv_message = m_BalanceMessageRcvLandSale;
+ }
+ else if (transaction.Type==(int)TransactionType.PayObject) {
+ snd_message = m_BalanceMessageBuyObject;
+ rcv_message = m_BalanceMessageSellObject;
+ }
+ else if (transaction.Type==(int)TransactionType.ObjectPays) { // ObjectGiveMoney
+ rcv_message = m_BalanceMessageGetMoney;
+ }
+
+ responseData["success"] = NotifyTransfer(transactionUUID, snd_message, rcv_message, objectName);
+ }
+ else if (amount==0) {
+ responseData["success"] = true; // No messages for L$0 object. by Fumi.Iseki
+ }
+ return response;
+ }
+ }
+ else { // add transaction failed
+ m_log.ErrorFormat("[MONEY RPC]: handleTransaction: Add transaction for user {0} failed.", senderID);
+ }
+ return response;
+ }
+ catch (Exception e) {
+ m_log.Error("[MONEY RPC]: handleTransaction: Exception occurred while adding transaction: " + e.ToString());
+ }
+ return response;
+ }
+ }
+
+ m_log.Error("[MONEY RPC]: handleTransaction: Session authentication failure for sender " + senderID);
+ responseData["message"] = "Session check failure, please re-login later!";
+ return response;
+ }
+
+
+ //
+ // added by Fumi.Iseki
+ //
+ ///
+ /// handle incoming force transaction. no check senderSessionID and senderSecureSessionID
+ ///
+ ///
+ ///
+ public XmlRpcResponse handleForceTransaction(XmlRpcRequest request, IPEndPoint remoteClient)
+ {
+ //m_log.InfoFormat("[MONEY RPC]: handleForceTransaction:");
+
+ GetSSLCommonName(request);
+
+ Hashtable requestData = (Hashtable)request.Params[0];
+ XmlRpcResponse response = new XmlRpcResponse();
+ Hashtable responseData = new Hashtable();
+ response.Value = responseData;
+
+ int amount = 0;
+ int transactionType = 0;
+ string senderID = string.Empty;
+ string receiverID = string.Empty;
+ string objectID = string.Empty;
+ string objectName = string.Empty;
+ string regionHandle = string.Empty;
+ string regionUUID = string.Empty;
+ string description = "Newly added on";
+
+ responseData["success"] = false;
+ UUID transactionUUID = UUID.Random();
+
+ //
+ if (!m_forceTransfer) {
+ m_log.Error("[MONEY RPC]: handleForceTransaction: Not allowed force transfer of Money.");
+ m_log.Error("[MONEY RPC]: handleForceTransaction: Set enableForceTransfer at [MoneyServer] to true in MoneyServer.ini");
+ responseData["message"] = "not allowed force transfer of Money!";
+ return response;
+ }
+
+ if (requestData.ContainsKey("senderID")) senderID = (string)requestData["senderID"];
+ if (requestData.ContainsKey("receiverID")) receiverID = (string)requestData["receiverID"];
+ if (requestData.ContainsKey("amount")) amount = Convert.ToInt32(requestData["amount"]);
+ if (requestData.ContainsKey("objectID")) objectID = (string)requestData["objectID"];
+ if (requestData.ContainsKey("objectName")) objectName = (string)requestData["objectName"];
+ if (requestData.ContainsKey("regionHandle")) regionHandle = (string)requestData["regionHandle"];
+ if (requestData.ContainsKey("regionUUID")) regionUUID = (string)requestData["regionUUID"];
+ if (requestData.ContainsKey("transactionType")) transactionType = Convert.ToInt32(requestData["transactionType"]);
+ if (requestData.ContainsKey("description")) description = (string)requestData["description"];
+
+ m_log.InfoFormat("[MONEY RPC]: handleForceTransaction: Force transfering money from {0} to {1}", senderID, receiverID);
+ int time = (int)((DateTime.UtcNow.Ticks - TicksToEpoch) / 10000000);
+
+ try {
+ TransactionData transaction = new TransactionData();
+ transaction.TransUUID = transactionUUID;
+ transaction.Sender = senderID;
+ transaction.Receiver = receiverID;
+ transaction.Amount = amount;
+ transaction.ObjectUUID = objectID;
+ transaction.ObjectName = objectName;
+ transaction.RegionHandle = regionHandle;
+ transaction.RegionUUID = regionUUID;
+ transaction.Type = transactionType;
+ transaction.Time = time;
+ transaction.SecureCode = UUID.Random().ToString();
+ transaction.Status = (int)Status.PENDING_STATUS;
+ transaction.CommonName = GetSSLCommonName();
+ transaction.Description = description + " " + DateTime.UtcNow.ToString();
+
+ UserInfo rcvr = m_moneyDBService.FetchUserInfo(receiverID);
+ if (rcvr==null) {
+ m_log.ErrorFormat("[MONEY RPC]: handleForceTransaction: Force receive User is not yet in DB {0}", receiverID);
+ return response;
+ }
+
+ bool result = m_moneyDBService.addTransaction(transaction);
+ if (result) {
+ UserInfo user = m_moneyDBService.FetchUserInfo(senderID);
+ if (user!=null) {
+ if (amount>0 || (m_enableAmountZero&&amount==0)) {
+ string snd_message = "";
+ string rcv_message = "";
+
+ if (transaction.Type==(int)TransactionType.Gift) {
+ snd_message = m_BalanceMessageSendGift;
+ rcv_message = m_BalanceMessageReceiveGift;
+ }
+ else if (transaction.Type==(int)TransactionType.LandSale) {
+ snd_message = m_BalanceMessageLandSale;
+ snd_message = m_BalanceMessageRcvLandSale;
+ }
+ else if (transaction.Type==(int)TransactionType.PayObject) {
+ snd_message = m_BalanceMessageBuyObject;
+ rcv_message = m_BalanceMessageSellObject;
+ }
+ else if (transaction.Type==(int)TransactionType.ObjectPays) { // ObjectGiveMoney
+ rcv_message = m_BalanceMessageGetMoney;
+ }
+
+ responseData["success"] = NotifyTransfer(transactionUUID, snd_message, rcv_message, objectName);
+ }
+ else if (amount==0) {
+ responseData["success"] = true; // No messages for L$0 object. by Fumi.Iseki
+ }
+ return response;
+ }
+ }
+ else { // add transaction failed
+ m_log.ErrorFormat("[MONEY RPC]: handleForceTransaction: Add force transaction for user {0} failed.", senderID);
+ }
+ return response;
+ }
+ catch (Exception e) {
+ m_log.Error("[MONEY RPC]: handleForceTransaction: Exception occurred while adding force transaction: " + e.ToString());
+ }
+ return response;
+ }
+
+
+ //
+ // added by Fumi.Iseki
+ //
+ ///
+ /// handle scripted sending money transaction.
+ ///
+ ///
+ ///
+ public XmlRpcResponse handleScriptTransaction(XmlRpcRequest request, IPEndPoint remoteClient)
+ {
+ //m_log.InfoFormat("[MONEY RPC]: handleScriptTransaction:");
+
+ GetSSLCommonName(request);
+
+ Hashtable requestData = (Hashtable)request.Params[0];
+ XmlRpcResponse response = new XmlRpcResponse();
+ Hashtable responseData = new Hashtable();
+ response.Value = responseData;
+
+ int amount = 0;
+ int transactionType = 0;
+ string senderID = UUID.Zero.ToString();
+ string receiverID = UUID.Zero.ToString();
+ string clientIP = remoteClient.Address.ToString();
+ string secretCode = string.Empty;
+ string description = "Scripted Send Money from/to Avatar on";
+
+ responseData["success"] = false;
+ UUID transactionUUID = UUID.Random();
+
+ if (!m_scriptSendMoney || m_scriptAccessKey=="") {
+ m_log.Error("[MONEY RPC]: handleScriptTransaction: Not allowed send money to avatar!!");
+ m_log.Error("[MONEY RPC]: handleScriptTransaction: Set enableScriptSendMoney and MoneyScriptAccessKey at [MoneyServer] in MoneyServer.ini");
+ responseData["message"] = "not allowed set money to avatar!";
+ return response;
+ }
+
+ if (requestData.ContainsKey("senderID")) senderID = (string)requestData["senderID"];
+ if (requestData.ContainsKey("receiverID")) receiverID = (string)requestData["receiverID"];
+ if (requestData.ContainsKey("amount")) amount = Convert.ToInt32(requestData["amount"]);
+ if (requestData.ContainsKey("transactionType")) transactionType = Convert.ToInt32(requestData["transactionType"]);
+ if (requestData.ContainsKey("description")) description = (string)requestData["description"];
+ if (requestData.ContainsKey("secretAccessCode")) secretCode = (string)requestData["secretAccessCode"];
+
+ MD5 md5 = MD5.Create();
+ byte[] code = md5.ComputeHash(ASCIIEncoding.Default.GetBytes(m_scriptAccessKey + "_" + clientIP));
+ string hash = BitConverter.ToString(code).ToLower().Replace("-", "");
+ code = md5.ComputeHash(ASCIIEncoding.Default.GetBytes(hash + "_" + m_scriptIPaddress));
+ hash = BitConverter.ToString(code).ToLower().Replace("-", "");
+
+ if (secretCode.ToLower()!=hash) {
+ m_log.Error("[MONEY RPC]: handleScriptTransaction: Not allowed send money to avatar!!");
+ m_log.Error("[MONEY RPC]: handleScriptTransaction: Not match Script Access Key.");
+ responseData["message"] = "not allowed send money to avatar! not match Script Key";
+ return response;
+ }
+
+ m_log.InfoFormat("[MONEY RPC]: handleScriptTransaction: Send money from {0} to {1}", senderID, receiverID);
+ int time = (int)((DateTime.UtcNow.Ticks - TicksToEpoch) / 10000000);
+
+ try {
+ TransactionData transaction = new TransactionData();
+ transaction.TransUUID = transactionUUID;
+ transaction.Sender = senderID;
+ transaction.Receiver = receiverID;
+ transaction.Amount = amount;
+ transaction.ObjectUUID = UUID.Zero.ToString();
+ transaction.RegionHandle = "0";
+ transaction.Type = transactionType;
+ transaction.Time = time;
+ transaction.SecureCode = UUID.Random().ToString();
+ transaction.Status = (int)Status.PENDING_STATUS;
+ transaction.CommonName = GetSSLCommonName();
+ transaction.Description = description + " " + DateTime.UtcNow.ToString();
+
+ UserInfo senderInfo = null;
+ UserInfo receiverInfo = null;
+ if (transaction.Sender !=UUID.Zero.ToString()) senderInfo = m_moneyDBService.FetchUserInfo(transaction.Sender);
+ if (transaction.Receiver!=UUID.Zero.ToString()) receiverInfo = m_moneyDBService.FetchUserInfo(transaction.Receiver);
+
+ if (senderInfo==null && receiverInfo==null) {
+ m_log.ErrorFormat("[MONEY RPC]: handleScriptTransaction: Sender and Receiver are not yet in DB, or both of them are System: {0}, {1}",
+ transaction.Sender, transaction.Receiver);
+ return response;
+ }
+
+ bool result = m_moneyDBService.addTransaction(transaction);
+ if (result) {
+ if (amount>0 || (m_enableAmountZero&&amount==0)) {
+ if (m_moneyDBService.DoTransfer(transactionUUID)) {
+ transaction = m_moneyDBService.FetchTransaction(transactionUUID);
+ if (transaction!=null && transaction.Status==(int)Status.SUCCESS_STATUS) {
+ m_log.InfoFormat("[MONEY RPC]: handleScriptTransaction: ScriptTransaction money finished successfully, now update balance {0}",
+ transactionUUID.ToString());
+ string message = string.Empty;
+ if (senderInfo!=null) {
+ if (receiverInfo==null) message = string.Format(m_BalanceMessageSendMoney, amount, "SYSTEM", "");
+ else message = string.Format(m_BalanceMessageSendMoney, amount, receiverInfo.Avatar, "");
+ UpdateBalance(transaction.Sender, message);
+ m_log.InfoFormat("[MONEY RPC]: handleScriptTransaction: Update balance of {0}. Message = {1}", transaction.Sender, message);
+ }
+ if (receiverInfo!=null) {
+ if (senderInfo==null) message = string.Format(m_BalanceMessageReceiveMoney, amount, "SYSTEM", "");
+ else message = string.Format(m_BalanceMessageReceiveMoney, amount, senderInfo.Avatar, "");
+ UpdateBalance(transaction.Receiver, message);
+ m_log.InfoFormat("[MONEY RPC]: handleScriptTransaction: Update balance of {0}. Message = {1}", transaction.Receiver, message);
+ }
+
+
+ responseData["success"] = true;
+ }
+ }
+ }
+ else if (amount==0) {
+ responseData["success"] = true; // No messages for L$0 add
+ }
+ return response;
+ }
+ else { // add transaction failed
+ m_log.ErrorFormat("[MONEY RPC]: handleScriptTransaction: Add force transaction for user {0} failed.", transaction.Sender);
+ }
+ return response;
+ }
+ catch (Exception e) {
+ m_log.Error("[MONEY RPC]: handleScriptTransaction: Exception occurred while adding money transaction: " + e.ToString());
+ }
+ return response;
+ }
+
+
+ //
+ // added by Fumi.Iseki
+ //
+ ///
+ /// handle adding money transaction.
+ ///
+ ///
+ ///
+ public XmlRpcResponse handleAddBankerMoney(XmlRpcRequest request, IPEndPoint remoteClient)
+ {
+ //m_log.InfoFormat("[MONEY RPC]: handleAddBankerMoney:");
+
+ GetSSLCommonName(request);
+
+ Hashtable requestData = (Hashtable)request.Params[0];
+ XmlRpcResponse response = new XmlRpcResponse();
+ Hashtable responseData = new Hashtable();
+ response.Value = responseData;
+
+ int amount = 0;
+ int transactionType = 0;
+ string senderID = UUID.Zero.ToString();
+ string bankerID = string.Empty;
+ string regionHandle = "0";
+ string regionUUID = UUID.Zero.ToString();
+ string description = "Add Money to Avatar on";
+
+ responseData["success"] = false;
+ UUID transactionUUID = UUID.Random();
+
+ if (requestData.ContainsKey("bankerID")) bankerID = (string)requestData["bankerID"];
+ if (requestData.ContainsKey("amount")) amount = Convert.ToInt32(requestData["amount"]);
+ if (requestData.ContainsKey("regionHandle")) regionHandle = (string)requestData["regionHandle"];
+ if (requestData.ContainsKey("regionUUID")) regionUUID = (string)requestData["regionUUID"];
+ if (requestData.ContainsKey("transactionType")) transactionType = Convert.ToInt32(requestData["transactionType"]);
+ if (requestData.ContainsKey("description")) description = (string)requestData["description"];
+
+ // Check Banker Avatar
+ if (m_bankerAvatar!=UUID.Zero.ToString() && m_bankerAvatar!=bankerID) {
+ m_log.Error("[MONEY RPC]: handleAddBankerMoney: Not allowed add money to avatar!!");
+ m_log.Error("[MONEY RPC]: handleAddBankerMoney: Set BankerAvatar at [MoneyServer] in MoneyServer.ini");
+ responseData["message"] = "not allowed add money to avatar!";
+ responseData["banker"] = false;
+ return response;
+ }
+ responseData["banker"] = true;
+
+ m_log.InfoFormat("[MONEY RPC]: handleAddBankerMoney: Add money to avatar {0}", bankerID);
+ int time = (int)((DateTime.UtcNow.Ticks - TicksToEpoch) / 10000000);
+
+ try {
+ TransactionData transaction = new TransactionData();
+ transaction.TransUUID = transactionUUID;
+ transaction.Sender = senderID;
+ transaction.Receiver = bankerID;
+ transaction.Amount = amount;
+ transaction.ObjectUUID = UUID.Zero.ToString();
+ transaction.RegionHandle = regionHandle;
+ transaction.RegionUUID = regionUUID;
+ transaction.Type = transactionType;
+ transaction.Time = time;
+ transaction.SecureCode = UUID.Random().ToString();
+ transaction.Status = (int)Status.PENDING_STATUS;
+ transaction.CommonName = GetSSLCommonName();
+ transaction.Description = description + " " + DateTime.UtcNow.ToString();
+
+ UserInfo rcvr = m_moneyDBService.FetchUserInfo(bankerID);
+ if (rcvr==null) {
+ m_log.ErrorFormat("[MONEY RPC]: handleAddBankerMoney: Avatar is not yet in DB {0}", bankerID);
+ return response;
+ }
+
+ bool result = m_moneyDBService.addTransaction(transaction);
+ if (result) {
+ if (amount>0 || (m_enableAmountZero&&amount==0)) {
+ if (m_moneyDBService.DoAddMoney(transactionUUID)) {
+ transaction = m_moneyDBService.FetchTransaction(transactionUUID);
+ if (transaction!=null && transaction.Status==(int)Status.SUCCESS_STATUS) {
+ m_log.InfoFormat("[MONEY RPC]: handleAddBankerMoney: Adding money finished successfully, now update balance: {0}",
+ transactionUUID.ToString());
+ string message = string.Format(m_BalanceMessageBuyMoney, amount, "SYSTEM", "");
+ UpdateBalance(transaction.Receiver, message);
+ responseData["success"] = true;
+ }
+ }
+ }
+ else if (amount==0) {
+ responseData["success"] = true; // No messages for L$0 add
+ }
+ return response;
+ }
+ else { // add transaction failed
+ m_log.ErrorFormat("[MONEY RPC]: handleAddBankerMoney: Add force transaction for user {0} failed.", senderID);
+ }
+ return response;
+ }
+ catch (Exception e) {
+ m_log.Error("[MONEY RPC]: handleAddBankerMoney: Exception occurred while adding money transaction: " + e.ToString());
+ }
+ return response;
+ }
+
+
+ //
+ // added by Fumi.Iseki
+ //
+ ///
+ /// handle pay charge transaction. no check receiver information.
+ ///
+ ///
+ ///
+ public XmlRpcResponse handlePayMoneyCharge(XmlRpcRequest request, IPEndPoint remoteClient)
+ {
+ //m_log.InfoFormat("[MONEY RPC]: handlePayMoneyCharge:");
+
+ GetSSLCommonName(request);
+
+ Hashtable requestData = (Hashtable)request.Params[0];
+ XmlRpcResponse response = new XmlRpcResponse();
+ Hashtable responseData = new Hashtable();
+ response.Value = responseData;
+
+ int amount = 0;
+ int transactionType = 0;
+ string senderID = string.Empty;
+ string receiverID = UUID.Zero.ToString();
+ string senderSessionID = string.Empty;
+ string senderSecureSessionID = string.Empty;
+ string objectID = UUID.Zero.ToString();
+ string objectName = string.Empty;
+ string regionHandle = string.Empty;
+ string regionUUID = string.Empty;
+ string description = "Pay Charge on";
+
+ responseData["success"] = false;
+ UUID transactionUUID = UUID.Random();
+
+ if (requestData.ContainsKey("senderID")) senderID = (string)requestData["senderID"];
+ if (requestData.ContainsKey("senderSessionID")) senderSessionID = (string)requestData["senderSessionID"];
+ if (requestData.ContainsKey("senderSecureSessionID")) senderSecureSessionID = (string)requestData["senderSecureSessionID"];
+ if (requestData.ContainsKey("amount")) amount = Convert.ToInt32(requestData["amount"]);
+ if (requestData.ContainsKey("regionHandle")) regionHandle = (string)requestData["regionHandle"];
+ if (requestData.ContainsKey("regionUUID")) regionUUID = (string)requestData["regionUUID"];
+ if (requestData.ContainsKey("transactionType")) transactionType = Convert.ToInt32(requestData["transactionType"]);
+ if (requestData.ContainsKey("description")) description = (string)requestData["description"];
+
+ if (m_sessionDic.ContainsKey(senderID) && m_secureSessionDic.ContainsKey(senderID)) {
+ if (m_sessionDic[senderID]==senderSessionID && m_secureSessionDic[senderID]==senderSecureSessionID) {
+ m_log.InfoFormat("[MONEY RPC]: handlePayMoneyCharge: Pay from {0}", senderID);
+ int time = (int)((DateTime.UtcNow.Ticks - TicksToEpoch) / 10000000);
+ try {
+ TransactionData transaction = new TransactionData();
+ transaction.TransUUID = transactionUUID;
+ transaction.Sender = senderID;
+ transaction.Receiver = receiverID;
+ transaction.Amount = amount;
+ transaction.ObjectUUID = objectID;
+ transaction.ObjectName = objectName;
+ transaction.RegionHandle = regionHandle;
+ transaction.RegionUUID = regionUUID;
+ transaction.Type = transactionType;
+ transaction.Time = time;
+ transaction.SecureCode = UUID.Random().ToString();
+ transaction.Status = (int)Status.PENDING_STATUS;
+ transaction.CommonName = GetSSLCommonName();
+ transaction.Description = description + " " + DateTime.UtcNow.ToString();
+
+ bool result = m_moneyDBService.addTransaction(transaction);
+ if (result) {
+ UserInfo user = m_moneyDBService.FetchUserInfo(senderID);
+ if (user!=null) {
+ if (amount>0 || (m_enableAmountZero&&amount==0)) {
+ string message = string.Format(m_BalanceMessagePayCharge, amount, "SYSTEM", "");
+ responseData["success"] = NotifyTransfer(transactionUUID, message, "", "");
+ }
+ else if (amount==0) {
+ responseData["success"] = true; // No messages for L$0 object. by Fumi.Iseki
+ }
+ return response;
+ }
+ }
+ else { // add transaction failed
+ m_log.ErrorFormat("[MONEY RPC]: handlePayMoneyCharge: Pay money transaction for user {0} failed.", senderID);
+ }
+ return response;
+ }
+ catch (Exception e) {
+ m_log.Error("[MONEY RPC]: handlePayMoneyCharge: Exception occurred while pay money transaction: " + e.ToString());
+ }
+ return response;
+ }
+ }
+
+ m_log.Error("[MONEY RPC]: handlePayMoneyCharge: Session authentication failure for sender " + senderID);
+ responseData["message"] = "Session check failure, please re-login later!";
+ return response;
+ }
+
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ //
+ // added by Fumi.Iseki
+ //
+ ///
+ /// Continue transaction with no confirm.
+ ///
+ ///
+ ///
+ public bool NotifyTransfer(UUID transactionUUID, string msg2sender, string msg2receiver, string objectName)
+ {
+ //m_log.InfoFormat("[MONEY RPC]: NotifyTransfer: User has accepted the transaction, now continue with the transaction");
+
+ try {
+ if (m_moneyDBService.DoTransfer(transactionUUID)) {
+ TransactionData transaction = m_moneyDBService.FetchTransaction(transactionUUID);
+ if (transaction!=null && transaction.Status==(int)Status.SUCCESS_STATUS) {
+ m_log.InfoFormat("[MONEY RPC]: NotifyTransfer: Transaction Type = {0}", transaction.Type);
+ m_log.InfoFormat("[MONEY RPC]: NotifyTransfer: Payment finished successfully, now update balance {0}", transactionUUID.ToString());
+
+ bool updateSender = true;
+ bool updateReceiv = true;
+ if (transaction.Sender==transaction.Receiver) updateSender = false;
+ //if (transaction.Type==(int)TransactionType.UploadCharge) return true;
+ if (transaction.Type==(int)TransactionType.UploadCharge) updateReceiv = false;
+
+ if (updateSender) {
+ UserInfo receiverInfo = m_moneyDBService.FetchUserInfo(transaction.Receiver);
+ string receiverName = "unknown user";
+ if (receiverInfo!=null) receiverName = receiverInfo.Avatar;
+ string snd_message = string.Format(msg2sender, transaction.Amount, receiverName, objectName);
+ UpdateBalance(transaction.Sender, snd_message);
+ }
+ if (updateReceiv) {
+ UserInfo senderInfo = m_moneyDBService.FetchUserInfo(transaction.Sender);
+ string senderName = "unknown user";
+ if (senderInfo!=null) senderName = senderInfo.Avatar;
+ string rcv_message = string.Format(msg2receiver, transaction.Amount, senderName, objectName);
+ UpdateBalance(transaction.Receiver, rcv_message);
+ }
+
+ // Notify to sender
+ if (transaction.Type==(int)TransactionType.PayObject) {
+ m_log.InfoFormat("[MONEY RPC]: NotifyTransfer: Now notify opensim to give object to customer {0} ", transaction.Sender);
+ Hashtable requestTable = new Hashtable();
+ requestTable["clientUUID"] = transaction.Sender;
+ requestTable["receiverUUID"] = transaction.Receiver;
+
+ if(m_sessionDic.ContainsKey(transaction.Sender)&&m_secureSessionDic.ContainsKey(transaction.Sender)) {
+ requestTable["clientSessionID"] = m_sessionDic[transaction.Sender];
+ requestTable["clientSecureSessionID"] = m_secureSessionDic[transaction.Sender];
+ }
+ else {
+ requestTable["clientSessionID"] = UUID.Zero.ToString();
+ requestTable["clientSecureSessionID"] = UUID.Zero.ToString();
+ }
+ requestTable["transactionType"] = transaction.Type;
+ requestTable["amount"] = transaction.Amount;
+ requestTable["objectID"] = transaction.ObjectUUID;
+ requestTable["objectName"] = transaction.ObjectName;
+ requestTable["regionHandle"] = transaction.RegionHandle;
+
+ UserInfo user = m_moneyDBService.FetchUserInfo(transaction.Sender);
+ if (user!=null) {
+ Hashtable responseTable = genericCurrencyXMLRPCRequest(requestTable, "OnMoneyTransfered", user.SimIP);
+
+ if (responseTable!=null && responseTable.ContainsKey("success")) {
+ //User not online or failed to get object ?
+ if (!(bool)responseTable["success"]) {
+ m_log.ErrorFormat("[MONEY RPC]: NotifyTransfer: User {0} can't get the object, rolling back.", transaction.Sender);
+ if (RollBackTransaction(transaction)) {
+ m_log.ErrorFormat("[MONEY RPC]: NotifyTransfer: Transaction {0} failed but roll back succeeded.", transactionUUID.ToString());
+ }
+ else {
+ m_log.ErrorFormat("[MONEY RPC]: NotifyTransfer: Transaction {0} failed and roll back failed as well.",
+ transactionUUID.ToString());
+ }
+ }
+ else {
+ m_log.InfoFormat("[MONEY RPC]: NotifyTransfer: Transaction {0} finished successfully.", transactionUUID.ToString());
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ return true;
+ }
+ }
+ m_log.ErrorFormat("[MONEY RPC]: NotifyTransfer: Transaction {0} failed.", transactionUUID.ToString());
+ }
+ catch (Exception e) {
+ m_log.ErrorFormat("[MONEY RPC]: NotifyTransfer: exception occurred when transaction {0}: {1}", transactionUUID.ToString(), e.ToString());
+ }
+
+ return false;
+ }
+
+
+
+ ///
+ /// Get the user balance.
+ ///
+ ///
+ ///
+ public XmlRpcResponse handleGetBalance(XmlRpcRequest request, IPEndPoint remoteClient)
+ {
+ //m_log.InfoFormat("[MONEY RPC]: handleGetBalance:");
+
+ GetSSLCommonName(request);
+
+ Hashtable requestData = (Hashtable)request.Params[0];
+ XmlRpcResponse response = new XmlRpcResponse();
+ Hashtable responseData = new Hashtable();
+ response.Value = responseData;
+
+ string clientUUID = string.Empty;
+ string sessionID = string.Empty;
+ string secureID = string.Empty;
+ int balance;
+
+ responseData["success"] = false;
+
+ if (requestData.ContainsKey("clientUUID")) clientUUID = (string)requestData["clientUUID"];
+ if (requestData.ContainsKey("clientSessionID")) sessionID = (string)requestData["clientSessionID"];
+ if (requestData.ContainsKey("clientSecureSessionID")) secureID = (string)requestData["clientSecureSessionID"];
+
+ m_log.InfoFormat("[MONEY RPC]: handleGetBalance: Getting balance for user {0}", clientUUID);
+
+ if (m_sessionDic.ContainsKey(clientUUID) && m_secureSessionDic.ContainsKey(clientUUID)) {
+ if (m_sessionDic[clientUUID]==sessionID && m_secureSessionDic[clientUUID]==secureID) {
+ try {
+ balance = m_moneyDBService.getBalance(clientUUID);
+ if (balance==-1) // User not found
+ {
+ responseData["description"] = "user not found";
+ responseData["clientBalance"] = 0;
+ }
+ else if (balance >= 0) {
+ responseData["success"] = true;
+ responseData["clientBalance"] = balance;
+ }
+
+ return response;
+ }
+ catch (Exception e) {
+ m_log.ErrorFormat("[MONEY RPC]: handleGetBalance: Can't get balance for user {0}, Exception {1}", clientUUID, e.ToString());
+ }
+ return response;
+ }
+ }
+
+ m_log.Error("[MONEY RPC]: handleGetBalance: Session authentication failed when getting balance for user " + clientUUID);
+ responseData["description"] = "Session check failure, please re-login";
+ return response;
+ }
+
+
+ ///
+ /// Generic XMLRPC client abstraction
+ ///
+ /// Hashtable containing parameters to the method
+ /// Method to invoke
+ /// Hashtable with success=>bool and other values
+ private Hashtable genericCurrencyXMLRPCRequest(Hashtable reqParams, string method, string uri)
+ {
+ //m_log.InfoFormat("[MONEY RPC]: genericCurrencyXMLRPCRequest: to {0}", uri);
+
+ if (reqParams.Count<=0 || string.IsNullOrEmpty(method)) return null;
+
+ if (m_checkServerCert) {
+ if (!uri.StartsWith("https://")) {
+ m_log.InfoFormat("[MONEY RPC]: genericCurrencyXMLRPCRequest: CheckServerCert is true, but protocol is not HTTPS. Please check INI file.");
+ //return null;
+ }
+ }
+ else {
+ if (!uri.StartsWith("https://") && !uri.StartsWith("http://")) {
+ m_log.ErrorFormat("[MONEY RPC]: genericCurrencyXMLRPCRequest: Invalid Region Server URL: {0}", uri);
+ return null;
+ }
+ }
+
+ ArrayList arrayParams = new ArrayList();
+ arrayParams.Add(reqParams);
+ XmlRpcResponse moneyServResp = null;
+ try {
+ //XmlRpcRequest moneyModuleReq = new XmlRpcRequest(method, arrayParams);
+ //moneyServResp = moneyModuleReq.Send(uri, MONEYMODULE_REQUEST_TIMEOUT);
+ NSLXmlRpcRequest moneyModuleReq = new NSLXmlRpcRequest(method, arrayParams);
+ moneyServResp = moneyModuleReq.certSend(uri, m_clientCert, m_checkServerCert, MONEYMODULE_REQUEST_TIMEOUT);
+ }
+ catch (Exception ex) {
+ m_log.ErrorFormat("[MONEY RPC]: genericCurrencyXMLRPCRequest: Unable to connect to Region Server {0}", uri);
+ m_log.ErrorFormat("[MONEY RPC]: genericCurrencyXMLRPCRequest: {0}", ex.ToString());
+
+ Hashtable ErrorHash = new Hashtable();
+ ErrorHash["success"] = false;
+ ErrorHash["errorMessage"] = "Failed to perform actions on OpenSim Server";
+ ErrorHash["errorURI"] = "";
+ return ErrorHash;
+ }
+
+ if (moneyServResp==null || moneyServResp.IsFault) {
+ Hashtable ErrorHash = new Hashtable();
+ ErrorHash["success"] = false;
+ ErrorHash["errorMessage"] = "Failed to perform actions on OpenSim Server";
+ ErrorHash["errorURI"] = "";
+ return ErrorHash;
+ }
+
+ Hashtable moneyRespData = (Hashtable)moneyServResp.Value;
+ return moneyRespData;
+ }
+
+
+ ///
+ /// Update the client balance.We don't care about the result.
+ ///
+ ///
+ private void UpdateBalance(string userID, string message)
+ {
+ //m_log.InfoFormat("[MONEY RPC]: UpdateBalance: ID = {0}, Message = {1}", userID, message);
+
+ string sessionID = string.Empty;
+ string secureID = string.Empty;
+
+ if (m_sessionDic.ContainsKey(userID) && m_secureSessionDic.ContainsKey(userID)) {
+ sessionID = m_sessionDic[userID];
+ secureID = m_secureSessionDic[userID];
+
+ Hashtable requestTable = new Hashtable();
+ requestTable["clientUUID"] = userID;
+ requestTable["clientSessionID"] = sessionID;
+ requestTable["clientSecureSessionID"] = secureID;
+ requestTable["Balance"] = m_moneyDBService.getBalance(userID);
+ if (message!="") requestTable["Message"] = message;
+
+ UserInfo user = m_moneyDBService.FetchUserInfo(userID);
+ if (user!=null) {
+ genericCurrencyXMLRPCRequest(requestTable, "UpdateBalance", user.SimIP);
+ m_log.InfoFormat("[MONEY RPC]: UpdateBalance: Sended UpdateBalance Request to {0}", user.SimIP.ToString());
+ }
+ }
+ }
+
+
+ ///
+ /// RollBack the transaction if user failed to get the object paid
+ ///
+ ///
+ ///
+ protected bool RollBackTransaction(TransactionData transaction)
+ {
+ //m_log.InfoFormat("[MONEY RPC]: RollBackTransaction:");
+
+ if(m_moneyDBService.withdrawMoney(transaction.TransUUID, transaction.Receiver, transaction.Amount)) {
+ if(m_moneyDBService.giveMoney(transaction.TransUUID, transaction.Sender, transaction.Amount)) {
+ m_log.InfoFormat("[MONEY RPC]: RollBackTransaction: Transaction {0} is successfully.", transaction.TransUUID.ToString());
+ m_moneyDBService.updateTransactionStatus(transaction.TransUUID, (int)Status.FAILED_STATUS,
+ "The buyer failed to get the object, roll back the transaction");
+ UserInfo senderInfo = m_moneyDBService.FetchUserInfo(transaction.Sender);
+ UserInfo receiverInfo = m_moneyDBService.FetchUserInfo(transaction.Receiver);
+ string senderName = "unknown user";
+ string receiverName = "unknown user";
+ if (senderInfo!=null) senderName = senderInfo.Avatar;
+ if (receiverInfo!=null) receiverName = receiverInfo.Avatar;
+
+ string snd_message = string.Format(m_BalanceMessageRollBack, transaction.Amount, receiverName, transaction.ObjectName);
+ string rcv_message = string.Format(m_BalanceMessageRollBack, transaction.Amount, senderName, transaction.ObjectName);
+
+ if (transaction.Sender!=transaction.Receiver) UpdateBalance(transaction.Sender, snd_message);
+ UpdateBalance(transaction.Receiver, rcv_message);
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ //
+ public XmlRpcResponse handleCancelTransfer(XmlRpcRequest request, IPEndPoint remoteClient)
+ {
+ //m_log.InfoFormat("[MONEY RPC]: handleCancelTransfer:");
+
+ GetSSLCommonName(request);
+
+ Hashtable requestData = (Hashtable)request.Params[0];
+ XmlRpcResponse response = new XmlRpcResponse();
+ Hashtable responseData = new Hashtable();
+ response.Value = responseData;
+
+ string secureCode = string.Empty;
+ string transactionID = string.Empty;
+ UUID transactionUUID = UUID.Zero;
+
+ responseData["success"] = false;
+
+ if (requestData.ContainsKey("secureCode")) secureCode = (string)requestData["secureCode"];
+ if (requestData.ContainsKey("transactionID")) {
+ transactionID = (string)requestData["transactionID"];
+ UUID.TryParse(transactionID, out transactionUUID);
+ }
+
+ if (string.IsNullOrEmpty(secureCode) || string.IsNullOrEmpty(transactionID)) {
+ m_log.Error("[MONEY RPC]: handleCancelTransfer: secureCode and/or transactionID are empty.");
+ return response;
+ }
+
+ TransactionData transaction = m_moneyDBService.FetchTransaction(transactionUUID);
+ UserInfo user = m_moneyDBService.FetchUserInfo(transaction.Sender);
+
+ try {
+ m_log.InfoFormat("[MONEY RPC]: handleCancelTransfer: User {0} wanted to cancel the transaction.", user.Avatar);
+ if (m_moneyDBService.ValidateTransfer(secureCode, transactionUUID)) {
+ m_log.InfoFormat("[MONEY RPC]: handleCancelTransfer: User {0} has canceled the transaction {1}", user.Avatar, transactionID);
+ m_moneyDBService.updateTransactionStatus(transactionUUID, (int)Status.FAILED_STATUS,
+ "User canceled the transaction on " + DateTime.UtcNow.ToString());
+ responseData["success"] = true;
+ }
+ }
+ catch (Exception e) {
+ m_log.ErrorFormat("[MONEY RPC]: handleCancelTransfer: Exception occurred when transaction {0}: {1}", transactionID, e.ToString());
+ }
+ return response;
+ }
+
+
+ //
+ public XmlRpcResponse handleGetTransaction(XmlRpcRequest request, IPEndPoint remoteClient)
+ {
+ //m_log.InfoFormat("[MONEY RPC]: handleGetTransaction:");
+
+ GetSSLCommonName(request);
+
+ Hashtable requestData = (Hashtable)request.Params[0];
+ XmlRpcResponse response = new XmlRpcResponse();
+ Hashtable responseData = new Hashtable();
+ response.Value = responseData;
+
+ string clientID = string.Empty;
+ string sessionID = string.Empty;
+ string secureID = string.Empty;
+ string transactionID = string.Empty;
+ UUID transactionUUID = UUID.Zero;
+
+ responseData["success"] = false;
+
+ if (requestData.ContainsKey("clientUUID")) clientID = (string)requestData["clientUUID"];
+ if (requestData.ContainsKey("clientSessionID")) sessionID = (string)requestData["clientSessionID"];
+ if (requestData.ContainsKey("clientSecureSessionID")) secureID = (string)requestData["clientSecureSessionID"];
+
+ if (requestData.ContainsKey("transactionID")) {
+ transactionID = (string)requestData["transactionID"];
+ UUID.TryParse(transactionID, out transactionUUID);
+ }
+
+ if (m_sessionDic.ContainsKey(clientID) && m_secureSessionDic.ContainsKey(clientID)) {
+ if (m_sessionDic[clientID]==sessionID && m_secureSessionDic[clientID]==secureID) {
+ //
+ if (string.IsNullOrEmpty(transactionID)) {
+ responseData["description"] = "TransactionID is empty";
+ m_log.Error("[MONEY RPC]: handleGetTransaction: TransactionID is empty.");
+ return response;
+ }
+
+ try {
+ TransactionData transaction = m_moneyDBService.FetchTransaction(transactionUUID);
+ if (transaction!=null) {
+ responseData["success"] = true;
+ responseData["amount"] = transaction.Amount;
+ responseData["time"] = transaction.Time;
+ responseData["type"] = transaction.Type;
+ responseData["sender"] = transaction.Sender.ToString();
+ responseData["receiver"] = transaction.Receiver.ToString();
+ responseData["description"] = transaction.Description;
+ }
+ else {
+ responseData["description"] = "Invalid Transaction UUID";
+ }
+
+ return response;
+ }
+ catch (Exception e) {
+ m_log.ErrorFormat("[MONEY RPC]: handleGetTransaction: {0}", e.ToString());
+ m_log.ErrorFormat("[MONEY RPC]: handleGetTransaction: Can't get transaction information for {0}", transactionUUID.ToString());
+ }
+ return response;
+ }
+ }
+
+ responseData["success"] = false;
+ responseData["description"] = "Session check failure, please re-login";
+ return response;
+ }
+
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // In development
+ //
+
+ public XmlRpcResponse handleWebLogin(XmlRpcRequest request, IPEndPoint remoteClient)
+ {
+ //m_log.InfoFormat("[MONEY RPC]: handleWebLogin:");
+
+ GetSSLCommonName(request);
+
+ Hashtable requestData = (Hashtable)request.Params[0];
+ XmlRpcResponse response = new XmlRpcResponse();
+ Hashtable responseData = new Hashtable();
+ response.Value = responseData;
+
+ string userID = string.Empty;
+ string webSessionID = string.Empty;
+
+ responseData["success"] = false;
+
+ if (requestData.ContainsKey("userID")) userID = (string)requestData["userID"];
+ if (requestData.ContainsKey("sessionID")) webSessionID = (string)requestData["sessionID"];
+
+ if (string.IsNullOrEmpty(userID) || string.IsNullOrEmpty(webSessionID)) {
+ responseData["errorMessage"] = "userID or sessionID can`t be empty, login failed!";
+ return response;
+ }
+
+ //Update the web session dictionary
+ lock (m_webSessionDic) {
+ if (!m_webSessionDic.ContainsKey(userID)) {
+ m_webSessionDic.Add(userID, webSessionID);
+ }
+ else m_webSessionDic[userID] = webSessionID;
+ }
+
+ m_log.InfoFormat("[MONEY RPC]: handleWebLogin: User {0} has logged in from web.", userID);
+ responseData["success"] = true;
+ return response;
+ }
+
+
+ //
+ public XmlRpcResponse handleWebLogout(XmlRpcRequest request, IPEndPoint remoteClient)
+ {
+ //m_log.InfoFormat("[MONEY RPC]: handleWebLogout:");
+
+ GetSSLCommonName(request);
+
+ Hashtable requestData = (Hashtable)request.Params[0];
+ XmlRpcResponse response = new XmlRpcResponse();
+ Hashtable responseData = new Hashtable();
+ response.Value = responseData;
+
+ string userID = string.Empty;
+ string webSessionID = string.Empty;
+
+ responseData["success"] = false;
+
+ if (requestData.ContainsKey("userID")) userID = (string)requestData["userID"];
+ if (requestData.ContainsKey("sessionID")) webSessionID = (string)requestData["sessionID"];
+
+ if (string.IsNullOrEmpty(userID) || string.IsNullOrEmpty(webSessionID)) {
+ responseData["errorMessage"] = "userID or sessionID can`t be empty, log out failed!";
+ return response;
+ }
+
+ //Update the web session dictionary
+ lock (m_webSessionDic) {
+ if (m_webSessionDic.ContainsKey(userID)) {
+ m_webSessionDic.Remove(userID);
+ }
+ }
+
+ m_log.InfoFormat("[MONEY RPC]: handleWebLogout: User {0} has logged out from web.", userID);
+ responseData["success"] = true;
+ return response;
+ }
+
+
+ ///
+ /// Get balance method for web pages.
+ ///
+ ///
+ ///
+ public XmlRpcResponse handleWebGetBalance(XmlRpcRequest request, IPEndPoint remoteClient)
+ {
+ //m_log.InfoFormat("[MONEY RPC]: handleWebGetBalance:");
+
+ GetSSLCommonName(request);
+
+ Hashtable requestData = (Hashtable)request.Params[0];
+ XmlRpcResponse response = new XmlRpcResponse();
+ Hashtable responseData = new Hashtable();
+ response.Value = responseData;
+
+ string userID = string.Empty;
+ string webSessionID = string.Empty;
+ int balance = 0;
+
+ responseData["success"] = false;
+
+ if (requestData.ContainsKey("userID")) userID = (string)requestData["userID"];
+ if (requestData.ContainsKey("sessionID")) webSessionID = (string)requestData["sessionID"];
+
+ m_log.InfoFormat("[MONEY RPC]: handleWebGetBalance: Getting balance for user {0}", userID);
+
+ //perform session check
+ if (m_webSessionDic.ContainsKey(userID)) {
+ if (m_webSessionDic[userID]==webSessionID) {
+ try {
+ balance = m_moneyDBService.getBalance(userID);
+ UserInfo user = m_moneyDBService.FetchUserInfo(userID);
+ if (user!=null) {
+ responseData["userName"] = user.Avatar;
+ }
+ else {
+ responseData["userName"] = "unknown user";
+ }
+ //
+ // User not found
+ if (balance==-1) {
+ responseData["errorMessage"] = "User not found";
+ responseData["balance"] = 0;
+ }
+ else if (balance >= 0) {
+ responseData["success"] = true;
+ responseData["balance"] = balance;
+ }
+ return response;
+ }
+ catch (Exception e) {
+ m_log.ErrorFormat("[MONEY RPC]: handleWebGetBalance: Can't get balance for user {0}, Exception {1}", userID, e.ToString());
+ responseData["errorMessage"] = "Exception occurred when getting balance";
+ return response;
+ }
+ }
+ }
+
+ m_log.Error("[MONEY RPC]: handleWebLogout: Session authentication failed when getting balance for user " + userID);
+ responseData["errorMessage"] = "Session check failure, please re-login";
+ return response;
+ }
+
+
+ ///
+ /// Get transaction for web pages
+ ///
+ ///
+ ///
+ public XmlRpcResponse handleWebGetTransaction(XmlRpcRequest request, IPEndPoint remoteClient)
+ {
+ //m_log.InfoFormat("[MONEY RPC]: handleWebGetTransaction:");
+
+ GetSSLCommonName(request);
+
+ Hashtable requestData = (Hashtable)request.Params[0];
+ XmlRpcResponse response = new XmlRpcResponse();
+ Hashtable responseData = new Hashtable();
+ response.Value = responseData;
+
+ string userID = string.Empty;
+ string webSessionID = string.Empty;
+ int lastIndex = -1;
+ int startTime = 0;
+ int endTime = 0;
+
+ responseData["success"] = false;
+
+ if (requestData.ContainsKey("userID")) userID = (string)requestData["userID"];
+ if (requestData.ContainsKey("sessionID")) webSessionID = (string)requestData["sessionID"];
+ if (requestData.ContainsKey("startTime")) startTime = (int)requestData["startTime"];
+ if (requestData.ContainsKey("endTime")) endTime = (int)requestData["endTime"];
+ if (requestData.ContainsKey("lastIndex")) lastIndex = (int)requestData["lastIndex"];
+
+ if (m_webSessionDic.ContainsKey(userID)) {
+ if (m_webSessionDic[userID]==webSessionID) {
+ try {
+ int total = m_moneyDBService.getTransactionNum(userID, startTime, endTime);
+ TransactionData tran = null;
+ m_log.InfoFormat("[MONEY RPC]: handleWebGetTransaction: Getting transation[{0}] for user {1}", lastIndex + 1, userID);
+ if (total > lastIndex + 2) {
+ responseData["isEnd"] = false;
+ }
+ else {
+ responseData["isEnd"] = true;
+ }
+
+ tran = m_moneyDBService.FetchTransaction(userID, startTime, endTime, lastIndex);
+ if (tran!=null) {
+ UserInfo senderInfo = m_moneyDBService.FetchUserInfo(tran.Sender);
+ UserInfo receiverInfo = m_moneyDBService.FetchUserInfo(tran.Receiver);
+ if (senderInfo!=null && receiverInfo!=null) {
+ responseData["senderName"] = senderInfo.Avatar;
+ responseData["receiverName"] = receiverInfo.Avatar;
+ }
+ else {
+ responseData["senderName"] = "unknown user";
+ responseData["receiverName"] = "unknown user";
+ }
+ responseData["success"] = true;
+ responseData["transactionIndex"] = lastIndex + 1;
+ responseData["transactionUUID"] = tran.TransUUID.ToString();
+ responseData["senderID"] = tran.Sender;
+ responseData["receiverID"] = tran.Receiver;
+ responseData["amount"] = tran.Amount;
+ responseData["type"] = tran.Type;
+ responseData["time"] = tran.Time;
+ responseData["status"] = tran.Status;
+ responseData["description"] = tran.Description;
+ }
+ else {
+ responseData["errorMessage"] = string.Format("Unable to fetch transaction data with the index {0}", lastIndex + 1);
+ }
+ return response;
+ }
+ catch (Exception e) {
+ m_log.ErrorFormat("[MONEY RPC]: handleWebGetTransaction: Can't get transaction for user {0}, Exception {1}", userID, e.ToString());
+ responseData["errorMessage"] = "Exception occurred when getting transaction";
+ return response;
+ }
+ }
+ }
+
+ m_log.Error("[MONEY RPC]: handleWebGetTransaction: Session authentication failed when getting transaction for user " + userID);
+ responseData["errorMessage"] = "Session check failure, please re-login";
+ return response;
+ }
+
+
+ ///
+ /// Get total number of transactions for web pages.
+ ///
+ ///
+ ///
+ public XmlRpcResponse handleWebGetTransactionNum(XmlRpcRequest request, IPEndPoint remoteClient)
+ {
+ //m_log.InfoFormat("[MONEY RPC]: handleWebGetTransactionNum:");
+
+ GetSSLCommonName(request);
+
+ Hashtable requestData = (Hashtable)request.Params[0];
+ XmlRpcResponse response = new XmlRpcResponse();
+ Hashtable responseData = new Hashtable();
+ response.Value = responseData;
+
+ string userID = string.Empty;
+ string webSessionID = string.Empty;
+ int startTime = 0;
+ int endTime = 0;
+
+ responseData["success"] = false;
+
+ if (requestData.ContainsKey("userID")) userID = (string)requestData["userID"];
+ if (requestData.ContainsKey("sessionID")) webSessionID = (string)requestData["sessionID"];
+ if (requestData.ContainsKey("startTime")) startTime = (int)requestData["startTime"];
+ if (requestData.ContainsKey("endTime")) endTime = (int)requestData["endTime"];
+
+ if (m_webSessionDic.ContainsKey(userID)) {
+ if (m_webSessionDic[userID]==webSessionID) {
+ int it = m_moneyDBService.getTransactionNum(userID, startTime, endTime);
+ if (it>=0) {
+ m_log.InfoFormat("[MONEY RPC]: handleWebGetTransactionNum: Get {0} transactions for user {1}", it, userID);
+ responseData["success"] = true;
+ responseData["number"] = it;
+ }
+ return response;
+ }
+ }
+
+ m_log.Error("[MONEY RPC]: handleWebGetTransactionNum: Session authentication failed when getting transaction number for user " + userID);
+ responseData["errorMessage"] = "Session check failure, please re-login";
+ return response;
+ }
+ }
+
+}
+
diff --git a/source/ThirdParty/OpenSim.Grid.MoneyServer/Program.cs b/source/ThirdParty/OpenSim.Grid.MoneyServer/Program.cs
new file mode 100644
index 0000000..3fbd12d
--- /dev/null
+++ b/source/ThirdParty/OpenSim.Grid.MoneyServer/Program.cs
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSim Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using log4net.Config;
+
+namespace OpenSim.Grid.MoneyServer
+{
+ class Program
+ {
+ public static void Main(string[] args)
+ {
+ XmlConfigurator.Configure();
+ MoneyServerBase app = new MoneyServerBase();
+ app.Startup();
+ app.Work();
+ }
+ }
+}
diff --git a/source/ThirdParty/OpenSim.Grid.MoneyServer/Properties/AssemblyInfo.cs b/source/ThirdParty/OpenSim.Grid.MoneyServer/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..407ecee
--- /dev/null
+++ b/source/ThirdParty/OpenSim.Grid.MoneyServer/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("OpenSim.Grid.MoneyServer")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("OpenSim.Grid.MoneyServer")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2009")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("f554c84a-d8c7-41ea-833d-2483cde29e0f")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/source/ThirdParty/OpenSim.Modules.Currency/DTLNSLMoneyModule.cs b/source/ThirdParty/OpenSim.Modules.Currency/DTLNSLMoneyModule.cs
new file mode 100644
index 0000000..344644e
--- /dev/null
+++ b/source/ThirdParty/OpenSim.Modules.Currency/DTLNSLMoneyModule.cs
@@ -0,0 +1,1905 @@
+// * Modified by Fumi.Iseki for Unix/Linix http://www.nsl.tuis.ac.jp
+// *
+// * Copyright (c) Contributors, http://opensimulator.org/, http://www.nsl.tuis.ac.jp/
+// * See CONTRIBUTORS.TXT for a full list of copyright holders.
+// *
+// * Redistribution and use in source and binary forms, with or without
+// * modification, are permitted provided that the following conditions are met:
+// * * Redistributions of source code must retain the above copyright
+// * notice, this list of conditions and the following disclaimer.
+// * * Redistributions in binary form must reproduce the above copyright
+// * notice, this list of conditions and the following disclaimer in the
+// * documentation and/or other materials provided with the distribution.
+// * * Neither the name of the OpenSim Project nor the
+// * names of its contributors may be used to endorse or promote products
+// * derived from this software without specific prior written permission.
+// *
+// * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+// * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+// * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+// * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+// * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// */
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Text;
+using System.Reflection;
+using System.Net;
+using System.Net.Security;
+using System.Security.Cryptography;
+using System.Security.Cryptography.X509Certificates;
+
+using log4net;
+using Nini.Config;
+using Nwc.XmlRpc;
+using Mono.Addins;
+
+using OpenMetaverse;
+
+using OpenSim.Framework;
+using OpenSim.Framework.Servers;
+using OpenSim.Framework.Servers.HttpServer;
+using OpenSim.Services.Interfaces;
+using OpenSim.Region.Framework;
+using OpenSim.Region.Framework.Interfaces;
+using OpenSim.Region.Framework.Scenes;
+
+using OpenSim.Data.MySQL.MySQLMoneyDataWrapper;
+using NSL.Certificate.Tools;
+using NSL.Network.XmlRpc;
+
+
+
+[assembly: Addin("DTLNSLMoneyModule", "1.0")]
+[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]
+
+
+
+namespace OpenSim.Modules.Currency
+{
+ //
+ public enum TransactionType : int
+ {
+ None = 0,
+ // Extend
+ BirthGift = 900,
+ AwardPoints = 901,
+ // One-Time Charges
+ ObjectClaim = 1000,
+ LandClaim = 1001,
+ GroupCreate = 1002,
+ GroupJoin = 1004,
+ TeleportCharge = 1100,
+ UploadCharge = 1101,
+ LandAuction = 1102,
+ ClassifiedCharge = 1103,
+ // Recurrent Charges
+ ObjectTax = 2000,
+ LandTax = 2001,
+ LightTax = 2002,
+ ParcelDirFee = 2003,
+ GroupTax = 2004,
+ ClassifiedRenew = 2005,
+ ScheduledFee = 2900,
+ // Inventory Transactions
+ GiveInventory = 3000,
+ // Transfers Between Users
+ ObjectSale = 5000,
+ Gift = 5001,
+ LandSale = 5002,
+ ReferBonus = 5003,
+ InvntorySale = 5004,
+ RefundPurchase = 5005,
+ LandPassSale = 5006,
+ DwellBonus = 5007,
+ PayObject = 5008,
+ ObjectPays = 5009,
+ BuyMoney = 5010,
+ MoveMoney = 5011,
+ SendMoney = 5012,
+ // Group Transactions
+ GroupLandDeed = 6001,
+ GroupObjectDeed = 6002,
+ GroupLiability = 6003,
+ GroupDividend = 6004,
+ GroupMembershipDues = 6005,
+ // Stipend Credits
+ StipendBasic = 10000
+ }
+
+
+/*
+ // Refer to OpenMetaverse
+ public enum OpenMetaverse.MoneyTransactionType : int
+ {
+ None = 0,
+ FailSimulatorTimeout = 1,
+ FailDataserverTimeout = 2,
+ ObjectClaim = 1000,
+ LandClaim = 1001,
+ GroupCreate = 1002,
+ ObjectPublicClaim = 1003,
+ GroupJoin = 1004,
+ TeleportCharge = 1100,
+ UploadCharge = 1101,
+ LandAuction = 1102,
+ ClassifiedCharge = 1103,
+ ObjectTax = 2000,
+ LandTax = 2001,
+ LightTax = 2002,
+ ParcelDirFee = 2003,
+ GroupTax = 2004,
+ ClassifiedRenew = 2005,
+ GiveInventory = 3000,
+ ObjectSale = 5000,
+ Gift = 5001,
+ LandSale = 5002,
+ ReferBonus = 5003,
+ InventorySale = 5004,
+ RefundPurchase = 5005,
+ LandPassSale = 5006,
+ DwellBonus = 5007,
+ PayObject = 5008,
+ ObjectPays = 5009,
+ GroupLandDeed = 6001,
+ GroupObjectDeed = 6002,
+ GroupLiability = 6003,
+ GroupDividend = 6004,
+ GroupMembershipDues = 6005,
+ ObjectRelease = 8000,
+ LandRelease = 8001,
+ ObjectDelete = 8002,
+ ObjectPublicDecay = 8003,
+ ObjectPublicDelete = 8004,
+ LindenAdjustment = 9000,
+ LindenGrant = 9001,
+ LindenPenalty = 9002,
+ EventFee = 9003,
+ EventPrize = 9004,
+ StipendBasic = 10000,
+ StipendDeveloper = 10001,
+ StipendAlways = 10002,
+ StipendDaily = 10003,
+ StipendRating = 10004,
+ StipendDelta = 10005
+ }
+*/
+
+
+ //
+ [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DTLNSLMoneyModule")]
+ public class DTLNSLMoneyModule : IMoneyModule, ISharedRegionModule
+ {
+ #region Constant numbers and members.
+
+ // Constant memebers
+ private const int MONEYMODULE_REQUEST_TIMEOUT = 10000;
+
+ // Private data members.
+ private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
+ //private bool m_enabled = true;
+ private bool m_sellEnabled = false;
+ private bool m_enable_server = true; // enable Money Server
+
+ private IConfigSource m_config;
+
+ private string m_moneyServURL = string.Empty;
+ public BaseHttpServer HttpServer;
+
+ private string m_certFilename = "";
+ private string m_certPassword = "";
+ private bool m_checkServerCert = false;
+ private string m_cacertFilename = "";
+ private X509Certificate2 m_cert = null;
+
+ private bool m_use_web_settle = false;
+ private string m_settle_url = "";
+ private string m_settle_message = "";
+ private bool m_settle_user = false;
+
+ private int m_hg_avatarClass = (int)AvatarType.HG_AVATAR;
+
+ private NSLCertificateVerify m_certVerify = new NSLCertificateVerify(); // サーバ認証用
+
+
+ ///
+ /// Scene dictionary indexed by Region Handle
+ ///
+ private Dictionary m_sceneList = new Dictionary();
+
+ ///
+ /// To cache the balance data while the money server is not available.
+ ///
+ private Dictionary m_moneyServer = new Dictionary();
+
+ // Events
+ public event ObjectPaid OnObjectPaid;
+
+ // Price
+ private int ObjectCount = 0;
+ private int PriceEnergyUnit = 100;
+ private int PriceObjectClaim = 10;
+ private int PricePublicObjectDecay = 4;
+ private int PricePublicObjectDelete = 4;
+ private int PriceParcelClaim = 1;
+ private float PriceParcelClaimFactor = 1.0f;
+ private int PriceUpload = 0;
+ private int PriceRentLight = 5;
+ private float PriceObjectRent = 1.0f;
+ private float PriceObjectScaleFactor = 10.0f;
+ private int PriceParcelRent = 1;
+ private int PriceGroupCreate = 0;
+ private int TeleportMinPrice = 2;
+ private float TeleportPriceExponent = 2.0f;
+ private float EnergyEfficiency = 1.0f;
+
+ #endregion
+
+
+ //
+ public void Initialise(Scene scene, IConfigSource source)
+ {
+ Initialise(source);
+ if (string.IsNullOrEmpty(m_moneyServURL)) m_enable_server = false;
+ //
+ AddRegion(scene);
+ }
+
+
+ #region ISharedRegionModule interface
+
+ public void Initialise(IConfigSource source)
+ {
+ //m_log.InfoFormat("[MONEY]: Initialise:");
+
+ // Handle the parameters errors.
+ if (source==null) return;
+
+ try {
+ m_config = source;
+
+ // [Economy] section
+ IConfig economyConfig = m_config.Configs["Economy"];
+
+ if (economyConfig.GetString("EconomyModule")!=Name) {
+ //m_enabled = false;
+ m_log.InfoFormat("[MONEY]: The DTL/NSL MoneyModule is disabled");
+ return;
+ }
+ else {
+ m_log.InfoFormat("[MONEY]: The DTL/NSL MoneyModule is enabled");
+ }
+
+ m_sellEnabled = economyConfig.GetBoolean("SellEnabled", m_sellEnabled);
+ m_moneyServURL = economyConfig.GetString("CurrencyServer", m_moneyServURL);
+
+ // クライアント証明書
+ m_certFilename = economyConfig.GetString("ClientCertFilename", m_certFilename);
+ m_certPassword = economyConfig.GetString("ClientCertPassword", m_certPassword);
+ if (m_certFilename!="") {
+ m_cert = new X509Certificate2(m_certFilename, m_certPassword);
+ //m_cert = new X509Certificate2(m_certFilename, m_certPassword, X509KeyStorageFlags.MachineKeySet);
+ m_log.InfoFormat("[MONEY]: Issue Authentication of Client. Cert File is " + m_certFilename);
+ }
+
+ // サーバ認証
+ m_checkServerCert = economyConfig.GetBoolean("CheckServerCert", m_checkServerCert);
+ m_cacertFilename = economyConfig.GetString("CACertFilename", m_cacertFilename);
+ if (m_cacertFilename!="") {
+ m_certVerify.SetPrivateCA(m_cacertFilename);
+ m_log.InfoFormat("[MONEY]: Execute Authentication of Server. CA Cert File is " + m_cacertFilename);
+ }
+ else {
+ m_checkServerCert = false;
+ }
+ ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(m_certVerify.ValidateServerCertificate);
+
+
+ // Settlement
+ m_use_web_settle = economyConfig.GetBoolean("SettlementByWeb", m_use_web_settle);
+ m_settle_url = economyConfig.GetString ("SettlementURL", m_settle_url);
+ m_settle_message = economyConfig.GetString ("SettlementMessage", m_settle_message);
+
+ // Price
+ PriceEnergyUnit = economyConfig.GetInt ("PriceEnergyUnit", PriceEnergyUnit);
+ PriceObjectClaim = economyConfig.GetInt ("PriceObjectClaim", PriceObjectClaim);
+ PricePublicObjectDecay = economyConfig.GetInt ("PricePublicObjectDecay", PricePublicObjectDecay);
+ PricePublicObjectDelete = economyConfig.GetInt ("PricePublicObjectDelete", PricePublicObjectDelete);
+ PriceParcelClaim = economyConfig.GetInt ("PriceParcelClaim", PriceParcelClaim);
+ PriceParcelClaimFactor = economyConfig.GetFloat("PriceParcelClaimFactor", PriceParcelClaimFactor);
+ PriceUpload = economyConfig.GetInt ("PriceUpload", PriceUpload);
+ PriceRentLight = economyConfig.GetInt ("PriceRentLight", PriceRentLight);
+ PriceObjectRent = economyConfig.GetFloat("PriceObjectRent", PriceObjectRent);
+ PriceObjectScaleFactor = economyConfig.GetFloat("PriceObjectScaleFactor", PriceObjectScaleFactor);
+ PriceParcelRent = economyConfig.GetInt ("PriceParcelRent", PriceParcelRent);
+ PriceGroupCreate = economyConfig.GetInt ("PriceGroupCreate", PriceGroupCreate);
+ TeleportMinPrice = economyConfig.GetInt ("TeleportMinPrice", TeleportMinPrice);
+ TeleportPriceExponent = economyConfig.GetFloat("TeleportPriceExponent", TeleportPriceExponent);
+ EnergyEfficiency = economyConfig.GetFloat("EnergyEfficiency", EnergyEfficiency);
+
+ // for HG Avatar
+ string avatar_class = economyConfig.GetString("HGAvatarAs", "HGAvatar").ToLower();
+ if (avatar_class=="localavatar") m_hg_avatarClass = (int)AvatarType.LOCAL_AVATAR;
+ else if (avatar_class=="guestavatar") m_hg_avatarClass = (int)AvatarType.GUEST_AVATAR;
+ else if (avatar_class=="hgavatar") m_hg_avatarClass = (int)AvatarType.HG_AVATAR;
+ else if (avatar_class=="foreignavatar") m_hg_avatarClass = (int)AvatarType.FOREIGN_AVATAR;
+ else m_hg_avatarClass = (int)AvatarType.UNKNOWN_AVATAR;
+
+ }
+ catch {
+ m_log.ErrorFormat("[MONEY]: Initialise: Faile to read configuration file");
+ }
+ }
+
+
+ public void AddRegion(Scene scene)
+ {
+ //m_log.InfoFormat("[MONEY]: AddRegion:");
+
+ if (scene==null) return;
+
+ scene.RegisterModuleInterface(this); // 競合するモジュールの排除
+
+ lock (m_sceneList) {
+ if (m_sceneList.Count==0) {
+ if (m_enable_server) {
+ HttpServer = new BaseHttpServer(9000);
+ HttpServer.AddStreamHandler(new Region.Framework.Scenes.RegionStatsHandler(scene.RegionInfo));
+
+ HttpServer.AddXmlRPCHandler("OnMoneyTransfered", OnMoneyTransferedHandler);
+ HttpServer.AddXmlRPCHandler("UpdateBalance", BalanceUpdateHandler);
+ HttpServer.AddXmlRPCHandler("UserAlert", UserAlertHandler);
+ HttpServer.AddXmlRPCHandler("GetBalance", GetBalanceHandler); // added
+ HttpServer.AddXmlRPCHandler("AddBankerMoney", AddBankerMoneyHandler); // added
+ HttpServer.AddXmlRPCHandler("SendMoney", SendMoneyHandler); // added
+ HttpServer.AddXmlRPCHandler("MoveMoney", MoveMoneyHandler); // added
+
+ MainServer.Instance.AddXmlRPCHandler("OnMoneyTransfered", OnMoneyTransferedHandler);
+ MainServer.Instance.AddXmlRPCHandler("UpdateBalance", BalanceUpdateHandler);
+ MainServer.Instance.AddXmlRPCHandler("UserAlert", UserAlertHandler);
+ MainServer.Instance.AddXmlRPCHandler("GetBalance", GetBalanceHandler); // added
+ MainServer.Instance.AddXmlRPCHandler("AddBankerMoney", AddBankerMoneyHandler); // added
+ MainServer.Instance.AddXmlRPCHandler("SendMoney", SendMoneyHandler); // added
+ MainServer.Instance.AddXmlRPCHandler("MoveMoney", MoveMoneyHandler); // added
+ }
+ }
+
+ if (m_sceneList.ContainsKey(scene.RegionInfo.RegionHandle)) {
+ m_sceneList[scene.RegionInfo.RegionHandle] = scene;
+ }
+ else {
+ m_sceneList.Add(scene.RegionInfo.RegionHandle, scene);
+ }
+ }
+
+ scene.EventManager.OnNewClient += OnNewClient;
+ scene.EventManager.OnMakeRootAgent += OnMakeRootAgent;
+ scene.EventManager.OnMakeChildAgent += MakeChildAgent;
+
+ // for OpenSim
+ scene.EventManager.OnMoneyTransfer += MoneyTransferAction;
+ scene.EventManager.OnValidateLandBuy += ValidateLandBuy;
+ scene.EventManager.OnLandBuy += processLandBuy;
+ }
+
+
+ public void RemoveRegion(Scene scene)
+ {
+ if (scene==null) return;
+
+ lock (m_sceneList) {
+ scene.EventManager.OnNewClient -= OnNewClient;
+ scene.EventManager.OnMakeRootAgent -= OnMakeRootAgent;
+ scene.EventManager.OnMakeChildAgent -= MakeChildAgent;
+
+ // for OpenSim
+ scene.EventManager.OnMoneyTransfer -= MoneyTransferAction;
+ scene.EventManager.OnValidateLandBuy -= ValidateLandBuy;
+ scene.EventManager.OnLandBuy -= processLandBuy;
+ }
+ }
+
+
+ public void RegionLoaded(Scene scene)
+ {
+ //m_log.InfoFormat("[MONEY]: RegionLoaded:");
+ }
+
+
+ public Type ReplaceableInterface
+ {
+ //get { return typeof(IMoneyModule); }
+ get { return null; }
+ }
+
+
+ public bool IsSharedModule
+ {
+ get { return true; }
+ }
+
+
+ public string Name
+ {
+ get { return "DTLNSLMoneyModule"; }
+ }
+
+
+ public void PostInitialise()
+ {
+ //m_log.InfoFormat("[MONEY]: PostInitialise:");
+ }
+
+
+ public void Close()
+ {
+ //m_log.InfoFormat("[MONEY]: Close:");
+ }
+
+ #endregion
+
+
+ #region IMoneyModule interface.
+
+ // for LSL llGiveMoney() function
+ public bool ObjectGiveMoney(UUID objectID, UUID fromID, UUID toID, int amount, UUID txn, out string result)
+ {
+ //m_log.InfoFormat("[MONEY]: ObjectGiveMoney: LSL ObjectGiveMoney. UUID = {0}", objectID.ToString());
+
+ result = string.Empty;
+ if (!m_sellEnabled) {
+ result = "LINDENDOLLAR_INSUFFICIENTFUNDS";
+ return false;
+ }
+
+ string objName = string.Empty;
+ string avatarName = string.Empty;
+
+ SceneObjectPart sceneObj = GetLocatePrim(objectID);
+ if (sceneObj==null) {
+ result = "LINDENDOLLAR_INSUFFICIENTFUNDS";
+ return false;
+ }
+ objName = sceneObj.Name;
+
+ Scene scene = GetLocateScene(toID);
+ if (scene!=null) {
+ UserAccount account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, toID);
+ if (account!=null) {
+ avatarName = account.FirstName + " " + account.LastName;
+ }
+ }
+
+ bool ret = false;
+ string description = String.Format("Object {0} pays {1}", objName, avatarName);
+
+ if (sceneObj.OwnerID==fromID) {
+ ulong regionHandle = sceneObj.RegionHandle;
+ UUID regionUUID = sceneObj.RegionID;
+ if (GetLocateClient(fromID)!=null) {
+ ret = TransferMoney(fromID, toID, amount, (int)TransactionType.ObjectPays, objectID, regionHandle, regionUUID, description);
+ }
+ else {
+ ret = ForceTransferMoney(fromID, toID, amount, (int)TransactionType.ObjectPays, objectID, regionHandle, regionUUID, description);
+ }
+ }
+
+ if (!ret) result = "LINDENDOLLAR_INSUFFICIENTFUNDS";
+ return ret;
+ }
+
+
+ //
+ public int UploadCharge
+ {
+ get { return PriceUpload; }
+ }
+
+
+ //
+ public int GroupCreationCharge
+ {
+ get { return PriceGroupCreate; }
+ }
+
+
+ public int GetBalance(UUID agentID)
+ {
+ IClientAPI client = GetLocateClient(agentID);
+ return QueryBalanceFromMoneyServer(client);
+ }
+
+
+ public bool UploadCovered(UUID agentID, int amount)
+ {
+ IClientAPI client = GetLocateClient(agentID);
+
+ if (m_enable_server || string.IsNullOrEmpty(m_moneyServURL)) {
+ int balance = QueryBalanceFromMoneyServer(client);
+ if (balance>=amount) return true;
+ }
+ return false;
+ }
+
+
+ public bool AmountCovered(UUID agentID, int amount)
+ {
+ IClientAPI client = GetLocateClient(agentID);
+
+ if (m_enable_server || string.IsNullOrEmpty(m_moneyServURL)) {
+ int balance = QueryBalanceFromMoneyServer(client);
+ if (balance>=amount) return true;
+ }
+ return false;
+ }
+
+
+ public void ApplyUploadCharge(UUID agentID, int amount, string text)
+ {
+ ulong regionHandle = GetLocateScene(agentID).RegionInfo.RegionHandle;
+ UUID regionUUID = GetLocateScene(agentID).RegionInfo.RegionID;
+ PayMoneyCharge(agentID, amount, (int)TransactionType.UploadCharge, regionHandle, regionUUID, text);
+ }
+
+
+ public void ApplyCharge(UUID agentID, int amount, MoneyTransactionType type)
+ {
+ ApplyCharge(agentID, amount, type, string.Empty);
+ }
+
+
+ public void ApplyCharge(UUID agentID, int amount, MoneyTransactionType type, string text)
+ {
+ ulong regionHandle = GetLocateScene(agentID).RegionInfo.RegionHandle;
+ UUID regionUUID = GetLocateScene(agentID).RegionInfo.RegionID;
+ PayMoneyCharge(agentID, amount, (int)type, regionHandle, regionUUID, text);
+ }
+
+
+ public bool Transfer(UUID fromID, UUID toID, int regionHandle, int amount, MoneyTransactionType type, string text)
+ {
+ return TransferMoney(fromID, toID, amount, (int)type, UUID.Zero, (ulong)regionHandle, UUID.Zero, text);
+ }
+
+
+ public bool Transfer(UUID fromID, UUID toID, UUID objectID, int amount, MoneyTransactionType type, string text)
+ {
+ SceneObjectPart sceneObj = GetLocatePrim(objectID);
+ if (sceneObj==null) return false;
+
+ ulong regionHandle = sceneObj.ParentGroup.Scene.RegionInfo.RegionHandle;
+ UUID regionUUID = sceneObj.ParentGroup.Scene.RegionInfo.RegionID;
+ return TransferMoney(fromID, toID, amount, (int)type, objectID, (ulong)regionHandle, regionUUID, text);
+ }
+
+
+ // for 0.8.3 over
+ public void MoveMoney(UUID fromAgentID, UUID toAgentID, int amount, string text)
+ {
+ ForceTransferMoney(fromAgentID, toAgentID, amount, (int)TransactionType.MoveMoney, UUID.Zero, (ulong)0, UUID.Zero, text);
+ }
+
+ // for 0.9.1 over
+ public bool MoveMoney(UUID fromAgentID, UUID toAgentID, int amount, MoneyTransactionType type, string text)
+ {
+ bool ret = ForceTransferMoney(fromAgentID, toAgentID, amount, (int)type, UUID.Zero, (ulong)0, UUID.Zero, text);
+ return ret;
+ }
+
+ #endregion
+
+
+ #region MoneyModule event handlers
+
+ //
+ private void OnNewClient(IClientAPI client)
+ {
+ m_log.InfoFormat("[MONEY]: OnNewClient");
+
+ client.OnEconomyDataRequest += OnEconomyDataRequest;
+ client.OnLogout += ClientClosed;
+
+ client.OnMoneyBalanceRequest += OnMoneyBalanceRequest;
+ client.OnRequestPayPrice += OnRequestPayPrice;
+ client.OnObjectBuy += OnObjectBuy;
+ }
+
+
+ public void OnMakeRootAgent(ScenePresence agent)
+ {
+ m_log.InfoFormat("[MONEY]: OnMakeRootAgent:");
+
+ int balance = 0;
+ IClientAPI client = agent.ControllingClient;
+
+ m_enable_server = LoginMoneyServer(agent, out balance);
+ client.SendMoneyBalance(UUID.Zero, true, new byte[0], balance, 0, UUID.Zero, false, UUID.Zero, false, 0, String.Empty);
+
+ //client.OnMoneyBalanceRequest += OnMoneyBalanceRequest;
+ //client.OnRequestPayPrice += OnRequestPayPrice;
+ //client.OnObjectBuy += OnObjectBuy;
+ }
+
+
+ // for OnClientClosed event
+ private void ClientClosed(IClientAPI client)
+ {
+ //m_log.InfoFormat("[MONEY]: ClientClosed:");
+
+ if (m_enable_server && client!=null) {
+ LogoffMoneyServer(client);
+ }
+ }
+
+
+ // for OnMakeChildAgent event
+ private void MakeChildAgent(ScenePresence avatar)
+ {
+ //m_log.InfoFormat("[MONEY]: MakeChildAgent:");
+ }
+
+
+ // for OnMoneyTransfer event
+ private void MoneyTransferAction(Object sender, EventManager.MoneyTransferArgs moneyEvent)
+ {
+ //m_log.InfoFormat("[MONEY]: MoneyTransferAction: type = {0}", moneyEvent.transactiontype);
+
+ if (!m_sellEnabled) return;
+
+ // Check the money transaction is necessary.
+ if (moneyEvent.sender==moneyEvent.receiver) {
+ return;
+ }
+
+ UUID receiver = moneyEvent.receiver;
+ // Pay for the object.
+ if (moneyEvent.transactiontype==(int)TransactionType.PayObject) {
+ SceneObjectPart sceneObj = GetLocatePrim(moneyEvent.receiver);
+ if (sceneObj!=null) {
+ receiver = sceneObj.OwnerID;
+ }
+ else {
+ return;
+ }
+ }
+
+ // Before paying for the object, save the object local ID for current transaction.
+ UUID objectID = UUID.Zero;
+ ulong regionHandle = 0;
+ UUID regionUUID = UUID.Zero;
+
+ if (sender is Scene) {
+ Scene scene = (Scene)sender;
+ regionHandle = scene.RegionInfo.RegionHandle;
+ regionUUID = scene.RegionInfo.RegionID;
+
+ if (moneyEvent.transactiontype==(int)TransactionType.PayObject) {
+ objectID = scene.GetSceneObjectPart(moneyEvent.receiver).UUID;
+ }
+ }
+
+ TransferMoney(moneyEvent.sender, receiver, moneyEvent.amount, moneyEvent.transactiontype, objectID, regionHandle, regionUUID, "OnMoneyTransfer event");
+ return;
+ }
+
+
+ // for OnValidateLandBuy event
+ private void ValidateLandBuy(Object sender, EventManager.LandBuyArgs landBuyEvent)
+ {
+ //m_log.InfoFormat("[MONEY]: ValidateLandBuy:");
+
+ IClientAPI senderClient = GetLocateClient(landBuyEvent.agentId);
+ if (senderClient!=null) {
+ int balance = QueryBalanceFromMoneyServer(senderClient);
+ if (balance >= landBuyEvent.parcelPrice) {
+ lock(landBuyEvent) {
+ landBuyEvent.economyValidated = true;
+ }
+ }
+ }
+ return;
+ }
+
+
+ // for LandBuy even
+ private void processLandBuy(Object sender, EventManager.LandBuyArgs landBuyEvent)
+ {
+ //m_log.InfoFormat("[MONEY]: processLandBuy:");
+
+ if (!m_sellEnabled) return;
+
+ lock(landBuyEvent) {
+ if (landBuyEvent.economyValidated==true && landBuyEvent.transactionID==0) {
+ landBuyEvent.transactionID = Util.UnixTimeSinceEpoch();
+
+ ulong parcelID = (ulong)landBuyEvent.parcelLocalID;
+ UUID regionUUID = UUID.Zero;
+ if (sender is Scene) regionUUID = ((Scene)sender).RegionInfo.RegionID;
+
+ if (TransferMoney(landBuyEvent.agentId, landBuyEvent.parcelOwnerID,
+ landBuyEvent.parcelPrice, (int)TransactionType.LandSale, regionUUID, parcelID, regionUUID, "Land Purchase")) {
+ landBuyEvent.amountDebited = landBuyEvent.parcelPrice;
+ }
+ }
+ }
+ return;
+ }
+
+
+ // for OnObjectBuy event
+ public void OnObjectBuy(IClientAPI remoteClient, UUID agentID, UUID sessionID,
+ UUID groupID, UUID categoryID, uint localID, byte saleType, int salePrice)
+ {
+ m_log.InfoFormat("[MONEY]: OnObjectBuy: agent = {0}, {1}", agentID, remoteClient.AgentId);
+
+ // Handle the parameters error.
+ if (!m_sellEnabled) return;
+ if (remoteClient==null || salePrice<0) return;
+
+ // Get the balance from money server.
+ int balance = QueryBalanceFromMoneyServer(remoteClient);
+ if (balance();
+ if (mod!=null) {
+ UUID receiverId = sceneObj.OwnerID;
+ ulong regionHandle = sceneObj.RegionHandle;
+ UUID regionUUID = sceneObj.RegionID;
+ bool ret = false;
+ //
+ if (salePrice>=0) {
+ if (!string.IsNullOrEmpty(m_moneyServURL)) {
+ ret = TransferMoney(remoteClient.AgentId, receiverId, salePrice,
+ (int)TransactionType.PayObject, sceneObj.UUID, regionHandle, regionUUID, "Object Buy");
+ }
+ else if (salePrice==0) { // amount is 0 with No Money Server
+ ret = true;
+ }
+ }
+ if (ret) {
+ mod.BuyObject(remoteClient, categoryID, localID, saleType, salePrice);
+ }
+ }
+ }
+ else {
+ remoteClient.SendAgentAlertMessage("Unable to buy now. The object was not found", false);
+ return;
+ }
+ }
+ return;
+ }
+
+
+ ///
+ /// Sends the the stored money balance to the client
+ ///
+ ///
+ ///
+ ///
+ ///
+ private void OnMoneyBalanceRequest(IClientAPI client, UUID agentID, UUID SessionID, UUID TransactionID)
+ {
+ m_log.InfoFormat("[MONEY]: OnMoneyBalanceRequest:");
+
+ if (client.AgentId==agentID && client.SessionId==SessionID) {
+ int balance = 0;
+ //
+ if (m_enable_server) {
+ balance = QueryBalanceFromMoneyServer(client);
+ }
+
+ client.SendMoneyBalance(TransactionID, true, new byte[0], balance, 0, UUID.Zero, false, UUID.Zero, false, 0, String.Empty);
+ }
+ else {
+ client.SendAlertMessage("Unable to send your money balance");
+ }
+ }
+
+
+ private void OnRequestPayPrice(IClientAPI client, UUID objectID)
+ {
+ m_log.InfoFormat("[MONEY]: OnRequestPayPrice:");
+
+ Scene scene = GetLocateScene(client.AgentId);
+ if (scene==null) return;
+ SceneObjectPart sceneObj = scene.GetSceneObjectPart(objectID);
+ if (sceneObj==null) return;
+ SceneObjectGroup group = sceneObj.ParentGroup;
+ SceneObjectPart root = group.RootPart;
+
+ client.SendPayPrice(objectID, root.PayPrice);
+ }
+
+
+ //
+ //private void OnEconomyDataRequest(UUID agentId)
+ private void OnEconomyDataRequest(IClientAPI user)
+ {
+ //m_log.InfoFormat("[MONEY]: OnEconomyDataRequest:");
+ //IClientAPI user = GetLocateClient(agentId);
+
+ if (user!=null) {
+ if (m_enable_server || string.IsNullOrEmpty(m_moneyServURL)) {
+ //Scene s = GetLocateScene(user.AgentId);
+ Scene s = (Scene)user.Scene;
+ user.SendEconomyData(EnergyEfficiency, s.RegionInfo.ObjectCapacity, ObjectCount, PriceEnergyUnit, PriceGroupCreate,
+ PriceObjectClaim, PriceObjectRent, PriceObjectScaleFactor, PriceParcelClaim, PriceParcelClaimFactor,
+ PriceParcelRent, PricePublicObjectDecay, PricePublicObjectDelete, PriceRentLight, PriceUpload,
+ TeleportMinPrice, TeleportPriceExponent);
+ }
+ }
+ }
+
+ #endregion
+
+
+ #region MoneyModule XML-RPC Handler
+
+ // "OnMoneyTransfered" RPC from MoneyServer
+ public XmlRpcResponse OnMoneyTransferedHandler(XmlRpcRequest request, IPEndPoint remoteClient)
+ {
+ m_log.InfoFormat("[MONEY]: OnMoneyTransferedHandler:");
+
+ bool ret = false;
+
+ if (request.Params.Count>0) {
+ Hashtable requestParam = (Hashtable)request.Params[0];
+ if (requestParam.Contains("clientUUID") && requestParam.Contains("clientSessionID") && requestParam.Contains("clientSecureSessionID")) {
+ UUID clientUUID = UUID.Zero;
+ UUID.TryParse((string)requestParam["clientUUID"], out clientUUID);
+
+ if (clientUUID!=UUID.Zero) {
+ IClientAPI client = GetLocateClient(clientUUID);
+ string sessionid = (string)requestParam["clientSessionID"];
+ string secureid = (string)requestParam["clientSecureSessionID"];
+ if (client!=null && secureid==client.SecureSessionId.ToString() && (sessionid==UUID.Zero.ToString()||sessionid==client.SessionId.ToString())) {
+ if (requestParam.Contains("transactionType") && requestParam.Contains("objectID") && requestParam.Contains("amount")) {
+ //m_log.InfoFormat("[MONEY]: OnMoneyTransferedHandler: type = {0}", requestParam["transactionType"]);
+
+ // Pay for the object.
+ if ((int)requestParam["transactionType"]==(int)TransactionType.PayObject) {
+ // Send notify to the client(viewer) for Money Event Trigger.
+ ObjectPaid handlerOnObjectPaid = OnObjectPaid;
+ if (handlerOnObjectPaid!=null) {
+ UUID objectID = UUID.Zero;
+ UUID.TryParse((string)requestParam["objectID"], out objectID);
+ handlerOnObjectPaid(objectID, clientUUID, (int)requestParam["amount"]); // call Script Engine for LSL money()
+ }
+ ret = true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Send the response to money server.
+ XmlRpcResponse resp = new XmlRpcResponse();
+ Hashtable paramTable = new Hashtable();
+ paramTable["success"] = ret;
+
+ if (!ret) {
+ m_log.ErrorFormat("[MONEY]: OnMoneyTransferedHandler: Transaction is failed. MoneyServer will rollback");
+ }
+ resp.Value = paramTable;
+
+ return resp;
+ }
+
+
+ // "UpdateBalance" RPC from MoneyServer or Script
+ public XmlRpcResponse BalanceUpdateHandler(XmlRpcRequest request, IPEndPoint remoteClient)
+ {
+ //m_log.InfoFormat("[MONEY]: BalanceUpdateHandler:");
+
+ bool ret = false;
+
+ #region Update the balance from money server.
+
+ if (request.Params.Count>0)
+ {
+ Hashtable requestParam = (Hashtable)request.Params[0];
+ if (requestParam.Contains("clientUUID") && requestParam.Contains("clientSessionID") && requestParam.Contains("clientSecureSessionID")) {
+ UUID clientUUID = UUID.Zero;
+ UUID.TryParse((string)requestParam["clientUUID"], out clientUUID);
+ //
+ if (clientUUID!=UUID.Zero) {
+ IClientAPI client = GetLocateClient(clientUUID);
+ string sessionid = (string)requestParam["clientSessionID"];
+ string secureid = (string)requestParam["clientSecureSessionID"];
+ if (client!=null && secureid==client.SecureSessionId.ToString() && (sessionid==UUID.Zero.ToString()||sessionid==client.SessionId.ToString())) {
+ //
+ if (requestParam.Contains("Balance")) {
+ // Send notify to the client.
+ string msg = "";
+ if (requestParam.Contains("Message")) msg = (string)requestParam["Message"];
+ client.SendMoneyBalance(UUID.Random(), true, Utils.StringToBytes(msg), (int)requestParam["Balance"],
+ 0, UUID.Zero, false, UUID.Zero, false, 0, String.Empty);
+ // Dialog
+ if (msg!="") {
+ Scene scene = (Scene)client.Scene;
+ IDialogModule dlg = scene.RequestModuleInterface();
+ dlg.SendAlertToUser(client.AgentId, msg);
+ }
+ ret = true;
+ }
+ }
+ }
+ }
+ }
+
+ #endregion
+
+ // Send the response to money server.
+ XmlRpcResponse resp = new XmlRpcResponse();
+ Hashtable paramTable = new Hashtable();
+ paramTable["success"] = ret;
+
+ if (!ret) {
+ m_log.ErrorFormat("[MONEY]: BalanceUpdateHandler: Cannot update client balance from MoneyServer");
+ }
+ resp.Value = paramTable;
+
+ return resp;
+ }
+
+
+ // "UserAlert" RPC from Script
+ public XmlRpcResponse UserAlertHandler(XmlRpcRequest request, IPEndPoint remoteClient)
+ {
+ //m_log.InfoFormat("[MONEY]: UserAlertHandler:");
+
+ bool ret = false;
+
+ #region confirm the request and show the notice from money server.
+
+ if (request.Params.Count>0) {
+ Hashtable requestParam = (Hashtable)request.Params[0];
+ if (requestParam.Contains("clientUUID") && requestParam.Contains("clientSessionID") && requestParam.Contains("clientSecureSessionID")) {
+ UUID clientUUID = UUID.Zero;
+ UUID.TryParse((string)requestParam["clientUUID"], out clientUUID);
+ //
+ if (clientUUID!=UUID.Zero) {
+ IClientAPI client = GetLocateClient(clientUUID);
+ string sessionid = (string)requestParam["clientSessionID"];
+ string secureid = (string)requestParam["clientSecureSessionID"];
+ if (client!=null && secureid==client.SecureSessionId.ToString() && (sessionid==UUID.Zero.ToString()||sessionid==client.SessionId.ToString())) {
+ if (requestParam.Contains("Description"))
+ {
+ string description = (string)requestParam["Description"];
+ // Show the notice dialog with money server message.
+ GridInstantMessage gridMsg = new GridInstantMessage(null, UUID.Zero, "MonyServer", new UUID(clientUUID.ToString()),
+ (byte)InstantMessageDialog.MessageFromAgent, description, false, new Vector3());
+ client.SendInstantMessage(gridMsg);
+ ret = true;
+ }
+ }
+ }
+ }
+ }
+ //
+ #endregion
+
+ // Send the response to money server.
+ XmlRpcResponse resp = new XmlRpcResponse();
+ Hashtable paramTable = new Hashtable();
+ paramTable["success"] = ret;
+
+ resp.Value = paramTable;
+ return resp;
+ }
+
+
+ // "GetBalance" RPC from Script
+ public XmlRpcResponse GetBalanceHandler(XmlRpcRequest request, IPEndPoint remoteClient)
+ {
+ //m_log.InfoFormat("[MONEY]: GetBalanceHandler:");
+
+ bool ret = false;
+ int balance = -1;
+
+ if (request.Params.Count>0)
+ {
+ Hashtable requestParam = (Hashtable)request.Params[0];
+ if (requestParam.Contains("clientUUID") && requestParam.Contains("clientSessionID") && requestParam.Contains("clientSecureSessionID")) {
+ UUID clientUUID = UUID.Zero;
+ UUID.TryParse((string)requestParam["clientUUID"], out clientUUID);
+ //
+ if (clientUUID!=UUID.Zero) {
+ IClientAPI client = GetLocateClient(clientUUID);
+ string sessionid = (string)requestParam["clientSessionID"];
+ string secureid = (string)requestParam["clientSecureSessionID"];
+ if (client!=null && secureid==client.SecureSessionId.ToString() && (sessionid==UUID.Zero.ToString()||sessionid==client.SessionId.ToString())) {
+ balance = QueryBalanceFromMoneyServer(client);
+ }
+ }
+ }
+ }
+
+ // Send the response to caller.
+ if (balance<0) {
+ m_log.ErrorFormat("[MONEY]: GetBalanceHandler: GetBalance transaction is failed");
+ ret = false;
+ }
+
+ XmlRpcResponse resp = new XmlRpcResponse();
+ Hashtable paramTable = new Hashtable();
+ paramTable["success"] = ret;
+ paramTable["balance"] = balance;
+ resp.Value = paramTable;
+
+ return resp;
+ }
+
+
+ // "AddBankerMoney" RPC from Script
+ public XmlRpcResponse AddBankerMoneyHandler(XmlRpcRequest request, IPEndPoint remoteClient)
+ {
+ //m_log.InfoFormat("[MONEY]: AddBankerMoneyHandler:");
+
+ bool ret = false;
+
+ if (request.Params.Count>0)
+ {
+ Hashtable requestParam = (Hashtable)request.Params[0];
+
+ if (requestParam.Contains("clientUUID") && requestParam.Contains("clientSessionID") && requestParam.Contains("clientSecureSessionID")) {
+ UUID bankerUUID = UUID.Zero;
+ UUID.TryParse((string)requestParam["clientUUID"], out bankerUUID);
+ //
+ if (bankerUUID!=UUID.Zero) {
+ IClientAPI client = GetLocateClient(bankerUUID);
+ string sessionid = (string)requestParam["clientSessionID"];
+ string secureid = (string)requestParam["clientSecureSessionID"];
+ if (client!=null && secureid==client.SecureSessionId.ToString() && (sessionid==UUID.Zero.ToString()||sessionid==client.SessionId.ToString())) {
+ if (requestParam.Contains("amount"))
+ {
+ Scene scene = (Scene)client.Scene;
+ int amount = (int)requestParam["amount"];
+ ulong regionHandle = scene.RegionInfo.RegionHandle;
+ UUID regionUUID = scene.RegionInfo.RegionID;
+ ret = AddBankerMoney(bankerUUID, amount, regionHandle, regionUUID);
+
+ if (m_use_web_settle && m_settle_user) {
+ ret = true;
+ IDialogModule dlg = scene.RequestModuleInterface();
+ if (dlg!=null) {
+ dlg.SendUrlToUser(bankerUUID, "SYSTEM", UUID.Zero, UUID.Zero, false, m_settle_message, m_settle_url);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!ret) m_log.ErrorFormat("[MONEY]: AddBankerMoneyHandler: Add Banker Money transaction is failed");
+
+ // Send the response to caller.
+ XmlRpcResponse resp = new XmlRpcResponse();
+ Hashtable paramTable = new Hashtable();
+ paramTable["settle"] = false;
+ paramTable["success"] = ret;
+
+ if (m_use_web_settle && m_settle_user) paramTable["settle"] = true;
+ resp.Value = paramTable;
+
+ return resp;
+ }
+
+
+ // "SendMoney" RPC from Script
+ public XmlRpcResponse SendMoneyHandler(XmlRpcRequest request, IPEndPoint remoteClient)
+ {
+ //m_log.InfoFormat("[MONEY]: SendMoneyHandler:");
+
+ bool ret = false;
+
+ if (request.Params.Count>0) {
+ Hashtable requestParam = (Hashtable)request.Params[0];
+ if (requestParam.Contains("agentUUID") && requestParam.Contains("secretAccessCode")) {
+ UUID agentUUID = UUID.Zero;
+ UUID.TryParse((string)requestParam["agentUUID"], out agentUUID);
+
+ if (agentUUID!=UUID.Zero) {
+ if (requestParam.Contains("amount")) {
+ int amount = (int)requestParam["amount"];
+ int type = -1;
+ if (requestParam.Contains("type")) type = (int)requestParam["type"];
+ string secretCode = (string)requestParam["secretAccessCode"];
+ string scriptIP = remoteClient.Address.ToString();
+
+ MD5 md5 = MD5.Create();
+ byte[] code = md5.ComputeHash(ASCIIEncoding.Default.GetBytes(secretCode + "_" + scriptIP));
+ string hash = BitConverter.ToString(code).ToLower().Replace("-","");
+ //m_log.InfoFormat("[MONEY]: SendMoneyHandler: SecretCode: {0} + {1} = {2}", secretCode, scriptIP, hash);
+ ret = SendMoneyTo(agentUUID, amount, type, hash);
+ }
+ }
+ else {
+ m_log.ErrorFormat("[MONEY]: SendMoneyHandler: amount is missed");
+ }
+ }
+ else {
+ if (!requestParam.Contains("agentUUID")) {
+ m_log.ErrorFormat("[MONEY]: SendMoneyHandler: agentUUID is missed");
+ }
+ if (!requestParam.Contains("secretAccessCode")) {
+ m_log.ErrorFormat("[MONEY]: SendMoneyHandler: secretAccessCode is missed");
+ }
+ }
+ }
+ else {
+ m_log.ErrorFormat("[MONEY]: SendMoneyHandler: Params count is under 0");
+ }
+
+ if (!ret) m_log.ErrorFormat("[MONEY]: SendMoneyHandler: Send Money transaction is failed");
+
+ // Send the response to caller.
+ XmlRpcResponse resp = new XmlRpcResponse();
+ Hashtable paramTable = new Hashtable();
+ paramTable["success"] = ret;
+
+ resp.Value = paramTable;
+
+ return resp;
+ }
+
+
+ // "MoveMoney" RPC from Script
+ public XmlRpcResponse MoveMoneyHandler(XmlRpcRequest request, IPEndPoint remoteClient)
+ {
+ //m_log.InfoFormat("[MONEY]: MoveMoneyHandler:");
+
+ bool ret = false;
+
+ if (request.Params.Count>0)
+ {
+ Hashtable requestParam = (Hashtable)request.Params[0];
+ if ((requestParam.Contains("fromUUID") || requestParam.Contains("toUUID")) && requestParam.Contains("secretAccessCode")) {
+ UUID fromUUID = UUID.Zero;
+ UUID toUUID = UUID.Zero; // UUID.Zero means System
+ if (requestParam.Contains("fromUUID")) UUID.TryParse((string)requestParam["fromUUID"], out fromUUID);
+ if (requestParam.Contains("toUUID")) UUID.TryParse((string)requestParam["toUUID"], out toUUID);
+
+ if (requestParam.Contains("amount")) {
+ int amount = (int)requestParam["amount"];
+ string secretCode = (string)requestParam["secretAccessCode"];
+ string scriptIP = remoteClient.Address.ToString();
+
+ MD5 md5 = MD5.Create();
+ byte[] code = md5.ComputeHash(ASCIIEncoding.Default.GetBytes(secretCode + "_" + scriptIP));
+ string hash = BitConverter.ToString(code).ToLower().Replace("-","");
+ //m_log.InfoFormat("[MONEY]: MoveMoneyHandler: SecretCode: {0} + {1} = {2}", secretCode, scriptIP, hash);
+ ret = MoveMoneyFromTo(fromUUID, toUUID, amount, hash);
+ }
+ else {
+ m_log.ErrorFormat("[MONEY]: MoveMoneyHandler: amount is missed");
+ }
+ }
+ else {
+ if (!requestParam.Contains("fromUUID") && !requestParam.Contains("toUUID")) {
+ m_log.ErrorFormat("[MONEY]: MoveMoneyHandler: fromUUID and toUUID are missed");
+ }
+ if (!requestParam.Contains("secretAccessCode")) {
+ m_log.ErrorFormat("[MONEY]: MoveMoneyHandler: secretAccessCode is missed");
+ }
+ }
+ }
+ else {
+ m_log.ErrorFormat("[MONEY]: MoveMoneyHandler: Params count is under 0");
+ }
+
+ if (!ret) m_log.ErrorFormat("[MONEY]: MoveMoneyHandler: Move Money transaction is failed");
+
+ // Send the response to caller.
+ XmlRpcResponse resp = new XmlRpcResponse();
+ Hashtable paramTable = new Hashtable();
+ paramTable["success"] = ret;
+
+ resp.Value = paramTable;
+
+ return resp;
+ }
+
+ #endregion
+
+
+ #region MoneyModule private help functions
+
+ ///
+ /// Transfer the money from one user to another. Need to notify money server to update.
+ ///
+ ///
+ /// The amount of money.
+ ///
+ ///
+ /// return true, if successfully.
+ ///
+ private bool TransferMoney(UUID sender, UUID receiver, int amount, int type, UUID objectID, ulong regionHandle, UUID regionUUID, string description)
+ {
+ //m_log.InfoFormat("[MONEY]: TransferMoney:");
+
+ bool ret = false;
+ IClientAPI senderClient = GetLocateClient(sender);
+
+ // Handle the illegal transaction.
+ // receiverClient could be null.
+ if (senderClient==null) {
+ m_log.InfoFormat("[MONEY]: TransferMoney: Client {0} not found", sender.ToString());
+ return false;
+ }
+
+ if (QueryBalanceFromMoneyServer(senderClient)
+ /// Force transfer the money from one user to another.
+ /// This function does not check sender login.
+ /// Need to notify money server to update.
+ ///
+ ///
+ /// The amount of money.
+ ///
+ ///
+ /// return true, if successfully.
+ ///
+ private bool ForceTransferMoney(UUID sender, UUID receiver, int amount, int type, UUID objectID, ulong regionHandle, UUID regionUUID, string description)
+ {
+ //m_log.InfoFormat("[MONEY]: ForceTransferMoney:");
+
+ bool ret = false;
+
+ #region Force send transaction request to money server and parse the resultes.
+
+ if (m_enable_server) {
+ string objName = string.Empty;
+ SceneObjectPart sceneObj = GetLocatePrim(objectID);
+ if (sceneObj!=null)objName = sceneObj.Name;
+
+ // Fill parameters for money transfer XML-RPC.
+ Hashtable paramTable = new Hashtable();
+ paramTable["senderID"] = sender.ToString();
+ paramTable["receiverID"] = receiver.ToString();
+ paramTable["transactionType"] = type;
+ paramTable["objectID"] = objectID.ToString();
+ paramTable["objectName"] = objName;
+ paramTable["regionHandle"] = regionHandle.ToString();
+ paramTable["regionUUID"] = regionUUID.ToString();
+ paramTable["amount"] = amount;
+ paramTable["description"] = description;
+
+ // Generate the request for transfer.
+ Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "ForceTransferMoney");
+
+ // Handle the return values from Money Server.
+ if (resultTable!=null && resultTable.Contains("success")) {
+ if ((bool)resultTable["success"]==true) {
+ ret = true;
+ }
+ }
+ else m_log.ErrorFormat("[MONEY]: ForceTransferMoney: Can not money force transfer request from [{0}] to [{1}]", sender.ToString(), receiver.ToString());
+ }
+ //else m_log.ErrorFormat("[MONEY]: ForceTransferMoney: Money Server is not available!!");
+
+ #endregion
+
+ return ret;
+ }
+
+
+ ///
+ /// Send the money to avatar. Need to notify money server to update.
+ ///
+ ///
+ /// The amount of money.
+ ///
+ ///
+ /// return true, if successfully.
+ ///
+ private bool SendMoneyTo(UUID avatarID, int amount, int type, string secretCode)
+ {
+ //m_log.InfoFormat("[MONEY]: SendMoneyTo:");
+
+ bool ret = false;
+
+ if (m_enable_server) {
+ // Fill parameters for money transfer XML-RPC.
+ if (type<0) type = (int)TransactionType.ReferBonus;
+ Hashtable paramTable = new Hashtable();
+ paramTable["receiverID"] = avatarID.ToString();
+ paramTable["transactionType"] = type;
+ paramTable["amount"] = amount;
+ paramTable["secretAccessCode"] = secretCode;
+ paramTable["description"] = "Bonus to Avatar";
+
+ // Generate the request for transfer.
+ Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "SendMoney");
+
+ // Handle the return values from Money Server.
+ if (resultTable!=null && resultTable.Contains("success")) {
+ if ((bool)resultTable["success"]==true) {
+ ret = true;
+ }
+ else m_log.ErrorFormat("[MONEY]: SendMoneyTo: Fail Message is {0}", resultTable["message"]);
+ }
+ else m_log.ErrorFormat("[MONEY]: SendMoneyTo: Money Server is not responce");
+ }
+ //else m_log.ErrorFormat("[MONEY]: SendMoneyTo: Money Server is not available!!");
+
+ return ret;
+ }
+
+
+ ///
+ /// Move the money from avatar to other avatar. Need to notify money server to update.
+ ///
+ ///
+ /// The amount of money.
+ ///
+ ///
+ /// return true, if successfully.
+ ///
+ private bool MoveMoneyFromTo(UUID senderID, UUID receiverID, int amount, string secretCode)
+ {
+ //m_log.InfoFormat("[MONEY]: MoveMoneyFromTo:");
+
+ bool ret = false;
+
+ if (m_enable_server) {
+ // Fill parameters for money transfer XML-RPC.
+ Hashtable paramTable = new Hashtable();
+ paramTable["senderID"] = senderID.ToString();
+ paramTable["receiverID"] = receiverID.ToString();
+ paramTable["transactionType"] = (int)TransactionType.MoveMoney;
+ paramTable["amount"] = amount;
+ paramTable["secretAccessCode"] = secretCode;
+ paramTable["description"] = "Move Money";
+
+ // Generate the request for transfer.
+ Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "MoveMoney");
+
+ // Handle the return values from Money Server.
+ if (resultTable!=null && resultTable.Contains("success")) {
+ if ((bool)resultTable["success"]==true) {
+ ret = true;
+ }
+ else m_log.ErrorFormat("[MONEY]: MoveMoneyFromTo: Fail Message is {0}", resultTable["message"]);
+ }
+ else m_log.ErrorFormat("[MONEY]: MoveMoneyFromTo: Money Server is not responce");
+ }
+ //else m_log.ErrorFormat("[MONEY]: MoveMoneyFromTo: Money Server is not available!!");
+
+ return ret;
+ }
+
+
+ ///
+ /// Add the money to banker avatar. Need to notify money server to update.
+ ///
+ ///
+ /// The amount of money.
+ ///
+ ///
+ /// return true, if successfully.
+ ///
+ private bool AddBankerMoney(UUID bankerID, int amount, ulong regionHandle, UUID regionUUID)
+ {
+ //m_log.InfoFormat("[MONEY]: AddBankerMoney:");
+
+ bool ret = false;
+ m_settle_user = false;
+
+ if (m_enable_server) {
+ // Fill parameters for money transfer XML-RPC.
+ Hashtable paramTable = new Hashtable();
+ paramTable["bankerID"] = bankerID.ToString();
+ paramTable["transactionType"] = (int)TransactionType.BuyMoney;
+ paramTable["amount"] = amount;
+ paramTable["regionHandle"] = regionHandle.ToString();
+ paramTable["regionUUID"] = regionUUID.ToString();
+ paramTable["description"] = "Add Money to Avatar";
+
+ // Generate the request for transfer.
+ Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "AddBankerMoney");
+
+ // Handle the return values from Money Server.
+ if (resultTable!=null) {
+ if (resultTable.Contains("success") && (bool)resultTable["success"]==true) {
+ ret = true;
+ }
+ else {
+ if (resultTable.Contains("banker")) {
+ m_settle_user = !(bool)resultTable["banker"]; // If avatar is not banker, Web Settlement is used.
+ if (m_settle_user && m_use_web_settle) m_log.ErrorFormat("[MONEY]: AddBankerMoney: Avatar is not Banker. Web Settlemrnt is used.");
+ }
+ else m_log.ErrorFormat("[MONEY]: AddBankerMoney: Fail Message {0}", resultTable["message"]);
+ }
+ }
+ else m_log.ErrorFormat("[MONEY]: AddBankerMoney: Money Server is not responce");
+ }
+ //else m_log.ErrorFormat("[MONEY]: AddBankerMoney: Money Server is not available!!");
+
+ return ret;
+ }
+
+
+ ///
+ /// Pay the money of charge.
+ ///
+ ///
+ /// The amount of money.
+ ///
+ ///
+ /// return true, if successfully.
+ ///
+ private bool PayMoneyCharge(UUID sender, int amount, int type, ulong regionHandle, UUID regionUUID, string description)
+ {
+ //m_log.InfoFormat("[MONEY]: PayMoneyCharge:");
+
+ bool ret = false;
+ IClientAPI senderClient = GetLocateClient(sender);
+
+ // Handle the illegal transaction.
+ // receiverClient could be null.
+ if (senderClient==null) {
+ m_log.InfoFormat("[MONEY]: PayMoneyCharge: Client {0} is not found", sender.ToString());
+ return false;
+ }
+
+ if (QueryBalanceFromMoneyServer(senderClient)
+ /// Login the money server when the new client login.
+ ///
+ ///
+ /// Indicate user ID of the new client.
+ ///
+ ///
+ /// return true, if successfully.
+ ///
+ private bool LoginMoneyServer(ScenePresence avatar, out int balance)
+ {
+ //m_log.InfoFormat("[MONEY]: LoginMoneyServer:");
+
+ balance = 0;
+ bool ret = false;
+ bool isNpc = avatar.IsNPC;
+
+ IClientAPI client = avatar.ControllingClient;
+
+ #region Send money server the client info for login.
+
+ if (!string.IsNullOrEmpty(m_moneyServURL)) {
+ Scene scene = (Scene)client.Scene;
+ string userName = string.Empty;
+
+ // Get the username for the login user.
+ if (client.Scene is Scene) {
+ if (scene!=null) {
+ UserAccount account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, client.AgentId);
+ if (account!=null) {
+ userName = account.FirstName + " " + account.LastName;
+ }
+ }
+ }
+
+ //////////////////////////////////////////////////////////////
+ // User Universal Identifer for Grid Avatar, HG Avatar or NPC
+ string universalID = string.Empty;
+ string firstName = string.Empty;
+ string lastName = string.Empty;
+ string serverURL = string.Empty;
+ int avatarType = (int)AvatarType.LOCAL_AVATAR;
+ int avatarClass = (int)AvatarType.LOCAL_AVATAR;
+
+ AgentCircuitData agent = scene.AuthenticateHandler.GetAgentCircuitData(client.AgentId);
+
+ if (agent!=null) {
+ universalID = Util.ProduceUserUniversalIdentifier(agent);
+ if (!String.IsNullOrEmpty(universalID)) {
+ UUID uuid;
+ string tmp;
+ Util.ParseUniversalUserIdentifier(universalID, out uuid, out serverURL, out firstName, out lastName, out tmp);
+ }
+ // if serverURL is empty, avatar is a NPC
+ if (isNpc || String.IsNullOrEmpty(serverURL)) {
+ avatarType = (int)AvatarType.NPC_AVATAR;
+ }
+ //
+ if (!isNpc) {
+ if ((agent.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin)!=0 || String.IsNullOrEmpty(userName)) {
+ avatarType = (int)AvatarType.HG_AVATAR;
+ }
+ }
+ }
+ if (String.IsNullOrEmpty(userName)) {
+ userName = firstName + " " + lastName;
+ }
+
+ //
+ avatarClass = avatarType;
+ if (avatarType==(int)AvatarType.NPC_AVATAR) return true;
+ if (avatarType==(int)AvatarType.HG_AVATAR) avatarClass = m_hg_avatarClass;
+
+ //
+ // Lognn the Money Server.
+ Hashtable paramTable = new Hashtable();
+ paramTable["openSimServIP"] = scene.RegionInfo.ServerURI.Replace(scene.RegionInfo.InternalEndPoint.Port.ToString(),
+ scene.RegionInfo.HttpPort.ToString());
+ paramTable["avatarType"] = avatarType.ToString();
+ paramTable["avatarClass"] = avatarClass.ToString();
+ paramTable["userName"] = userName;
+ paramTable["universalID"] = universalID;
+ paramTable["clientUUID"] = client.AgentId.ToString();
+ paramTable["clientSessionID"] = client.SessionId.ToString();
+ paramTable["clientSecureSessionID"] = client.SecureSessionId.ToString();
+
+ // Generate the request for transfer.
+ Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "ClientLogin");
+
+ // Handle the return result
+ if (resultTable!=null && resultTable.Contains("success")) {
+ if ((bool)resultTable["success"]==true) {
+ balance = (int)resultTable["clientBalance"];
+ m_log.InfoFormat("[MONEY]: LoginMoneyServer: Client [{0}] login Money Server {1}", client.AgentId.ToString(), m_moneyServURL);
+ ret = true;
+ }
+ }
+ else m_log.ErrorFormat("[MONEY]: LoginMoneyServer: Unable to login Money Server {0} for client [{1}]", m_moneyServURL, client.AgentId.ToString());
+ }
+ else m_log.ErrorFormat("[MONEY]: LoginMoneyServer: Money Server is not available!!");
+
+ #endregion
+
+ // Viewerへ設定を通知する.
+ if (ret || string.IsNullOrEmpty(m_moneyServURL)) {
+ OnEconomyDataRequest(client);
+ }
+
+ return ret;
+ }
+
+
+ ///
+ /// Log off from the money server.
+ ///
+ ///
+ /// Indicate user ID of the new client.
+ ///
+ ///
+ /// return true, if successfully.
+ ///
+ private bool LogoffMoneyServer(IClientAPI client)
+ {
+ //m_log.InfoFormat("[MONEY]: LogoffMoneyServer:");
+
+ bool ret = false;
+
+ if (!string.IsNullOrEmpty(m_moneyServURL)) {
+ // Log off from the Money Server.
+ Hashtable paramTable = new Hashtable();
+ paramTable["clientUUID"] = client.AgentId.ToString();
+ paramTable["clientSessionID"] = client.SessionId.ToString();
+ paramTable["clientSecureSessionID"] = client.SecureSessionId.ToString();
+
+ // Generate the request for transfer.
+ Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "ClientLogout");
+ // Handle the return result
+ if (resultTable!=null && resultTable.Contains("success")) {
+ if ((bool)resultTable["success"]==true) {
+ ret = true;
+ }
+ }
+ }
+
+ return ret;
+ }
+
+
+ //
+ private EventManager.MoneyTransferArgs GetTransactionInfo(IClientAPI client, string transactionID)
+ {
+ //m_log.InfoFormat("[MONEY]: GetTransactionInfo:");
+
+ EventManager.MoneyTransferArgs args = null;
+
+ if (m_enable_server) {
+ Hashtable paramTable = new Hashtable();
+ paramTable["clientUUID"] = client.AgentId.ToString();
+ paramTable["clientSessionID"] = client.SessionId.ToString();
+ paramTable["clientSecureSessionID"] = client.SecureSessionId.ToString();
+ paramTable["transactionID"] = transactionID;
+
+ // Generate the request for transfer.
+ Hashtable resultTable = genericCurrencyXMLRPCRequest(paramTable, "GetTransaction");
+
+ // Handle the return result
+ if (resultTable!=null && resultTable.Contains("success")) {
+ if ((bool)resultTable["success"]==true) {
+ int amount = (int)resultTable["amount"];
+ int type = (int)resultTable["type"];
+ string desc = (string)resultTable["description"];
+ UUID sender = UUID.Zero;
+ UUID recver = UUID.Zero;
+ UUID.TryParse((string)resultTable["sender"], out sender);
+ UUID.TryParse((string)resultTable["receiver"], out recver);
+ args = new EventManager.MoneyTransferArgs(sender, recver, amount, type, desc);
+ }
+ else {
+ m_log.ErrorFormat("[MONEY]: GetTransactionInfo: GetTransactionInfo: Fail to Request. {0}", (string)resultTable["description"]);
+ }
+ }
+ else {
+ m_log.ErrorFormat("[MONEY]: GetTransactionInfo: Invalid Response");
+ }
+ }
+ else {
+ m_log.ErrorFormat("[MONEY]: GetTransactionInfo: Invalid Money Server URL");
+ }
+
+ return args;
+ }
+
+
+ ///
+ /// Generic XMLRPC client abstraction
+ ///
+ /// Hashtable containing parameters to the method
+ /// Method to invoke
+ /// Hashtable with success=>bool and other values
+ private Hashtable genericCurrencyXMLRPCRequest(Hashtable reqParams, string method)
+ {
+ //m_log.InfoFormat("[MONEY]: genericCurrencyXMLRPCRequest:");
+
+ if (reqParams.Count<=0 || string.IsNullOrEmpty(method)) return null;
+
+ if (m_checkServerCert) {
+ if (!m_moneyServURL.StartsWith("https://")) {
+ m_log.InfoFormat("[MONEY]: genericCurrencyXMLRPCRequest: CheckServerCert is true, but protocol is not HTTPS. Please check INI file");
+ //return null;
+ }
+ }
+ else {
+ if (!m_moneyServURL.StartsWith("https://") && !m_moneyServURL.StartsWith("http://")) {
+ m_log.ErrorFormat("[MONEY]: genericCurrencyXMLRPCRequest: Invalid Money Server URL: {0}", m_moneyServURL);
+ return null;
+ }
+ }
+
+ //
+ ArrayList arrayParams = new ArrayList();
+ arrayParams.Add(reqParams);
+ XmlRpcResponse moneyServResp = null;
+ try {
+ NSLXmlRpcRequest moneyModuleReq = new NSLXmlRpcRequest(method, arrayParams);
+ moneyServResp = moneyModuleReq.certSend(m_moneyServURL, m_cert, m_checkServerCert, MONEYMODULE_REQUEST_TIMEOUT);
+ }
+ catch (Exception ex) {
+ m_log.ErrorFormat("[MONEY]: genericCurrencyXMLRPCRequest: Unable to connect to Money Server {0}", m_moneyServURL);
+ m_log.ErrorFormat("[MONEY]: genericCurrencyXMLRPCRequest: {0}", ex);
+
+ Hashtable ErrorHash = new Hashtable();
+ ErrorHash["success"] = false;
+ ErrorHash["errorMessage"] = "Unable to manage your money at this time. Purchases may be unavailable";
+ ErrorHash["errorURI"] = "";
+ return ErrorHash;
+ }
+
+ if (moneyServResp==null || moneyServResp.IsFault) {
+ Hashtable ErrorHash = new Hashtable();
+ ErrorHash["success"] = false;
+ ErrorHash["errorMessage"] = "Unable to manage your money at this time. Purchases may be unavailable";
+ ErrorHash["errorURI"] = "";
+ return ErrorHash;
+ }
+
+ Hashtable moneyRespData = (Hashtable)moneyServResp.Value;
+ return moneyRespData;
+ }
+
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ /// Locates a IClientAPI for the client specified
+ ///
+ ///
+ ///
+ private IClientAPI GetLocateClient(UUID AgentID)
+ {
+ IClientAPI client = null;
+
+ lock (m_sceneList) {
+ if (m_sceneList.Count>0) {
+ foreach (Scene _scene in m_sceneList.Values) {
+ ScenePresence tPresence = (ScenePresence)_scene.GetScenePresence(AgentID);
+ if (tPresence!=null && !tPresence.IsChildAgent) {
+ IClientAPI rclient = tPresence.ControllingClient;
+ if (rclient!=null) {
+ client = rclient;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return client;
+ }
+
+
+ private Scene GetLocateScene(UUID AgentId)
+ {
+ Scene scene = null;
+
+ lock (m_sceneList) {
+ if (m_sceneList.Count>0) {
+ foreach (Scene _scene in m_sceneList.Values) {
+ ScenePresence tPresence = (ScenePresence)_scene.GetScenePresence(AgentId);
+ if (tPresence!=null && !tPresence.IsChildAgent) {
+ scene = _scene;
+ break;
+ }
+ }
+ }
+ }
+
+ return scene;
+ }
+
+
+ private SceneObjectPart GetLocatePrim(UUID objectID)
+ {
+ SceneObjectPart sceneObj = null;
+
+ lock (m_sceneList) {
+ if (m_sceneList.Count>0) {
+ foreach (Scene _scene in m_sceneList.Values) {
+ SceneObjectPart part = (SceneObjectPart)_scene.GetSceneObjectPart(objectID);
+ if (part!=null) {
+ sceneObj = part;
+ break;
+ }
+ }
+ }
+ }
+
+ return sceneObj;
+ }
+
+ #endregion
+ }
+
+}
diff --git a/source/ThirdParty/OpenSim.Modules.Currency/NSLCertificateTools.cs b/source/ThirdParty/OpenSim.Modules.Currency/NSLCertificateTools.cs
new file mode 100644
index 0000000..db0008c
--- /dev/null
+++ b/source/ThirdParty/OpenSim.Modules.Currency/NSLCertificateTools.cs
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) Contributors, http://www.nsl.tuis.ac.jp
+ *
+ */
+
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Xml;
+using System.Net;
+using System.Net.Security;
+using System.Text;
+using System.Reflection;
+using System.Security.Cryptography.X509Certificates;
+
+using log4net;
+
+
+namespace NSL.Certificate.Tools
+{
+ //
+ public class NSLCertificateVerify
+ {
+ private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
+ private X509Chain m_chain = null;
+ private X509Certificate2 m_cacert = null;
+
+ private Mono.Security.X509.X509Crl m_clientcrl = null;
+
+
+ public NSLCertificateVerify()
+ {
+ m_chain = null;
+ m_cacert = null;
+ m_clientcrl = null;
+ }
+
+
+ public NSLCertificateVerify(string certfile)
+ {
+ SetPrivateCA(certfile);
+ }
+
+
+ public NSLCertificateVerify(string certfile, string crlfile)
+ {
+ SetPrivateCA (certfile);
+ SetPrivateCRL(crlfile);
+ }
+
+
+ public void SetPrivateCA(string certfile)
+ {
+ try {
+ m_cacert = new X509Certificate2(certfile);
+ }
+ catch (Exception ex)
+ {
+ m_cacert = null;
+ m_log.ErrorFormat("[SET PRIVATE CA]: CA File reading error [{0}]. {1}", certfile, ex);
+ }
+
+ if (m_cacert!=null) {
+ m_chain = new X509Chain();
+ m_chain.ChainPolicy.ExtraStore.Add(m_cacert);
+ m_chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
+ m_chain.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag;
+ }
+ }
+
+
+ public void SetPrivateCRL(string crlfile)
+ {
+ try {
+ m_clientcrl = Mono.Security.X509.X509Crl.CreateFromFile(crlfile);
+ }
+ catch (Exception ex)
+ {
+ m_clientcrl = null;
+ m_log.ErrorFormat("[SET PRIVATE CRL]: CRL File reading error [{0}]. {1}", crlfile, ex);
+ }
+ }
+
+
+ //
+ //
+ //
+ public bool CheckPrivateChain(X509Certificate2 cert)
+ {
+ if (m_chain==null || m_cacert==null) {
+ return false;
+ }
+
+ bool ret = m_chain.Build((X509Certificate2)cert);
+ if (ret) {
+ return true;
+ }
+
+ for (int i=0; i
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/source/bin/MoneyServer.ini b/source/bin/MoneyServer.ini
new file mode 100644
index 0000000..f439360
--- /dev/null
+++ b/source/bin/MoneyServer.ini
@@ -0,0 +1,99 @@
+[Startup]
+;
+; Place to create a PID file
+; PIDFile = "/tmp/money.pid"
+
+
+[MySql]
+;
+;Connection parameters of MySQL
+hostname = localhost ; Name of MySQL Server
+database = opensim_db
+username = opensim_user
+password = opensim_pass
+
+pooling = false
+port = 3306
+
+;
+; Max DB connections kept by money server.
+MaxConnection = 50
+
+
+[MoneyServer]
+;
+; If the user is not found in database,he/she will be created with the default balance.
+DefaultBalance = 1000
+
+;
+; Is amount==0 transaction enable? Default is false.
+EnableAmountZero = true
+
+;
+; If "00000000-0000-0000-0000-000000000000" is specified, all avatars can get money from system.
+; If "" is specified, nobody can get money.
+BankerAvatar = ""
+
+;
+; If you want to use llGiveMoney() function normally even when payer doesn't login to OpenSim,
+; please set true to this valiable
+EnableForceTransfer = true
+
+;
+; Send/Move money to/from avatar by Money Script
+;EnableScriptSendMoney = false
+;MoneyScriptAccessKey = "123456789" ;; Specify same secret key in include/config.php or WI(XoopenSim/Modlos)
+;MoneyScriptIPaddress = "202.26.159.139" ;; Not use 127.0.0.1. This is used to generate Script key
+
+;
+; for HG/Guest Avatar. Foreign Avatar is always false
+EnableHGAvatar = true
+EnableGuestAvatar = true
+HGAvatarDefaultBalance = 1000
+GuestAvatarDefaultBalance = 1000
+
+;
+; Message that displayed in blue dialog, when balance is updated.
+; If "" is specified, blue dialog is not displayed.
+; You can use {0} and {1} in message string.
+; {0} means amount and {1} means avatar name or object owner name.
+BalanceMessageSendGift = "Sent Gift L${0} to {1}." ;; for send gift to other avatar
+BalanceMessageReceiveGift = "Received Gift L${0} from {1}." ;; for receieve gift from other avatar
+BalanceMessagePayCharge = "" ;; for upload and group creation charge
+BalanceMessageBuyObject = "Bought the Object {2} from {1} by L${0}." ;; for buy the object
+BalanceMessageSellObject = "{1} bought the Object {2} by L${0}." ;; for sell the object
+BalanceMessageLandSale = "Paid the Money L${0} for Land." ;; for buy the land
+BalanceMessageScvLandSale = "" ;; for get the money of the sold land
+BalanceMessageGetMoney = "Got the Money L${0} from {1}." ;; for get the money from object by llGiveMoney()
+BalanceMessageBuyMoney = "Bought the Money L${0}." ;; for buy the money from system
+BalanceMessageRollBack = "RollBack the Transaction: L${0} from/to {1}.";; when roll back ocuurred
+BalanceMessageSendMoney = "Paid the Money L${0} to {1}." ;; for sender of sending the money
+BalanceMessageReceiveMoney = "Received L${0} from {1}." ;; for receive the money
+
+
+[Certificate]
+;
+; Certification Configuration
+;
+
+; CA Cert to check Client/Server Cert
+;CACertFilename = "cacert.crt"
+
+;
+; HTTPS Server Cert (Server Mode)
+;ServerCertFilename = "SineWaveCert.pfx"
+;ServerCertPassword = "123"
+;ServerCertFilename = "server_cert.p12"
+;ServerCertPassword = ""
+
+; Client Authentication from Region Server
+;CheckClientCert = false ;; check Region Server
+;ClientCrlFilename = "clcrl.crt"
+
+
+;
+; XML RPC to Region Server (Client Mode)
+;;CheckServerCert = false ;; check Region Server
+;;ClientCertFilename = "client_cert.p12"
+;;ClientCertPassword = ""
+
diff --git a/source/bin/OpenSim.ini.sample b/source/bin/OpenSim.ini.sample
new file mode 100644
index 0000000..c932f78
--- /dev/null
+++ b/source/bin/OpenSim.ini.sample
@@ -0,0 +1,43 @@
+[Economy]
+
+ ;; Enables selling things for $0. Default is true.
+ SellEnabled = true
+
+ ;CurrencyServer = "" ;; ex.) "https://jogrid.net:8008/" Default is ""
+ EconomyModule = DTLNSLMoneyModule
+
+ ;
+ ;; CA
+ ;CheckServerCert = false
+ ;CACertFilename = "cacert.crt"
+
+ ;
+ ;; Client Cert
+ ;ClientCertFilename = "region_cert.p12"
+ ;ClientCertPassword = ""
+
+ ;
+ ;; Money Unit fee to upload textures, animations etc. Default is 0.
+ PriceUpload = 0
+
+ ;; Mesh upload factors
+ ;MeshModelUploadCostFactor = 0.0
+ ;MeshModelUploadTextureCostFactor = 1.0
+ ;MeshModelMinCostFactor = 0.0
+
+ ;; Money Unit fee to create groups. Default is 0.
+ PriceGroupCreate = 0
+
+ ;
+ ;; Avatar Class for HG Avatar
+ ;; {ForeignAvatar, HGAvatar, GuestAvatar, LocalAvatar} HGAvatar
+ ;; HG Avatar is assumed as a specified avatar class. Default is HGAvatar
+ ;; Processing for each avatar class is dependent on Money Server settings.
+ ;HGAvatarAs = "HGAvatar"
+
+ ;
+ ;; in development
+ ;SettlementByWeb = false
+ ;SettlementURL = "http://www.jogrid.net"
+ ;SettlementMessage = "Goto the settlement of accounts Web page. (Testing now)"
+
diff --git a/source/bin/README.md b/source/bin/README.md
new file mode 100644
index 0000000..0d65386
--- /dev/null
+++ b/source/bin/README.md
@@ -0,0 +1 @@
+# Copy this to /opensim/bin
diff --git a/source/bin/SineWaveCert.pfx b/source/bin/SineWaveCert.pfx
new file mode 100644
index 0000000..11c8ae5
Binary files /dev/null and b/source/bin/SineWaveCert.pfx differ
diff --git a/source/bin/server_cert.p12 b/source/bin/server_cert.p12
new file mode 100644
index 0000000..16adb01
Binary files /dev/null and b/source/bin/server_cert.p12 differ
diff --git a/source/money-prebuild.xml b/source/money-prebuild.xml
new file mode 100644
index 0000000..e158440
--- /dev/null
+++ b/source/money-prebuild.xml
@@ -0,0 +1,141 @@
+
+
+
+
+ ../../bin/
+
+
+
+
+ ../../bin/
+
+
+
+ ../../bin/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ../../bin/
+
+
+
+
+ ../../bin/
+
+
+
+ ../../bin/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ../../bin/
+
+
+
+
+ ../../bin/
+
+
+
+ ../../bin/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/source/patch-old-archive/DTLNSLMoneyModule-NPC.patch b/source/patch-old-archive/DTLNSLMoneyModule-NPC.patch
new file mode 100644
index 0000000..b81fc0e
--- /dev/null
+++ b/source/patch-old-archive/DTLNSLMoneyModule-NPC.patch
@@ -0,0 +1,26 @@
+---------------------------------------------------------------------
+--- DTLNSLMoneyModule.cs.ori 2020-01-16 11:40:31.320753823 +0100
++++ DTLNSLMoneyModule.cs 2020-01-16 11:39:54.717394571 +0100
+@@ -1638,8 +1638,10 @@
+ avatarType = (int)AvatarType.NPC_AVATAR;
+ }
+ //
+- if ((agent.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin)!=0 || String.IsNullOrEmpty(userName)) {
+- avatarType = (int)AvatarType.HG_AVATAR;
++ if (!isNpc) {
++ if ((agent.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin)!=0 || String.IsNullOrEmpty(userName)) {
++ avatarType = (int)AvatarType.HG_AVATAR;
++ }
+ }
+ }
+ if (String.IsNullOrEmpty(userName)) {
+@@ -1648,7 +1650,7 @@
+
+ //
+ avatarClass = avatarType;
+- if (avatarType==(int)AvatarType.NPC_AVATAR) return false;
++ if (avatarType==(int)AvatarType.NPC_AVATAR) return true;
+ if (avatarType==(int)AvatarType.HG_AVATAR) avatarClass = m_hg_avatarClass;
+
+ //
+---------------------------------------------------------------------
\ No newline at end of file
diff --git a/source/patch-old-archive/opensim-0.9.0.patch b/source/patch-old-archive/opensim-0.9.0.patch
new file mode 100644
index 0000000..8e9ebeb
--- /dev/null
+++ b/source/patch-old-archive/opensim-0.9.0.patch
@@ -0,0 +1,46 @@
+diff -Nur OpenSim-/Framework/Servers/HttpServer/BaseHttpServer.cs OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
+--- OpenSim-/Framework/Servers/HttpServer/BaseHttpServer.cs 2018-04-22 14:34:37.642698003 +0900
++++ OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs 2018-04-22 14:35:35.331826307 +0900
+@@ -1094,6 +1094,10 @@
+
+ if (gridproxy)
+ xmlRprcRequest.Params.Add("gridproxy"); // Param[4]
++
++ // by Fumi.Iseki for DTLNSLMoneyServer
++ xmlRprcRequest.Params.Add(request.IHttpClientContext.SSLCommonName); // Param[4] or Param[5]
++
+ try
+ {
+ xmlRpcResponse = method(xmlRprcRequest, request.RemoteIPEndPoint);
+diff -Nur OpenSim-/Framework/Servers/Tests/OSHttpTests.cs OpenSim/Framework/Servers/Tests/OSHttpTests.cs
+--- OpenSim-/Framework/Servers/Tests/OSHttpTests.cs 2018-04-22 14:34:37.643698006 +0900
++++ OpenSim/Framework/Servers/Tests/OSHttpTests.cs 2018-04-22 14:35:35.331826307 +0900
+@@ -62,6 +62,12 @@
+ _secured = secured;
+ }
+
++ // by Fumi.Iseki for DTLNSLMoenyServer
++ public string SSLCommonName
++ {
++ get { return "";}
++ }
++
+ public void Disconnect(SocketError error) {}
+ public void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body) {}
+ public void Respond(string httpVersion, HttpStatusCode statusCode, string reason) {}
+diff -Nur OpenSim-/Tests/Common/Mock/TestHttpClientContext.cs OpenSim/Tests/Common/Mock/TestHttpClientContext.cs
+--- OpenSim-/Tests/Common/Mock/TestHttpClientContext.cs 2018-04-22 14:34:37.643698006 +0900
++++ OpenSim/Tests/Common/Mock/TestHttpClientContext.cs 2018-04-22 14:35:35.332826313 +0900
+@@ -72,6 +72,12 @@
+ // Console.WriteLine("TestHttpClientContext.Disconnect Received disconnect with status {0}", error);
+ }
+
++ // by Fumi.Iseki for DTLNSLMoenyServer
++ public string SSLCommonName
++ {
++ get { return "";}
++ }
++
+ public void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body) {Console.WriteLine("x");}
+ public void Respond(string httpVersion, HttpStatusCode statusCode, string reason) {Console.WriteLine("xx");}
+ public void Respond(string body) { Console.WriteLine("xxx");}
diff --git a/source/patch-old-archive/opensim-0.9.1.patch b/source/patch-old-archive/opensim-0.9.1.patch
new file mode 100644
index 0000000..e803d15
--- /dev/null
+++ b/source/patch-old-archive/opensim-0.9.1.patch
@@ -0,0 +1,15 @@
+diff -Nur OpenSim-/Framework/Servers/HttpServer/BaseHttpServer.cs OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
+--- OpenSim-/Framework/Servers/HttpServer/BaseHttpServer.cs 2019-02-13 17:07:00.037657561 +0900
++++ OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs 2019-02-13 17:29:49.371393303 +0900
+@@ -158,6 +158,11 @@
+ m_port = port;
+ }
+
++ public RemoteCertificateValidationCallback CertificateValidationCallback
++ {
++ set { m_certificateValidationCallback = value; }
++ }
++
+ private void load_cert(string CPath, string CPass)
+ {
+ try