/**
	 * Fetch latest version and licensing information from versions server
	 *
	 * @param  boolean     $detailed  Gives detailed latest version description ?
	 * @return array|NULL             errorText  NULL if the key record could be fetched and stored, otherwise major error string
	 */
	public function fetchVersion( $detailed = false ) {
		global $_CB_framework;

		$return							=	null;
		if ( ! isset( $this->responses[$detailed] ) ) {
			$cbsubsVersion				=	explode( ' ', cbpaidApp::version() );
			$this->version				=	$cbsubsVersion[0];
			$this->versionminor			=	( isset( $cbsubsVersion[1] ) ? $cbsubsVersion[1] : '' );

			$formvars		=	array(	'task'					=>	'version',
										'type'					=>	'3',
										'version'				=>	'300',
										'product'				=>	$this->product,
										'productversion'		=>	$this->version,
										'productversionminor'	=>	$this->versionminor,
										'lang'					=>	$_CB_framework->getCfg( 'lang_tag' ),
										'info'					=>	( $detailed ? 'latestversiondetailed' : 'latestversionsummary' )
			);
			$random						=	sprintf( '%08x', mt_rand() );
			$formvars['sign']			=	$random . '-' . md5( $random . implode( '&', $formvars ) );

			$result						=	null;
			$status						=	null;
			$timeout					=	90;
			$live_site					=	$_CB_framework->getCfg( 'live_site' );
			$error						=	cbpaidWebservices::httpsRequest( $this->url, $formvars, $timeout, $result, $status, 'post', 'normal', '*/*', $this->https, $this->port, '', '', false, $live_site );

			$this->responses[$detailed]	=	array();
			if ($error || ( $status != 200) ) {
				$return					=	CBPTXT::T("Connection to update server failed") . ': ' . CBPTXT::T("Error") . ': ' . $error . ($status == -100 ? CBPTXT::T("Timeout") : $status);
			} else {
				$resultArray			=	explode( '-', $result );
				if ( count( $resultArray ) == 3 ) {
					$md5hash			=	md5( $resultArray[1] . $resultArray[0] );
					if ( $md5hash == $resultArray[2] ) {
						$result			=	base64_decode( $resultArray[0] );
						$arr			=	explode( '&', $result );
						$this->responses[$detailed]						=	array();
						foreach ( $arr as $v ) {
							$parts										=	explode( '=', $v );
							if ( count( $parts ) == 2 ) {
								$this->responses[$detailed][$parts[0]]	=	rawurldecode( $parts[1] );
							}
						}
						$return			=	null;
					} else {
						$return			=	CBPTXT::T("Hash mismatch");
					}
				} else {
					// echo $result;
					$return				=	CBPTXT::T("Malformed version server response");	// . $result;
				}
			}
		}
		if ( $return === null ) {
			return $this->responses[$detailed];
		}
		return $return;
	}
 /**
  * Posts a POST form by https if available, otherwise by http and gets result.
  *
  * @param  string  $urlNoHttpsPrefix  URL without https:// in front (but works also with http:// or https:// in front, but it's ignored.
  * @param  array|string  $formvars          Variables in form to post
  * @param  int     $timeout           Timeout of the access
  * @param  string  $result            RETURNING: the fetched access
  * @param  int     $status            RETURNING: the status of the access (e.g. 200 is normal)
  * @param  string  $getPostType       'post' (default) or 'get'
  * @param  string  $contentType       'normal' (default) or 'xml' ($formvars['xml']=xml content) or 'json' (application/json)
  * @param  string  $acceptType        '* / *' (default) or 'application/xml' or 'application/json'
  * @param  boolean $https             SSL protocol (default: true)
  * @param  int     $port              port number (default: 443)
  * @param  string  $username          HTTP username authentication
  * @param  string  $password          HTTP password authentication
  * @param  boolean $allowHttpFallback Allow fallback to http if https not available locally (default: false)
  * @param  string  $referer           referrer
  * @return int     $error             error-code of access (0 for ok)
  */
 protected function _httpsRequest($urlNoHttpsPrefix, $formvars, $timeout, &$result, &$status, $getPostType = 'post', $contentType = 'normal', $acceptType = '*/*', $https = true, $port = 443, $username = '', $password = '', $allowHttpFallback = false, $referer = null)
 {
     return cbpaidWebservices::httpsRequest($urlNoHttpsPrefix, $formvars, $timeout, $result, $status, $getPostType, $contentType, $acceptType, $https, $port, $username, $password, $allowHttpFallback, $referer);
 }
	/**
	 * Calls PayPal API on an NVP basis
	 *
	 * @param  array          $specificVars  Request vars (beyond API credentials)
	 * @return array|boolean                 Results if array, FALSE: error (logged)
	 */
	protected function callAPI( $specificVars )
	{
		$formvars					=	array_merge( $this->apiCredentials, $specificVars );

		//Send the XML via curl:
		$response					=	null;
		$status						=	null;
		$error						=	cbpaidWebservices::httpsRequest( $this->apiUrl, $formvars, 105, $response, $status, 'post', 'normal' );
		if( $error || ( $status != 200 ) || ! $response ) {
			// Error, log it:
			$this->setError( 3, null, 'Paypal API: Error ' . $error . ' Status ' . $status . ': could not reach Paypal API gateway at ' . $this->apiUrl . '.', CBPTXT::T("Paypal API gateway could not be reached.") . ' ' . CBPTXT::T("Please ask administrator to check his error log for details.") );
			return false;
		} else {
			// API call success:
			$results				=	array();
			parse_str( $response, $results );
			//?	foreach ( $results as &$v ) {
			//?		$v		=	urldecode( $v );
			//?	}

			// Remove sensitive data from raw logs:
			$formvars['USER']		=	'******';
			$formvars['PWD']		=	'PWD';
			$formvars['SIGNATURE']	=	'SIGNATURE';
			// Log raw data:
			$this->setRawLogData( $formvars, $results );
			return $results;
		}
		
	}