]> git.mxchange.org Git - friendica-addons.git/blobdiff - pumpio/oauth/oauth_client.php
pumpio: New plugin to post to pump.io servers
[friendica-addons.git] / pumpio / oauth / oauth_client.php
diff --git a/pumpio/oauth/oauth_client.php b/pumpio/oauth/oauth_client.php
new file mode 100644 (file)
index 0000000..5047e0e
--- /dev/null
@@ -0,0 +1,2176 @@
+<?php
+/*
+ * oauth_client.php
+ *
+ * @(#) $Id: oauth_client.php,v 1.58 2013/04/11 09:33:16 mlemos Exp $
+ *
+ */
+
+/*
+{metadocument}<?xml version="1.0" encoding="ISO-8859-1" ?>
+<class>
+
+       <package>net.manuellemos.oauth</package>
+
+       <version>@(#) $Id: oauth_client.php,v 1.58 2013/04/11 09:33:16 mlemos Exp $</version>
+       <copyright>Copyright © (C) Manuel Lemos 2012</copyright>
+       <title>OAuth client</title>
+       <author>Manuel Lemos</author>
+       <authoraddress>mlemos-at-acm.org</authoraddress>
+
+       <documentation>
+               <idiom>en</idiom>
+               <purpose>This class serves two main purposes:<paragraphbreak />
+                       1) Implement the OAuth protocol to retrieve a token from a server to
+                       authorize the access to an API on behalf of the current
+                       user.<paragraphbreak />
+                       2) Perform calls to a Web services API using a token previously
+                       obtained using this class or a token provided some other way by the
+                       Web services provider.</purpose>
+               <usage>Regardless of your purposes, you always need to start calling
+                       the class <functionlink>Initialize</functionlink> function after
+                       initializing setup variables. After you are done with the class,
+                       always call the <functionlink>Finalize</functionlink> function at
+                       the end.<paragraphbreak />
+                       This class supports either OAuth protocol versions 1.0, 1.0a and
+                       2.0. It abstracts the differences between these protocol versions,
+                       so the class usage is the same independently of the OAuth
+                       version of the server.<paragraphbreak />
+                       The class also provides built-in support to several popular OAuth
+                       servers, so you do not have to manually configure all the details to
+                       access those servers. Just set the
+                       <variablelink>server</variablelink> variable to configure the class
+                       to access one of the built-in supported servers.<paragraphbreak />
+                       If you need to access one type of server that is not yet directly
+                       supported by the class, you need to configure it explicitly setting
+                       the variables: <variablelink>oauth_version</variablelink>,
+                       <variablelink>url_parameters</variablelink>,
+                       <variablelink>authorization_header</variablelink>,
+                       <variablelink>request_token_url</variablelink>,
+                       <variablelink>dialog_url</variablelink>,
+                       <variablelink>offline_dialog_url</variablelink>,
+                       <variablelink>append_state_to_redirect_uri</variablelink> and
+                       <variablelink>access_token_url</variablelink>.<paragraphbreak />
+                       Before proceeding to the actual OAuth authorization process, you
+                       need to have registered your application with the OAuth server. The
+                       registration provides you values to set the variables
+                       <variablelink>client_id</variablelink> and 
+                       <variablelink>client_secret</variablelink>.<paragraphbreak />
+                       You also need to set the variables
+                       <variablelink>redirect_uri</variablelink> and
+                       <variablelink>scope</variablelink> before calling the
+                       <functionlink>Process</functionlink> function to make the class
+                       perform the necessary interactions with the OAuth
+                       server.<paragraphbreak />
+                       The OAuth protocol involves multiple steps that include redirection
+                       to the OAuth server. There it asks permission to the current user to
+                       grant your application access to APIs on his/her behalf. When there
+                       is a redirection, the class will set the
+                       <variablelink>exit</variablelink> variable to
+                       <booleanvalue>1</booleanvalue>. Then your script should exit
+                       immediately without outputting anything.<paragraphbreak />
+                       When the OAuth access token is successfully obtained, the following
+                       variables are set by the class with the obtained values:
+                       <variablelink>access_token</variablelink>,
+                       <variablelink>access_token_secret</variablelink>,
+                       <variablelink>access_token_expiry</variablelink>,
+                       <variablelink>access_token_type</variablelink>. You may want to
+                       store these values to use them later when calling the server
+                       APIs.<paragraphbreak />
+                       If there was a problem during OAuth authorization process, check the
+                       variable <variablelink>authorization_error</variablelink> to
+                       determine the reason.<paragraphbreak />
+                       Once you get the access token, you can call the server APIs using
+                       the <functionlink>CallAPI</functionlink> function. Check the
+                       <variablelink>access_token_error</variablelink> variable to
+                       determine if there was an error when trying to to call the
+                       API.<paragraphbreak />
+                       If for some reason the user has revoked the access to your
+                       application, you need to ask the user to authorize your application
+                       again. First you may need to call the function
+                       <functionlink>ResetAccessToken</functionlink> to reset the value of
+                       the access token that may be cached in session variables.</usage>
+       </documentation>
+
+{/metadocument}
+*/
+
+class oauth_client_class
+{
+/*
+{metadocument}
+       <variable>
+               <name>error</name>
+               <type>STRING</type>
+               <value></value>
+               <documentation>
+                       <purpose>Store the message that is returned when an error
+                               occurs.</purpose>
+                       <usage>Check this variable to understand what happened when a call to
+                               any of the class functions has failed.<paragraphbreak />
+                               This class uses cumulative error handling. This means that if one
+                               class functions that may fail is called and this variable was
+                               already set to an error message due to a failure in a previous call
+                               to the same or other function, the function will also fail and does
+                               not do anything.<paragraphbreak />
+                               This allows programs using this class to safely call several
+                               functions that may fail and only check the failure condition after
+                               the last function call.<paragraphbreak />
+                               Just set this variable to an empty string to clear the error
+                               condition.</usage>
+               </documentation>
+       </variable>
+{/metadocument}
+*/
+       var $error = '';
+
+/*
+{metadocument}
+       <variable>
+               <name>debug</name>
+               <type>BOOLEAN</type>
+               <value>0</value>
+               <documentation>
+                       <purpose>Control whether debug output is enabled</purpose>
+                       <usage>Set this variable to <booleanvalue>1</booleanvalue> if you
+                               need to check what is going on during calls to the class. When
+                               enabled, the debug output goes either to the variable
+                               <variablelink>debug_output</variablelink> and the PHP error log.</usage>
+               </documentation>
+       </variable>
+{/metadocument}
+*/
+       var $debug = false;
+
+/*
+{metadocument}
+       <variable>
+               <name>debug_http</name>
+               <type>BOOLEAN</type>
+               <value>0</value>
+               <documentation>
+                       <purpose>Control whether the dialog with the remote Web server
+                               should also be logged.</purpose>
+                       <usage>Set this variable to <booleanvalue>1</booleanvalue> if you
+                               want to inspect the data exchange with the OAuth server.</usage>
+               </documentation>
+       </variable>
+{/metadocument}
+*/
+       var $debug_http = false;
+
+/*
+{metadocument}
+       <variable>
+               <name>exit</name>
+               <type>BOOLEAN</type>
+               <value>0</value>
+               <documentation>
+                       <purpose>Determine if the current script should be exited.</purpose>
+                       <usage>Check this variable after calling the
+                               <functionlink>Process</functionlink> function and exit your script
+                               immediately if the variable is set to
+                               <booleanvalue>1</booleanvalue>.</usage>
+               </documentation>
+       </variable>
+{/metadocument}
+*/
+       var $exit = false;
+
+/*
+{metadocument}
+       <variable>
+               <name>debug_output</name>
+               <type>STRING</type>
+               <value></value>
+               <documentation>
+                       <purpose>Capture the debug output generated by the class</purpose>
+                       <usage>Inspect this variable if you need to see what happened during
+                               the class function calls.</usage>
+               </documentation>
+       </variable>
+{/metadocument}
+*/
+       var $debug_output = '';
+
+/*
+{metadocument}
+       <variable>
+               <name>debug_prefix</name>
+               <type>STRING</type>
+               <value>OAuth client: </value>
+               <documentation>
+                       <purpose>Mark the lines of the debug output to identify actions
+                               performed by this class.</purpose>
+                       <usage>Change this variable if you prefer the debug output lines to
+                               be prefixed with a different text.</usage>
+               </documentation>
+       </variable>
+{/metadocument}
+*/
+       var $debug_prefix = 'OAuth client: ';
+
+/*
+{metadocument}
+       <variable>
+               <name>server</name>
+               <type>STRING</type>
+               <value></value>
+               <documentation>
+                       <purpose>Identify the type of OAuth server to access.</purpose>
+                       <usage>The class provides built-in support to several types of OAuth
+                               servers. This means that the class can automatically initialize
+                               several configuration variables just by setting this server
+                               variable.<paragraphbreak />
+                               Currently it supports the following servers:
+                               <stringvalue>Bitbucket</stringvalue>,
+                               <stringvalue>Box</stringvalue>,
+                               <stringvalue>Dropbox</stringvalue>,
+                               <stringvalue>Eventful</stringvalue>,
+                               <stringvalue>Facebook</stringvalue>,
+                               <stringvalue>Fitbit</stringvalue>,
+                               <stringvalue>Flickr</stringvalue>,
+                               <stringvalue>Foursquare</stringvalue>,
+                               <stringvalue>github</stringvalue>,
+                               <stringvalue>Google</stringvalue>,
+                               <stringvalue>Instagram</stringvalue>,
+                               <stringvalue>LinkedIn</stringvalue>,
+                               <stringvalue>Microsoft</stringvalue>,
+                               <stringvalue>Scoop.it</stringvalue>,
+                               <stringvalue>StockTwits</stringvalue>,
+                               <stringvalue>Tumblr</stringvalue>,
+                               <stringvalue>Twitter</stringvalue>,
+                               <stringvalue>XING</stringvalue> and
+                               <stringvalue>Yahoo</stringvalue>. Please contact the author if you
+                               would like to ask to add built-in support for other types of OAuth
+                               servers.<paragraphbreak />
+                               If you want to access other types of OAuth servers that are not
+                               yet supported, set this variable to an empty string and configure
+                               other variables with values specific to those servers.</usage>
+               </documentation>
+       </variable>
+{/metadocument}
+*/
+       var $server = '';
+
+/*
+{metadocument}
+       <variable>
+               <name>request_token_url</name>
+               <type>STRING</type>
+               <value></value>
+               <documentation>
+                       <purpose>URL of the OAuth server to request the initial token for
+                               OAuth 1.0 and 1.0a servers.</purpose>
+                       <usage>Set this variable to the OAuth request token URL when you are
+                               not accessing one of the built-in supported OAuth
+                               servers.<paragraphbreak />
+                               For OAuth 1.0 and 1.0a servers, the request token URL can have
+                               certain marks that will act as template placeholders which will be
+                               replaced with given values before requesting the authorization
+                               token. Currently it supports the following placeholder
+                               marks:<paragraphbreak />
+                               {SCOPE} - scope of the requested permissions to the granted by the
+                               OAuth server with the user permissions</usage>
+               </documentation>
+       </variable>
+{/metadocument}
+*/
+       var $request_token_url = '';
+
+/*
+{metadocument}
+       <variable>
+               <name>dialog_url</name>
+               <type>STRING</type>
+               <value></value>
+               <documentation>
+                       <purpose>URL of the OAuth server to redirect the browser so the user
+                               can grant access to your application.</purpose>
+                       <usage>Set this variable to the OAuth request token URL when you are
+                               not accessing one of the built-in supported OAuth servers.<paragraphbreak />
+                               For certain servers, the dialog URL can have certain marks that
+                               will act as template placeholders which will be replaced with
+                               values defined before redirecting the users browser. Currently it
+                               supports the following placeholder marks:<paragraphbreak />
+                               {REDIRECT_URI} - URL to redirect when returning from the OAuth
+                               server authorization page<paragraphbreak />
+                               {CLIENT_ID} - client application identifier registered at the
+                               server<paragraphbreak />
+                               {SCOPE} - scope of the requested permissions to the granted by the
+                               OAuth server with the user permissions<paragraphbreak />
+                               {STATE} - identifier of the OAuth session state</usage>
+               </documentation>
+       </variable>
+{/metadocument}
+*/
+       var $dialog_url = '';
+
+/*
+{metadocument}
+       <variable>
+               <name>offline_dialog_url</name>
+               <type>STRING</type>
+               <value></value>
+               <documentation>
+                       <purpose>URL of the OAuth server to redirect the browser so the user
+                               can grant access to your application when offline access is
+                               requested.</purpose>
+                       <usage>Set this variable to the OAuth request token URL when you are
+                               not accessing one of the built-in supported OAuth servers and the
+                               OAuth server supports offline access.<paragraphbreak />
+                               It should have the same format as the
+                               <variablelink>dialog_url</variablelink> variable.</usage>
+               </documentation>
+       </variable>
+{/metadocument}
+*/
+       var $offline_dialog_url = '';
+
+/*
+{metadocument}
+       <variable>
+               <name>append_state_to_redirect_uri</name>
+               <type>STRING</type>
+               <value></value>
+               <documentation>
+                       <purpose>Pass the OAuth session state in a variable with a different
+                               name to work around implementation bugs of certain OAuth
+                               servers</purpose>
+                       <usage>Set this variable  when you are not accessing one of the
+                               built-in supported OAuth servers if the OAuth server has a bug
+                               that makes it not pass back the OAuth state identifier in a
+                               request variable named state.</usage>
+               </documentation>
+       </variable>
+{/metadocument}
+*/
+       var $append_state_to_redirect_uri = '';
+
+/*
+{metadocument}
+       <variable>
+               <name>access_token_url</name>
+               <type>STRING</type>
+               <value></value>
+               <documentation>
+                       <purpose>OAuth server URL that will return the access token
+                               URL.</purpose>
+                       <usage>Set this variable to the OAuth access token URL when you are
+                               not accessing one of the built-in supported OAuth servers.</usage>
+               </documentation>
+       </variable>
+{/metadocument}
+*/
+       var $access_token_url = '';
+
+
+/*
+{metadocument}
+       <variable>
+               <name>oauth_version</name>
+               <type>STRING</type>
+               <value>2.0</value>
+               <documentation>
+                       <purpose>Version of the protocol version supported by the OAuth
+                               server.</purpose>
+                       <usage>Set this variable to the OAuth server protocol version when
+                               you are not accessing one of the built-in supported OAuth
+                               servers.</usage>
+               </documentation>
+       </variable>
+{/metadocument}
+*/
+       var $oauth_version = '2.0';
+
+/*
+{metadocument}
+       <variable>
+               <name>url_parameters</name>
+               <type>BOOLEAN</type>
+               <value>0</value>
+               <documentation>
+                       <purpose>Determine if the API call parameters should be moved to the
+                               call URL.</purpose>
+                       <usage>Set this variable to <booleanvalue>1</booleanvalue> if the
+                               API you need to call requires that the call parameters always be
+                               passed via the API URL.</usage>
+               </documentation>
+       </variable>
+{/metadocument}
+*/
+       var $url_parameters = false;
+
+/*
+{metadocument}
+       <variable>
+               <name>authorization_header</name>
+               <type>BOOLEAN</type>
+               <value>1</value>
+               <documentation>
+                       <purpose>Determine if the OAuth parameters should be passed via HTTP
+                               Authorization request header.</purpose>
+                       <usage>Set this variable to <booleanvalue>1</booleanvalue> if the
+                               OAuth server requires that the OAuth parameters be passed using
+                               the HTTP Authorization instead of the request URI parameters.</usage>
+               </documentation>
+       </variable>
+{/metadocument}
+*/
+       var $authorization_header = true;
+
+/*
+{metadocument}
+       <variable>
+               <name>token_request_method</name>
+               <type>STRING</type>
+               <value>GET</value>
+               <documentation>
+                       <purpose>Define the HTTP method that should be used to request
+                               tokens from the server.</purpose>
+                       <usage>Set this variable to <stringvalue>POST</stringvalue> if the
+                               OAuth server does not support requesting tokens using the HTTP GET
+                               method.</usage>
+               </documentation>
+       </variable>
+{/metadocument}
+*/
+       var $token_request_method = 'GET';
+
+/*
+{metadocument}
+       <variable>
+               <name>signature_method</name>
+               <type>STRING</type>
+               <value>HMAC-SHA1</value>
+               <documentation>
+                       <purpose>Define the method to generate the signature for API request
+                               parameters values.</purpose>
+                       <usage>Currently it supports <stringvalue>PLAINTEXT</stringvalue>
+                               and <stringvalue>HMAC-SHA1</stringvalue>.</usage>
+               </documentation>
+       </variable>
+{/metadocument}
+*/
+       var $signature_method = 'HMAC-SHA1';
+
+/*
+{metadocument}
+       <variable>
+               <name>redirect_uri</name>
+               <type>STRING</type>
+               <value></value>
+               <documentation>
+                       <purpose>URL of the current script page that is calling this
+                               class</purpose>
+                       <usage>Set this variable to the current script page URL before
+                               proceeding the the OAuth authorization process.</usage>
+               </documentation>
+       </variable>
+{/metadocument}
+*/
+       var $redirect_uri = '';
+
+/*
+{metadocument}
+       <variable>
+               <name>client_id</name>
+               <type>STRING</type>
+               <value></value>
+               <documentation>
+                       <purpose>Identifier of your application registered with the OAuth
+                               server</purpose>
+                       <usage>Set this variable to the application identifier that is
+                               provided by the OAuth server when you register the
+                               application.</usage>
+               </documentation>
+       </variable>
+{/metadocument}
+*/
+       var $client_id = '';
+
+/*
+{metadocument}
+       <variable>
+               <name>client_secret</name>
+               <type>STRING</type>
+               <value></value>
+               <documentation>
+                       <purpose>Secret value assigned to your application when it is
+                               registered with the OAuth server.</purpose>
+                       <usage>Set this variable to the application secret that is provided
+                               by the OAuth server when you register the application.</usage>
+               </documentation>
+       </variable>
+{/metadocument}
+*/
+       var $client_secret = '';
+
+/*
+{metadocument}
+       <variable>
+               <name>scope</name>
+               <type>STRING</type>
+               <value></value>
+               <documentation>
+                       <purpose>Permissions that your application needs to call the OAuth
+                               server APIs</purpose>
+                       <usage>Check the documentation of the APIs that your application
+                               needs to call to set this variable with the identifiers of the
+                               permissions that the user needs to grant to your application.</usage>
+               </documentation>
+       </variable>
+{/metadocument}
+*/
+       var $scope = '';
+
+/*
+{metadocument}
+       <variable>
+               <name>offline</name>
+               <type>BOOLEAN</type>
+               <value>0</value>
+               <documentation>
+                       <purpose>Specify whether it will be necessary to call the API when
+                               the user is not present and the server supports renewing expired
+                               access tokens using refresh tokens.</purpose>
+                       <usage>Set this variable to <booleanvalue>1</booleanvalue> if the
+                               server supports renewing expired tokens automatically when the
+                               user is not present.</usage>
+               </documentation>
+       </variable>
+{/metadocument}
+*/
+       var $offline = false;
+
+/*
+{metadocument}
+       <variable>
+               <name>access_token</name>
+               <type>STRING</type>
+               <value></value>
+               <documentation>
+                       <purpose>Access token obtained from the OAuth server</purpose>
+                       <usage>Check this variable to get the obtained access token upon
+                               successful OAuth authorization.</usage>
+               </documentation>
+       </variable>
+{/metadocument}
+*/
+       var $access_token = '';
+
+/*
+{metadocument}
+       <variable>
+               <name>access_token_secret</name>
+               <type>STRING</type>
+               <value></value>
+               <documentation>
+                       <purpose>Access token secret obtained from the OAuth server</purpose>
+                       <usage>If the OAuth protocol version is 1.0 or 1.0a, check this
+                               variable to get the obtained access token secret upon successful
+                               OAuth authorization.</usage>
+               </documentation>
+       </variable>
+{/metadocument}
+*/
+       var $access_token_secret = '';
+
+/*
+{metadocument}
+       <variable>
+               <name>access_token_expiry</name>
+               <type>STRING</type>
+               <value></value>
+               <documentation>
+                       <purpose>Timestamp of the expiry of the access token obtained from
+                               the OAuth server.</purpose>
+                       <usage>Check this variable to get the obtained access token expiry
+                               time upon successful OAuth authorization. If this variable is
+                               empty, that means no expiry time was set.</usage>
+               </documentation>
+       </variable>
+{/metadocument}
+*/
+       var $access_token_expiry = '';
+
+/*
+{metadocument}
+       <variable>
+               <name>access_token_type</name>
+               <type>STRING</type>
+               <value></value>
+               <documentation>
+                       <purpose>Type of access token obtained from the OAuth server.</purpose>
+                       <usage>Check this variable to get the obtained access token type
+                               upon successful OAuth authorization.</usage>
+               </documentation>
+       </variable>
+{/metadocument}
+*/
+       var $access_token_type = '';
+
+/*
+{metadocument}
+       <variable>
+               <name>refresh_token</name>
+               <type>STRING</type>
+               <value></value>
+               <documentation>
+                       <purpose>Refresh token obtained from the OAuth server</purpose>
+                       <usage>Check this variable to get the obtained refresh token upon
+                               successful OAuth authorization.</usage>
+               </documentation>
+       </variable>
+{/metadocument}
+*/
+       var $refresh_token = '';
+
+/*
+{metadocument}
+       <variable>
+               <name>access_token_error</name>
+               <type>STRING</type>
+               <value></value>
+               <documentation>
+                       <purpose>Error message returned when a call to the API fails.</purpose>
+                       <usage>Check this variable to determine if there was an error while
+                               calling the Web services API when using the
+                               <functionlink>CallAPI</functionlink> function.</usage>
+               </documentation>
+       </variable>
+{/metadocument}
+*/
+       var $access_token_error = '';
+
+/*
+{metadocument}
+       <variable>
+               <name>authorization_error</name>
+               <type>STRING</type>
+               <value></value>
+               <documentation>
+                       <purpose>Error message returned when it was not possible to obtain
+                               an OAuth access token</purpose>
+                       <usage>Check this variable to determine if there was an error while
+                               trying to obtain the OAuth access token.</usage>
+               </documentation>
+       </variable>
+{/metadocument}
+*/
+       var $authorization_error = '';
+
+/*
+{metadocument}
+       <variable>
+               <name>response_status</name>
+               <type>INTEGER</type>
+               <value>0</value>
+               <documentation>
+                       <purpose>HTTP response status returned by the server when calling an
+                               API</purpose>
+                       <usage>Check this variable after calling the
+                               <functionlink>CallAPI</functionlink> function if the API calls and you
+                               need to process the error depending the response status.
+                               <integervalue>200</integervalue> means no error. 
+                               <integervalue>0</integervalue> means the server response was not
+                               retrieved.</usage>
+               </documentation>
+       </variable>
+{/metadocument}
+*/
+       var $response_status = 0;
+
+       var $oauth_user_agent = 'PHP-OAuth-API (http://www.phpclasses.org/oauth-api $Revision: 1.58 $)';
+       var $session_started = false;
+
+       Function SetError($error)
+       {
+               $this->error = $error;
+               if($this->debug)
+                       $this->OutputDebug('Error: '.$error);
+               return(false);
+       }
+
+       Function SetPHPError($error, &$php_error_message)
+       {
+               if(IsSet($php_error_message)
+               && strlen($php_error_message))
+                       $error.=": ".$php_error_message;
+               return($this->SetError($error));
+       }
+
+       Function OutputDebug($message)
+       {
+               if($this->debug)
+               {
+                       $message = $this->debug_prefix.$message;
+                       $this->debug_output .= $message."\n";;
+                       error_log($message);
+               }
+               return(true);
+       }
+
+       Function GetRequestTokenURL(&$request_token_url)
+       {
+               $request_token_url = $this->request_token_url;
+               return(true);
+       }
+
+       Function GetDialogURL(&$url, $redirect_uri = '', $state = '')
+       {
+               $url = (($this->offline && strlen($this->offline_dialog_url)) ? $this->offline_dialog_url : $this->dialog_url);
+               if(strlen($url) === 0)
+                       return $this->SetError('the dialog URL '.($this->offline ? 'for offline access ' : '').'is not defined for this server');
+               $url = str_replace(
+                       '{REDIRECT_URI}', UrlEncode($redirect_uri), str_replace(
+                       '{STATE}', UrlEncode($state), str_replace(
+                       '{CLIENT_ID}', UrlEncode($this->client_id), str_replace(
+                       '{SCOPE}', UrlEncode($this->scope),
+                       $url))));
+               return(true);
+       }
+
+       Function GetAccessTokenURL(&$access_token_url)
+       {
+               $access_token_url = $this->access_token_url;
+               return(true);
+       }
+
+       Function GetStoredState(&$state)
+       {
+               if(!$this->session_started)
+               {
+                       if(!function_exists('session_start'))
+                               return $this->SetError('Session variables are not accessible in this PHP environment');
+               }
+               if(IsSet($_SESSION['OAUTH_STATE']))
+                       $state = $_SESSION['OAUTH_STATE'];
+               else
+                       $state = $_SESSION['OAUTH_STATE'] = time().'-'.substr(md5(rand().time()), 0, 6);
+               return(true);
+       }
+
+       Function GetRequestState(&$state)
+       {
+               $check = (strlen($this->append_state_to_redirect_uri) ? $this->append_state_to_redirect_uri : 'state');
+               $state = (IsSet($_GET[$check]) ? $_GET[$check] : null);
+               return(true);
+       }
+
+       Function GetRequestCode(&$code)
+       {
+               $code = (IsSet($_GET['code']) ? $_GET['code'] : null);
+               return(true);
+       }
+
+       Function GetRequestError(&$error)
+       {
+               $error = (IsSet($_GET['error']) ? $_GET['error'] : null);
+               return(true);
+       }
+
+       Function GetRequestDenied(&$denied)
+       {
+               $denied = (IsSet($_GET['denied']) ? $_GET['denied'] : null);
+               return(true);
+       }
+
+       Function GetRequestToken(&$token, &$verifier)
+       {
+               $token = (IsSet($_GET['oauth_token']) ? $_GET['oauth_token'] : null);
+               $verifier = (IsSet($_GET['oauth_verifier']) ? $_GET['oauth_verifier'] : null);
+               return(true);
+       }
+
+       Function GetRedirectURI(&$redirect_uri)
+       {
+               if(strlen($this->redirect_uri))
+                       $redirect_uri = $this->redirect_uri;
+               else
+                       $redirect_uri = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
+               return true;
+       }
+
+/*
+{metadocument}
+       <function>
+               <name>StoreAccessToken</name>
+               <type>BOOLEAN</type>
+               <documentation>
+                       <purpose>Store the values of the access token when it is succefully
+                               retrieved from the OAuth server.</purpose>
+                       <usage>This function is meant to be only be called from inside the
+                               class. By default it stores access tokens in a session variable
+                               named <stringvalue>OAUTH_ACCESS_TOKEN</stringvalue>.<paragraphbreak />
+                               Actual implementations should create a sub-class and override this
+                               function to make the access token values be stored in other types
+                               of containers, like for instance databases.</usage>
+                       <returnvalue>This function should return
+                               <booleanvalue>1</booleanvalue> if the access token was stored
+                               successfully.</returnvalue>
+               </documentation>
+               <argument>
+                       <name>access_token</name>
+                       <type>HASH</type>
+                       <documentation>
+                               <purpose>Associative array with properties of the access token. 
+                                       The array may have set the following
+                                       properties:<paragraphbreak />
+                                       <stringvalue>value</stringvalue>: string value of the access
+                                               token<paragraphbreak />
+                                       <stringvalue>authorized</stringvalue>: boolean value that
+                                               determines if the access token was obtained
+                                               successfully<paragraphbreak />
+                                       <stringvalue>expiry</stringvalue>: (optional) timestamp in ISO
+                                               format relative to UTC time zone of the access token expiry
+                                               time<paragraphbreak />
+                                       <stringvalue>type</stringvalue>: (optional) type of OAuth token
+                                               that may determine how it should be used when sending API call
+                                               requests.<paragraphbreak />
+                                       <stringvalue>refresh</stringvalue>: (optional) token that some
+                                               servers may set to allowing refreshing access tokens when they
+                                               expire.</purpose>
+                       </documentation>
+               </argument>
+               <do>
+{/metadocument}
+*/
+       Function StoreAccessToken($access_token)
+       {
+               if(!$this->session_started)
+               {
+                       if(!function_exists('session_start'))
+                               return $this->SetError('Session variables are not accessible in this PHP environment');
+               }
+               $_SESSION['OAUTH_ACCESS_TOKEN'][$this->access_token_url] = $access_token;
+               return true;
+       }
+/*
+{metadocument}
+               </do>
+       </function>
+{/metadocument}
+*/
+
+/*
+{metadocument}
+       <function>
+               <name>GetAccessToken</name>
+               <type>BOOLEAN</type>
+               <documentation>
+                       <purpose>Retrieve the OAuth access token if it was already
+                               previously stored by the
+                               <functionlink>StoreAccessToken</functionlink> function.</purpose>
+                       <usage>This function is meant to be only be called from inside the
+                               class. By default it retrieves access tokens stored in a session
+                               variable named
+                               <stringvalue>OAUTH_ACCESS_TOKEN</stringvalue>.<paragraphbreak />
+                               Actual implementations should create a sub-class and override this
+                               function to retrieve the access token values from other types of
+                               containers, like for instance databases.</usage>
+                       <returnvalue>This function should return
+                               <booleanvalue>1</booleanvalue> if the access token was retrieved
+                               successfully.</returnvalue>
+               </documentation>
+               <argument>
+                       <name>access_token</name>
+                       <type>STRING</type>
+                       <out />
+                       <documentation>
+                               <purpose>Return the properties of the access token in an
+                                       associative array. If the access token was not yet stored, it
+                                       returns an empty array. Otherwise, the properties it may return
+                                       are the same that may be passed to the
+                                       <functionlink>StoreAccessToken</functionlink>.</purpose>
+                       </documentation>
+               </argument>
+               <do>
+{/metadocument}
+*/
+       Function GetAccessToken(&$access_token)
+       {
+               if(!$this->session_started)
+               {
+                       if(!function_exists('session_start'))
+                               return $this->SetError('Session variables are not accessible in this PHP environment');
+                       if(!session_start())
+                               return($this->SetPHPError('it was not possible to start the PHP session', $php_error_message));
+                       $this->session_started = true;
+               }
+               if(IsSet($_SESSION['OAUTH_ACCESS_TOKEN'][$this->access_token_url]))
+                       $access_token = $_SESSION['OAUTH_ACCESS_TOKEN'][$this->access_token_url];
+               else
+                       $access_token = array();
+               return true;
+       }
+/*
+{metadocument}
+               </do>
+       </function>
+{/metadocument}
+*/
+
+/*
+{metadocument}
+       <function>
+               <name>ResetAccessToken</name>
+               <type>BOOLEAN</type>
+               <documentation>
+                       <purpose>Reset the access token to a state back when the user has
+                               not yet authorized the access to the OAuth server API.</purpose>
+                       <usage>Call this function if for some reason the token to access
+                               the API was revoked and you need to ask the user to authorize
+                               the access again.<paragraphbreak />
+                               By default the class stores and retrieves access tokens in a
+                               session variable named
+                               <stringvalue>OAUTH_ACCESS_TOKEN</stringvalue>.<paragraphbreak />
+                               This function must be called when the user is accessing your site
+                               pages, so it can reset the information stored in session variables
+                               that cache the state of a previously retrieved access
+                               token.<paragraphbreak />
+                               Actual implementations should create a sub-class and override this
+                               function to reset the access token state when it is stored in
+                               other types of containers, like for instance databases.</usage>
+                       <returnvalue>This function should return
+                               <booleanvalue>1</booleanvalue> if the access token was resetted
+                               successfully.</returnvalue>
+               </documentation>
+               <do>
+{/metadocument}
+*/
+       Function ResetAccessToken()
+       {
+               if($this->debug)
+                       $this->OutputDebug('Resetting the access token status for OAuth server located at '.$this->access_token_url);
+               if(!$this->session_started)
+               {
+                       if(!function_exists('session_start'))
+                               return $this->SetError('Session variables are not accessible in this PHP environment');
+                       if(!session_start())
+                               return($this->SetPHPError('it was not possible to start the PHP session', $php_error_message));
+               }
+               $this->session_started = true;
+               if(IsSet($_SESSION['OAUTH_ACCESS_TOKEN'][$this->access_token_url]))
+                       Unset($_SESSION['OAUTH_ACCESS_TOKEN'][$this->access_token_url]);
+               return true;
+       }
+/*
+{metadocument}
+               </do>
+       </function>
+{/metadocument}
+*/
+
+       Function Encode($value)
+       {
+               return(is_array($value) ? $this->EncodeArray($value) : str_replace('%7E', '~', str_replace('+',' ', RawURLEncode($value))));
+       }
+
+       Function EncodeArray($array)
+       {
+               foreach($array as $key => $value)
+                       $array[$key] = $this->Encode($value);
+               return $array;
+       }
+
+       Function HMAC($function, $data, $key)
+       {
+               switch($function)
+               {
+                       case 'sha1':
+                               $pack = 'H40';
+                               break;
+                       default:
+                               if($this->debug)
+                                       $this->OutputDebug($function.' is not a supported an HMAC hash type');
+                               return('');
+               }
+               if(strlen($key) > 64)
+                       $key = pack($pack, $function($key));
+               if(strlen($key) < 64)
+                       $key = str_pad($key, 64, "\0");
+               return(pack($pack, $function((str_repeat("\x5c", 64) ^ $key).pack($pack, $function((str_repeat("\x36", 64) ^ $key).$data)))));
+       }
+
+       Function SendAPIRequest($url, $method, $parameters, $oauth, $options, &$response)
+       {
+               $this->response_status = 0;
+               $http = new http_class;
+               $http->debug = ($this->debug && $this->debug_http);
+               $http->log_debug = true;
+               $http->sasl_authenticate = 0;
+               $http->user_agent = $this->oauth_user_agent;
+               $http->redirection_limit = (IsSet($options['FollowRedirection']) ? intval($options['FollowRedirection']) : 0);
+               $http->follow_redirect = ($http->redirection_limit != 0);
+               if($this->debug)
+                       $this->OutputDebug('Accessing the '.$options['Resource'].' at '.$url);
+               $post_files = array();
+               $method = strtoupper($method);
+               $authorization = '';
+               $type = (IsSet($options['RequestContentType']) ? strtolower(trim(strtok($options['RequestContentType'], ';'))) : 'application/x-www-form-urlencoded');
+               if(IsSet($oauth))
+               {
+                       $values = array(
+                               'oauth_consumer_key'=>$this->client_id,
+                               'oauth_nonce'=>md5(uniqid(rand(), true)),
+                               'oauth_signature_method'=>$this->signature_method,
+                               'oauth_timestamp'=>time(),
+                               'oauth_version'=>'1.0',
+                       );
+                       $files = (IsSet($options['Files']) ? $options['Files'] : array());
+                       if(count($files))
+                       {
+                               foreach($files as $name => $value)
+                               {
+                                       if(!IsSet($parameters[$name]))
+                                               return($this->SetError('it was specified an file parameters named '.$name));
+                                       $file = array();
+                                       switch(IsSet($value['Type']) ? $value['Type'] : 'FileName')
+                                       {
+                                               case 'FileName':
+                                                       $file['FileName'] = $parameters[$name];
+                                                       break;
+                                               case 'Data':
+                                                       $file['Data'] = $parameters[$name];
+                                                       break;
+                                               default:
+                                                       return($this->SetError($value['Type'].' is not a valid type for file '.$name));
+                                       }
+                                       $file['ContentType'] = (IsSet($value['Content-Type']) ? $value['Content-Type'] : 'automatic/name');
+                                       $post_files[$name] = $file;
+                               }
+                               UnSet($parameters[$name]);
+                               if($method !== 'POST')
+                               {
+                                       $this->OutputDebug('For uploading files the method should be POST not '.$method);
+                                       $method = 'POST';
+                               }
+                               if($type !== 'multipart/form-data')
+                               {
+                                       if(IsSet($options['RequestContentType']))
+                                               return($this->SetError('the request content type for uploading files should be multipart/form-data'));
+                                       $type = 'multipart/form-data';
+                               }
+                               $value_parameters = array();
+                       }
+                       else
+                       {
+                               if($this->url_parameters
+                               && $type === 'application/x-www-form-urlencoded'
+                               && count($parameters))
+                               {
+                                       $first = (strpos($url, '?') === false);
+                                       foreach($parameters as $parameter => $value)
+                                       {
+                                               $url .= ($first ? '?' : '&').UrlEncode($parameter).'='.UrlEncode($value);
+                                               $first = false;
+                                       }
+                                       $parameters = array();
+                               }
+                               $value_parameters = ($type !== 'application/x-www-form-urlencoded' ? array() : $parameters);
+                       }
+                       $values = array_merge($values, $oauth, $value_parameters);
+                       $key = $this->Encode($this->client_secret).'&'.$this->Encode($this->access_token_secret);
+                       switch($this->signature_method)
+                       {
+                               case 'PLAINTEXT':
+                                       $values['oauth_signature'] = $key;
+                                       break;
+                               case 'HMAC-SHA1':
+                                       $uri = strtok($url, '?');
+                                       $sign = $method.'&'.$this->Encode($uri).'&';
+                                       $first = true;
+                                       $sign_values = $values;
+                                       $u = parse_url($url);
+                                       if(IsSet($u['query']))
+                                       {
+                                               parse_str($u['query'], $q);
+                                               foreach($q as $parameter => $value)
+                                                       $sign_values[$parameter] = $value;
+                                       }
+                                       KSort($sign_values);
+                                       foreach($sign_values as $parameter => $value)
+                                       {
+                                               $sign .= $this->Encode(($first ? '' : '&').$parameter.'='.$this->Encode($value));
+                                               $first = false;
+                                       }
+                                       $values['oauth_signature'] = base64_encode($this->HMAC('sha1', $sign, $key));
+                                       break;
+                               default:
+                                       return $this->SetError($this->signature_method.' signature method is not yet supported');
+                       }
+                       if($this->authorization_header)
+                       {
+                               $authorization = 'OAuth';
+                               $first = true;
+                               foreach($values as $parameter => $value)
+                               {
+                                       $authorization .= ($first ? ' ' : ',').$parameter.'="'.$this->Encode($value).'"';
+                                       $first = false;
+                               }
+                       }
+                       else
+                       {
+                               if($method === 'GET'
+                               || (IsSet($options['PostValuesInURI'])
+                               && $options['PostValuesInURI']))
+                               {
+                                       $first = (strcspn($url, '?') == strlen($url));
+                                       foreach($values as $parameter => $value)
+                                       {
+                                               $url .= ($first ? '?' : '&').$parameter.'='.$this->Encode($value);
+                                               $first = false;
+                                       }
+                                       $post_values = array();
+                               }
+                               else
+                                       $post_values = $values;
+                       }
+               }
+               if(strlen($error = $http->GetRequestArguments($url, $arguments)))
+                       return($this->SetError('it was not possible to open the '.$options['Resource'].' URL: '.$error));
+               if(strlen($error = $http->Open($arguments)))
+                       return($this->SetError('it was not possible to open the '.$options['Resource'].' URL: '.$error));
+               if(count($post_files))
+                       $arguments['PostFiles'] = $post_files;
+               $arguments['RequestMethod'] = $method;
+               switch($type)
+               {
+                       case 'application/x-www-form-urlencoded':
+                       case 'multipart/form-data':
+                               if(IsSet($options['RequestBody']))
+                                       return($this->SetError('the request body is defined automatically from the parameters'));
+                               $arguments['PostValues'] = $parameters;
+                               break;
+                       case 'application/json':
+                               $arguments['Headers']['Content-Type'] = $options['RequestContentType'];
+                               if(!IsSet($options['RequestBody']))
+                               {
+                                       $arguments['Body'] = json_encode($parameters);
+                                       break;
+                               }
+                       default:
+                               if(!IsSet($options['RequestBody']))
+                                       return($this->SetError('it was not specified the body value of the of the API call request'));
+                               $arguments['Headers']['Content-Type'] = $options['RequestContentType'];
+                               $arguments['Body'] = $options['RequestBody'];
+                               break;
+               }
+               $arguments['Headers']['Accept'] = (IsSet($options['Accept']) ? $options['Accept'] : '*/*');
+               if(strlen($authorization))
+                       $arguments['Headers']['Authorization'] = $authorization;
+               if(strlen($error = $http->SendRequest($arguments))
+               || strlen($error = $http->ReadReplyHeaders($headers)))
+               {
+                       $http->Close();
+                       return($this->SetError('it was not possible to retrieve the '.$options['Resource'].': '.$error));
+               }
+               $error = $http->ReadWholeReplyBody($data);
+               $http->Close();
+               if(strlen($error))
+               {
+                       return($this->SetError('it was not possible to access the '.$options['Resource'].': '.$error));
+               }
+               $this->response_status = intval($http->response_status);
+               $content_type = (IsSet($options['ResponseContentType']) ? $options['ResponseContentType'] : (IsSet($headers['content-type']) ? strtolower(trim(strtok($headers['content-type'], ';'))) : 'unspecified'));
+               switch($content_type)
+               {
+                       case 'text/javascript':
+                       case 'application/json':
+                               if(!function_exists('json_decode'))
+                                       return($this->SetError('the JSON extension is not available in this PHP setup'));
+                               $object = json_decode($data);
+                               switch(GetType($object))
+                               {
+                                       case 'object':
+                                               if(!IsSet($options['ConvertObjects'])
+                                               || !$options['ConvertObjects'])
+                                                       $response = $object;
+                                               else
+                                               {
+                                                       $response = array();
+                                                       foreach($object as $property => $value)
+                                                               $response[$property] = $value;
+                                               }
+                                               break;
+                                       case 'array':
+                                               $response = $object;
+                                               break;
+                                       default:
+                                               if(!IsSet($object))
+                                                       return($this->SetError('it was not returned a valid JSON definition of the '.$options['Resource'].' values'));
+                                               $response = $object;
+                                               break;
+                               }
+                               break;
+                       case 'application/x-www-form-urlencoded':
+                       case 'text/plain':
+                       case 'text/html':
+                               parse_str($data, $response);
+                               break;
+                       default:
+                               $response = $data;
+                               break;
+               }
+               if($this->response_status >= 200
+               && $this->response_status < 300)
+                       $this->access_token_error = '';
+               else
+               {
+                       $this->access_token_error = 'it was not possible to access the '.$options['Resource'].': it was returned an unexpected response status '.$http->response_status.' Response: '.$data;
+                       if($this->debug)
+                               $this->OutputDebug('Could not retrieve the OAuth access. Error: '.$this->access_token_error);
+                       if(IsSet($options['FailOnAccessError'])
+                       && $options['FailOnAccessError'])
+                       {
+                               $this->error = $this->access_token_error;
+                               return false;
+                       }
+               }
+               return true;
+       }
+
+       Function ProcessToken($code, $refresh)
+       {
+               if($refresh)
+               {
+                       $values = array(
+                               'client_id'=>$this->client_id,
+                               'client_secret'=>$this->client_secret,
+                               'refresh_token'=>$this->refresh_token,
+                               'grant_type'=>'refresh_token'
+                       );
+               }
+               else
+               {
+                       if(!$this->GetRedirectURI($redirect_uri))
+                               return false;
+                       $values = array(
+                               'code'=>$code,
+                               'client_id'=>$this->client_id,
+                               'client_secret'=>$this->client_secret,
+                               'redirect_uri'=>$redirect_uri,
+                               'grant_type'=>'authorization_code'
+                       );
+               }
+               if(!$this->GetAccessTokenURL($url))
+                       return false;
+               if(!$this->SendAPIRequest($url, 'POST', $values, null, array('Resource'=>'OAuth '.($refresh ? 'refresh' : 'access').' token', 'ConvertObjects'=>true), $response))
+                       return false;
+               if(strlen($this->access_token_error))
+               {
+                       $this->authorization_error = $this->access_token_error;
+                       return true;
+               }
+               if(!IsSet($response['access_token']))
+               {
+                       if(IsSet($response['error']))
+                       {
+                               $this->authorization_error = 'it was not possible to retrieve the access token: it was returned the error: '.$response['error'];
+                               return true;
+                       }
+                       return($this->SetError('OAuth server did not return the access token'));
+               }
+               $access_token = array(
+                       'value'=>$this->access_token = $response['access_token'],
+                       'authorized'=>true
+               );
+               if($this->debug)
+                       $this->OutputDebug('Access token: '.$this->access_token);
+               if(IsSet($response['expires'])
+               || IsSet($response['expires_in']))
+               {
+                       $expires = (IsSet($response['expires']) ? $response['expires'] : $response['expires_in']);
+                       if(strval($expires) !== strval(intval($expires))
+                       || $expires <= 0)
+                               return($this->SetError('OAuth server did not return a supported type of access token expiry time'));
+                       $this->access_token_expiry = gmstrftime('%Y-%m-%d %H:%M:%S', time() + $expires);
+                       if($this->debug)
+                               $this->OutputDebug('Access token expiry: '.$this->access_token_expiry.' UTC');
+                       $access_token['expiry'] = $this->access_token_expiry;
+               }
+               else
+                       $this->access_token_expiry = '';
+               if(IsSet($response['token_type']))
+               {
+                       $this->access_token_type = $response['token_type'];
+                       if($this->debug)
+                               $this->OutputDebug('Access token type: '.$this->access_token_type);
+                       $access_token['type'] = $this->access_token_type;
+               }
+               else
+                       $this->access_token_type = '';
+               if($refresh)
+                       $response['refresh_token'] = $this->refresh_token;
+               elseif(IsSet($response['refresh_token']))
+               {
+                       $this->refresh_token = $response['refresh_token'];
+                       if($this->debug)
+                               $this->OutputDebug('Refresh token: '.$this->refresh_token);
+                       $access_token['refresh'] = $this->refresh_token;
+               }
+               else
+                       $this->refresh_token = '';
+               if(!$this->StoreAccessToken($access_token))
+                       return false;
+               return true;
+       }
+
+       Function RetrieveToken(&$valid)
+       {
+               $valid = false;
+               if(!$this->GetAccessToken($access_token))
+                       return false;
+               if(IsSet($access_token['value']))
+               {
+                       $this->access_token_expiry = '';
+                       if(IsSet($access_token['expiry'])
+                       && strcmp($this->access_token_expiry = $access_token['expiry'], gmstrftime('%Y-%m-%d %H:%M:%S')) < 0)
+                       {
+                               $this->access_token = '';
+                               if($this->debug)
+                                       $this->OutputDebug('The OAuth access token expired in '.$this->access_token_expiry);
+                       }
+                       else
+                       {
+                               $this->access_token = $access_token['value'];
+                               if(IsSet($access_token['type']))
+                                       $this->access_token_type = $access_token['type'];
+                               else
+                                       $this->access_token_type = '';
+                               if($this->debug)
+                                       $this->OutputDebug('The OAuth access token '.$this->access_token.' is valid');
+                               if(strlen($this->access_token_type)
+                               && $this->debug)
+                                       $this->OutputDebug('The OAuth access token is of type '.$this->access_token_type);
+                               if(IsSet($access_token['refresh']))
+                                       $this->refresh_token = $access_token['refresh'];
+                               else
+                                       $this->refresh_token = '';
+                               $valid = true;
+                       }
+               }
+               return true;
+       }
+/*
+{metadocument}
+       <function>
+               <name>CallAPI</name>
+               <type>BOOLEAN</type>
+               <documentation>
+                       <purpose>Send a HTTP request to the Web services API using a
+                               previously obtained authorization token via OAuth.</purpose>
+                       <usage>This function can be used to call an API after having
+                               previously obtained an access token through the OAuth protocol
+                               using the <functionlink>Process</functionlink> function, or by
+                               directly setting the variables
+                               <variablelink>access_token</variablelink>, as well as
+                               <variablelink>access_token_secret</variablelink> in case of using
+                               OAuth 1.0 or 1.0a services.</usage>
+                       <returnvalue>This function returns <booleanvalue>1</booleanvalue> if
+                               the call was done successfully.</returnvalue>
+               </documentation>
+               <argument>
+                       <name>url</name>
+                       <type>STRING</type>
+                       <documentation>
+                               <purpose>URL of the API where the HTTP request will be sent.</purpose>
+                       </documentation>
+               </argument>
+               <argument>
+                       <name>method</name>
+                       <type>STRING</type>
+                       <documentation>
+                               <purpose>HTTP method that will be used to send the request. It can
+                               be <stringvalue>GET</stringvalue>,
+                               <stringvalue>POST</stringvalue>,
+                               <stringvalue>DELETE</stringvalue>, <stringvalue>PUT</stringvalue>,
+                               etc..</purpose>
+                       </documentation>
+               </argument>
+               <argument>
+                       <name>parameters</name>
+                       <type>HASH</type>
+                       <documentation>
+                               <purpose>Associative array with the names and values of the API
+                                       call request parameters.</purpose>
+                       </documentation>
+               </argument>
+               <argument>
+                       <name>options</name>
+                       <type>HASH</type>
+                       <documentation>
+                               <purpose>Associative array with additional options to configure
+                                       the request. Currently it supports the following
+                                       options:<paragraphbreak />
+                                       <stringvalue>2Legged</stringvalue>: boolean option that
+                                               determines if the API request should be 2 legged. The default
+                                               value is <tt><booleanvalue>0</booleanvalue></tt>.<paragraphbreak />
+                                       <stringvalue>Accept</stringvalue>: content type value of the
+                                               Accept HTTP header to be sent in the API call HTTP request.
+                                               Some APIs require that a certain value be sent to specify
+                                               which version of the API is being called. The default value is
+                                               <stringvalue>*&#47;*</stringvalue>.<paragraphbreak />
+                                       <stringvalue>ConvertObjects</stringvalue>: boolean option that
+                                               determines if objects should be converted into arrays when the
+                                               response is returned in JSON format. The default value is
+                                               <booleanvalue>0</booleanvalue>.<paragraphbreak />
+                                       <stringvalue>FailOnAccessError</stringvalue>: boolean option
+                                               that determines if this functions should fail when the server
+                                               response status is not between 200 and 299. The default value
+                                               is <booleanvalue>0</booleanvalue>.<paragraphbreak />
+                                       <stringvalue>Files</stringvalue>: associative array with
+                                               details of the parameters that must be passed as file uploads.
+                                               The array indexes must have the same name of the parameters
+                                               to be sent as files. The respective array entry values must
+                                               also be associative arrays with the parameters for each file.
+                                               Currently it supports the following parameters:<paragraphbreak />
+                                               - <tt>Type</tt> - defines how the parameter value should be
+                                               treated. It can be <tt>'FileName'</tt> if the parameter value is
+                                               is the name of a local file to be uploaded. It may also be
+                                               <tt>'Data'</tt> if the parameter value is the actual data of
+                                               the file to be uploaded.<paragraphbreak />
+                                               - Default: <tt>'FileName'</tt><paragraphbreak />
+                                               - <tt>ContentType</tt> - MIME value of the content type of the
+                                               file. It can be <tt>'automatic/name'</tt> if the content type
+                                               should be determine from the file name extension.<paragraphbreak />
+                                               - Default: <tt>'automatic/name'</tt><paragraphbreak />
+                                       <stringvalue>PostValuesInURI</stringvalue>: boolean option to
+                                               determine that a POST request should pass the request values
+                                               in the URI. The default value is
+                                               <booleanvalue>0</booleanvalue>.<paragraphbreak />
+                                       <stringvalue>FollowRedirection</stringvalue>: limit number of
+                                               times that HTTP response redirects will be followed. If it is
+                                               set to <integervalue>0</integervalue>, redirection responses
+                                               fail in error. The default value is
+                                               <integervalue>0</integervalue>.<paragraphbreak />
+                                       <stringvalue>RequestBody</stringvalue>: request body data of a
+                                               custom type. The <stringvalue>RequestContentType</stringvalue>
+                                               option must be specified, so the
+                                               <stringvalue>RequestBody</stringvalue> option is considered.<paragraphbreak />
+                                       <stringvalue>RequestContentType</stringvalue>: content type that
+                                               should be used to send the request values. It can be either
+                                               <stringvalue>application/x-www-form-urlencoded</stringvalue>
+                                               for sending values like from Web forms, or
+                                               <stringvalue>application/json</stringvalue> for sending the
+                                               values encoded in JSON format. Other types are accepted if the
+                                               <stringvalue>RequestBody</stringvalue> option is specified.
+                                               The default value is
+                                               <stringvalue>application/x-www-form-urlencoded</stringvalue>.<paragraphbreak />
+                                       <stringvalue>RequestBody</stringvalue>: request body data of a
+                                               custom type. The <stringvalue>RequestContentType</stringvalue>
+                                               option must be specified, so the
+                                               <stringvalue>RequestBody</stringvalue> option is considered.<paragraphbreak />
+                                       <stringvalue>Resource</stringvalue>: string with a label that
+                                               will be used in the error messages and debug log entries to
+                                               identify what operation the request is performing. The default
+                                               value is <stringvalue>API call</stringvalue>.<paragraphbreak />
+                                       <stringvalue>ResponseContentType</stringvalue>: content type
+                                               that should be considered when decoding the API request
+                                               response. This overrides the <tt>Content-Type</tt> header
+                                               returned by the server. If the content type is 
+                                               <stringvalue>application/x-www-form-urlencoded</stringvalue>
+                                               the function will parse the data returning an array of
+                                               key-value pairs. If the content type is 
+                                               <stringvalue>application/json</stringvalue> the response will
+                                               be decode as a JSON-encoded data type. Other content type
+                                               values will make the function return the original response
+                                               value as it was returned from the server. The default value
+                                               for this option is to use what the server returned in the
+                                               <tt>Content-Type</tt> header.</purpose>
+                       </documentation>
+               </argument>
+               <argument>
+                       <name>response</name>
+                       <type>STRING</type>
+                       <out />
+                       <documentation>
+                               <purpose>Return the value of the API response. If the value is
+                                       JSON encoded, this function will decode it and return the value
+                                       converted to respective types. If the value is form encoded,
+                                       this function will decode the response and return it as an
+                                       array. Otherwise, the class will return the value as a
+                                       string.</purpose>
+                       </documentation>
+               </argument>
+               <do>
+{/metadocument}
+*/
+       Function CallAPI($url, $method, $parameters, $options, &$response)
+       {
+               if(!IsSet($options['Resource']))
+                       $options['Resource'] = 'API call';
+               if(!IsSet($options['ConvertObjects']))
+                       $options['ConvertObjects'] = false;
+               if(strlen($this->access_token) === 0)
+               {
+                       if(!$this->RetrieveToken($valid))
+                               return false;
+                       if(!$valid)
+                               return $this->SetError('the access token is not set to a valid value');
+               }
+               switch(intval($this->oauth_version))
+               {
+                       case 1:
+                               $oauth = array(
+                                       'oauth_token'=>((IsSet($options['2Legged']) && $options['2Legged']) ? '' : $this->access_token)
+                               );
+                               break;
+
+                       case 2:
+                               if(strlen($this->access_token_expiry)
+                               && strcmp($this->access_token_expiry, gmstrftime('%Y-%m-%d %H:%M:%S')) <= 0)
+                               {
+                                       if(strlen($this->refresh_token) === 0)
+                                               return($this->SetError('the access token expired and no refresh token is available'));
+                                       if($this->debug)
+                                       {
+                                               $this->OutputDebug('The access token expired on '.$this->access_token_expiry);
+                                               $this->OutputDebug('Refreshing the access token');
+                                       }
+                                       if(!$this->ProcessToken(null, true))
+                                               return false;
+                               }
+                               $oauth = null;
+                               $url .= (strcspn($url, '?') < strlen($url) ? '&' : '?').'access_token='.UrlEncode($this->access_token);
+                               break;
+
+                       default:
+                               return($this->SetError($this->oauth_version.' is not a supported version of the OAuth protocol'));
+               }
+               return($this->SendAPIRequest($url, $method, $parameters, $oauth, $options, $response));
+       }
+/*
+{metadocument}
+               </do>
+       </function>
+{/metadocument}
+*/
+
+/*
+{metadocument}
+       <function>
+               <name>Initialize</name>
+               <type>BOOLEAN</type>
+               <documentation>
+                       <purpose>Initialize the class variables and internal state. It must
+                               be called before calling other class functions.</purpose>
+                       <usage>Set the <variablelink>server</variablelink> variable before
+                               calling this function to let it initialize the class variables to
+                               work with the specified server type. Alternatively, you can set
+                               other class variables manually to make it work with servers that
+                               are not yet built-in supported.</usage>
+                       <returnvalue>This function returns <booleanvalue>1</booleanvalue> if
+                               it was able to successfully initialize the class for the specified
+                               server type.</returnvalue>
+               </documentation>
+               <do>
+{/metadocument}
+*/
+       Function Initialize()
+       {
+               if(strlen($this->server) === 0)
+                       return true;
+               $this->request_token_url = '';
+               $this->append_state_to_redirect_uri = '';
+               $this->authorization_header = true;
+               $this->url_parameters = false;
+               $this->token_request_method = 'GET';
+               $this->signature_method = 'HMAC-SHA1';
+               switch($this->server)
+               {
+                       case 'Bitbucket':
+                               $this->oauth_version = '1.0a';
+                               $this->request_token_url = 'https://bitbucket.org/!api/1.0/oauth/request_token';
+                               $this->dialog_url = 'https://bitbucket.org/!api/1.0/oauth/authenticate';
+                               $this->access_token_url = 'https://bitbucket.org/!api/1.0/oauth/access_token';
+                               $this->url_parameters = true;
+                               break;
+
+                       case 'Box':
+                               $this->oauth_version = '2.0';
+                               $this->dialog_url = 'https://www.box.com/api/oauth2/authorize?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&state={STATE}';
+                               $this->offline_dialog_url = 'https://www.box.com/api/oauth2/authorize?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&state={STATE}&access_type=offline&approval_prompt=force';
+                               $this->access_token_url = 'https://www.box.com/api/oauth2/token';
+                               break;
+
+                       case 'Dropbox':
+                               $this->oauth_version = '1.0';
+                               $this->request_token_url = 'https://api.dropbox.com/1/oauth/request_token';
+                               $this->dialog_url = 'https://www.dropbox.com/1/oauth/authorize';
+                               $this->access_token_url = 'https://api.dropbox.com/1/oauth/access_token';
+                               $this->authorization_header = false;
+                               break;
+
+                       case 'Eventful':
+                               $this->oauth_version = '1.0a';
+                               $this->request_token_url = 'http://eventful.com/oauth/request_token';
+                               $this->dialog_url = 'http://eventful.com/oauth/authorize';
+                               $this->access_token_url = 'http://eventful.com/oauth/access_token';
+                               $this->authorization_header = false;
+                               $this->url_parameters = true;
+                               $this->token_request_method = 'POST';
+                               break;
+
+                       case 'Evernote':
+                               $this->oauth_version = '1.0a';
+                               $this->request_token_url = 'https://sandbox.evernote.com/oauth';
+                               $this->dialog_url = 'https://sandbox.evernote.com/OAuth.action';
+                               $this->access_token_url = 'https://sandbox.evernote.com/oauth';
+                               $this->url_parameters = true;
+                               $this->authorization_header = false;
+                               break;
+
+                       case 'Facebook':
+                               $this->oauth_version = '2.0';
+                               $this->dialog_url = 'https://www.facebook.com/dialog/oauth?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&state={STATE}';
+                               $this->access_token_url = 'https://graph.facebook.com/oauth/access_token';
+                               break;
+
+                       case 'Fitbit':
+                               $this->oauth_version = '1.0a';
+                               $this->request_token_url = 'http://api.fitbit.com/oauth/request_token';
+                               $this->dialog_url = 'http://api.fitbit.com/oauth/authorize';
+                               $this->access_token_url = 'http://api.fitbit.com/oauth/access_token';
+                               break;
+
+                       case 'Flickr':
+                               $this->oauth_version = '1.0a';
+                               $this->request_token_url = 'http://www.flickr.com/services/oauth/request_token';
+                               $this->dialog_url = 'http://www.flickr.com/services/oauth/authorize?perms={SCOPE}';
+                               $this->access_token_url = 'http://www.flickr.com/services/oauth/access_token';
+                               $this->authorization_header = false;
+                               break;
+
+                       case 'Foursquare':
+                               $this->oauth_version = '2.0';
+                               $this->dialog_url = 'https://foursquare.com/oauth2/authorize?client_id={CLIENT_ID}&scope={SCOPE}&response_type=code&redirect_uri={REDIRECT_URI}&state={STATE}';
+                               $this->access_token_url = 'https://foursquare.com/oauth2/access_token';
+                               break;
+
+                       case 'github':
+                               $this->oauth_version = '2.0';
+                               $this->dialog_url = 'https://github.com/login/oauth/authorize?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&state={STATE}';
+                               $this->access_token_url = 'https://github.com/login/oauth/access_token';
+                               break;
+
+                       case 'Google':
+                               $this->oauth_version = '2.0';
+                               $this->dialog_url = 'https://accounts.google.com/o/oauth2/auth?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&state={STATE}';
+                               $this->offline_dialog_url = 'https://accounts.google.com/o/oauth2/auth?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&state={STATE}&access_type=offline&approval_prompt=force';
+                               $this->access_token_url = 'https://accounts.google.com/o/oauth2/token';
+                               break;
+
+                       case 'Instagram':
+                               $this->oauth_version = '2.0';
+                               $this->dialog_url ='https://api.instagram.com/oauth/authorize/?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&response_type=code&state={STATE}';
+                               $this->access_token_url = 'https://api.instagram.com/oauth/access_token';
+                               break;
+
+                       case 'LinkedIn':
+                               $this->oauth_version = '1.0a';
+                               $this->request_token_url = 'https://api.linkedin.com/uas/oauth/requestToken?scope={SCOPE}';
+                               $this->dialog_url = 'https://api.linkedin.com/uas/oauth/authenticate';
+                               $this->access_token_url = 'https://api.linkedin.com/uas/oauth/accessToken';
+                               $this->url_parameters = true;
+                               break;
+
+                       case 'Microsoft':
+                               $this->oauth_version = '2.0';
+                               $this->dialog_url = 'https://login.live.com/oauth20_authorize.srf?client_id={CLIENT_ID}&scope={SCOPE}&response_type=code&redirect_uri={REDIRECT_URI}&state={STATE}';
+                               $this->access_token_url = 'https://login.live.com/oauth20_token.srf';
+                               break;
+
+                       case 'RightSignature':
+                               $this->oauth_version = '1.0a';
+                               $this->request_token_url = 'https://rightsignature.com/oauth/request_token';
+                               $this->dialog_url = 'https://rightsignature.com/oauth/authorize';
+                               $this->access_token_url = 'https://rightsignature.com/oauth/access_token';
+                               $this->authorization_header = false;
+                               break;
+
+                       case 'Scoop.it':
+                               $this->oauth_version = '1.0a';
+                               $this->request_token_url = 'https://www.scoop.it/oauth/request';
+                               $this->dialog_url = 'https://www.scoop.it/oauth/authorize';
+                               $this->access_token_url = 'https://www.scoop.it/oauth/access';
+                               $this->authorization_header = false;
+                               break;
+
+                       case 'StockTwits':
+                               $this->oauth_version = '2.0';
+                               $this->dialog_url = 'https://api.stocktwits.com/api/2/oauth/authorize?client_id={CLIENT_ID}&response_type=code&redirect_uri={REDIRECT_URI}&scope={SCOPE}&state={STATE}';
+                               $this->access_token_url = 'https://api.stocktwits.com/api/2/oauth/token';
+                               break;
+
+                       case 'Tumblr':
+                               $this->oauth_version = '1.0a';
+                               $this->request_token_url = 'http://www.tumblr.com/oauth/request_token';
+                               $this->dialog_url = 'http://www.tumblr.com/oauth/authorize';
+                               $this->access_token_url = 'http://www.tumblr.com/oauth/access_token';
+                               break;
+
+                       case 'Twitter':
+                               $this->oauth_version = '1.0a';
+                               $this->request_token_url = 'https://api.twitter.com/oauth/request_token';
+                               $this->dialog_url = 'https://api.twitter.com/oauth/authenticate';
+                               $this->access_token_url = 'https://api.twitter.com/oauth/access_token';
+                               $this->url_parameters = true;
+                               break;
+
+                       case 'XING':
+                               $this->oauth_version = '1.0a';
+                               $this->request_token_url = 'https://api.xing.com/v1/request_token';
+                               $this->dialog_url = 'https://api.xing.com/v1/authorize';
+                               $this->access_token_url = 'https://api.xing.com/v1/access_token';
+                               $this->authorization_header = false;
+                               break;
+
+                       case 'Yahoo':
+                               $this->oauth_version = '1.0a';
+                               $this->request_token_url = 'https://api.login.yahoo.com/oauth/v2/get_request_token';
+                               $this->dialog_url = 'https://api.login.yahoo.com/oauth/v2/request_auth';
+                               $this->access_token_url = 'https://api.login.yahoo.com/oauth/v2/get_token';
+                               $this->authorization_header = false;
+                               break;
+
+                       default:
+                               return($this->SetError($this->server.' is not yet a supported type of OAuth server. Please contact the author Manuel Lemos <mlemos@acm.org> to request adding built-in support to this type of OAuth server.'));
+               }
+               return(true);
+       }
+/*
+{metadocument}
+               </do>
+       </function>
+{/metadocument}
+*/
+
+/*
+{metadocument}
+       <function>
+               <name>Process</name>
+               <type>BOOLEAN</type>
+               <documentation>
+                       <purpose>Process the OAuth protocol interaction with the OAuth
+                               server.</purpose>
+                       <usage>Call this function when you need to retrieve the OAuth access
+                               token. Check the <variablelink>access_token</variablelink> to
+                               determine if the access token was obtained successfully.</usage>
+                       <returnvalue>This function returns <booleanvalue>1</booleanvalue> if
+                               the OAuth protocol was processed without errors.</returnvalue>
+               </documentation>
+               <do>
+{/metadocument}
+*/
+       Function Process()
+       {
+               switch(intval($this->oauth_version))
+               {
+                       case 1:
+                               $one_a = ($this->oauth_version === '1.0a');
+                               if($this->debug)
+                                       $this->OutputDebug('Checking the OAuth token authorization state');
+                               if(!$this->GetAccessToken($access_token))
+                                       return false;
+                               if(IsSet($access_token['authorized'])
+                               && IsSet($access_token['value']))
+                               {
+                                       $expired = (IsSet($access_token['expiry']) && strcmp($access_token['expiry'], gmstrftime('%Y-%m-%d %H:%M:%S')) <= 0);
+                                       if(!$access_token['authorized']
+                                       || $expired)
+                                       {
+                                               if($this->debug)
+                                               {
+                                                       if($expired)
+                                                               $this->OutputDebug('The OAuth token expired on '.$access_token['expiry'].'UTC');
+                                                       else
+                                                               $this->OutputDebug('The OAuth token is not yet authorized');
+                                                       $this->OutputDebug('Checking the OAuth token and verifier');
+                                               }
+                                               if(!$this->GetRequestToken($token, $verifier))
+                                                       return false;
+                                               if(!IsSet($token)
+                                               || ($one_a
+                                               && !IsSet($verifier)))
+                                               {
+                                                       if(!$this->GetRequestDenied($denied))
+                                                               return false;
+                                                       if(IsSet($denied)
+                                                       && $denied === $access_token['value'])
+                                                       {
+                                                               if($this->debug)
+                                                                       $this->OutputDebug('The authorization request was denied');
+                                                               $this->authorization_error = 'the request was denied';
+                                                               return true;
+                                                       }
+                                                       else
+                                                       {
+                                                               if($this->debug)
+                                                                       $this->OutputDebug('Reset the OAuth token state because token and verifier are not both set');
+                                                               $access_token = array();
+                                                       }
+                                               }
+                                               elseif($token !== $access_token['value'])
+                                               {
+                                                       if($this->debug)
+                                                               $this->OutputDebug('Reset the OAuth token state because token does not match what as previously retrieved');
+                                                       $access_token = array();
+                                               }
+                                               else
+                                               {
+                                                       if(!$this->GetAccessTokenURL($url))
+                                                               return false;
+                                                       $oauth = array(
+                                                               'oauth_token'=>$token,
+                                                       );
+                                                       if($one_a)
+                                                               $oauth['oauth_verifier'] = $verifier;
+                                                       $this->access_token_secret = $access_token['secret'];
+                                                       $options = array('Resource'=>'OAuth access token');
+                                                       $method = strtoupper($this->token_request_method);
+                                                       switch($method)
+                                                       {
+                                                               case 'GET':
+                                                                       break;
+                                                               case 'POST':
+                                                                       $options['PostValuesInURI'] = true;
+                                                                       break;
+                                                               default:
+                                                                       $this->error = $method.' is not a supported method to request tokens';
+                                                                       break;
+                                                       }
+                                                       if(!$this->SendAPIRequest($url, $method, array(), $oauth, $options, $response))
+                                                               return false;
+                                                       if(strlen($this->access_token_error))
+                                                       {
+                                                               $this->authorization_error = $this->access_token_error;
+                                                               return true;
+                                                       }
+                                                       if(!IsSet($response['oauth_token'])
+                                                       || !IsSet($response['oauth_token_secret']))
+                                                       {
+                                                               $this->authorization_error= 'it was not returned the access token and secret';
+                                                               return true;
+                                                       }
+                                                       $access_token = array(
+                                                               'value'=>$response['oauth_token'],
+                                                               'secret'=>$response['oauth_token_secret'],
+                                                               'authorized'=>true
+                                                       );
+                                                       if(IsSet($response['oauth_expires_in']))
+                                                       {
+                                                               $expires = $response['oauth_expires_in'];
+                                                               if(strval($expires) !== strval(intval($expires))
+                                                               || $expires <= 0)
+                                                                       return($this->SetError('OAuth server did not return a supported type of access token expiry time'));
+                                                               $this->access_token_expiry = gmstrftime('%Y-%m-%d %H:%M:%S', time() + $expires);
+                                                               if($this->debug)
+                                                                       $this->OutputDebug('Access token expiry: '.$this->access_token_expiry.' UTC');
+                                                               $access_token['expiry'] = $this->access_token_expiry;
+                                                       }
+                                                       else
+                                                               $this->access_token_expiry = '';
+
+                                                       if(!$this->StoreAccessToken($access_token))
+                                                               return false;
+                                                       if($this->debug)
+                                                               $this->OutputDebug('The OAuth token was authorized');
+                                               }
+                                       }
+                                       elseif($this->debug)
+                                               $this->OutputDebug('The OAuth token was already authorized');
+                                       if(IsSet($access_token['authorized'])
+                                       && $access_token['authorized'])
+                                       {
+                                               $this->access_token = $access_token['value'];
+                                               $this->access_token_secret = $access_token['secret'];
+                                               return true;
+                                       }
+                               }
+                               else
+                               {
+                                       if($this->debug)
+                                               $this->OutputDebug('The OAuth access token is not set');
+                                       $access_token = array();
+                               }
+                               if(!IsSet($access_token['authorized']))
+                               {
+                                       if($this->debug)
+                                               $this->OutputDebug('Requesting the unauthorized OAuth token');
+                                       if(!$this->GetRequestTokenURL($url))
+                                               return false;
+                                       $url = str_replace('{SCOPE}', UrlEncode($this->scope), $url); 
+                                       if(!$this->GetRedirectURI($redirect_uri))
+                                               return false;
+                                       $oauth = array(
+                                               'oauth_callback'=>$redirect_uri,
+                                       );
+                                       $options = array('Resource'=>'OAuth request token');
+                                       $method = strtoupper($this->token_request_method);
+                                       switch($method)
+                                       {
+                                               case 'GET':
+                                                       break;
+                                               case 'POST':
+                                                       $options['PostValuesInURI'] = true;
+                                                       break;
+                                               default:
+                                                       $this->error = $method.' is not a supported method to request tokens';
+                                                       break;
+                                       }
+                                       if(!$this->SendAPIRequest($url, $method, array(), $oauth, $options, $response))
+                                               return false;
+                                       if(strlen($this->access_token_error))
+                                       {
+                                               $this->authorization_error = $this->access_token_error;
+                                               return true;
+                                       }
+                                       if(!IsSet($response['oauth_token'])
+                                       || !IsSet($response['oauth_token_secret']))
+                                       {
+                                               $this->authorization_error = 'it was not returned the requested token';
+                                               return true;
+                                       }
+                                       $access_token = array(
+                                               'value'=>$response['oauth_token'],
+                                               'secret'=>$response['oauth_token_secret'],
+                                               'authorized'=>false
+                                       );
+                                       if(!$this->StoreAccessToken($access_token))
+                                               return false;
+                               }
+                               if(!$this->GetDialogURL($url))
+                                       return false;
+                               $url .= (strpos($url, '?') === false ? '?' : '&').'oauth_token='.$access_token['value'];
+                               if(!$one_a)
+                               {
+                                       if(!$this->GetRedirectURI($redirect_uri))
+                                               return false;
+                                       $url .= '&oauth_callback='.UrlEncode($redirect_uri);
+                               }
+                               if($this->debug)
+                                       $this->OutputDebug('Redirecting to OAuth authorize page '.$url);
+                               Header('HTTP/1.0 302 OAuth Redirection');
+                               Header('Location: '.$url);
+                               $this->exit = true;
+                               return true;
+
+                       case 2:
+                               if($this->debug)
+                                       $this->OutputDebug('Checking if OAuth access token was already retrieved from '.$this->access_token_url);
+                               if(!$this->RetrieveToken($valid))
+                                       return false;
+                               if($valid)
+                                       return true;
+                               if($this->debug)
+                                       $this->OutputDebug('Checking the authentication state in URI '.$_SERVER['REQUEST_URI']);
+                               if(!$this->GetStoredState($stored_state))
+                                       return false;
+                               if(strlen($stored_state) == 0)
+                                       return($this->SetError('it was not set the OAuth state'));
+                               if(!$this->GetRequestState($state))
+                                       return false;
+                               if($state === $stored_state)
+                               {
+                                       if($this->debug)
+                                               $this->OutputDebug('Checking the authentication code');
+                                       if(!$this->GetRequestCode($code))
+                                               return false;
+                                       if(strlen($code) == 0)
+                                       {
+                                               if(!$this->GetRequestError($this->authorization_error))
+                                                       return false;
+                                               if(IsSet($this->authorization_error))
+                                               {
+                                                       if($this->debug)
+                                                               $this->OutputDebug('Authorization failed with error code '.$this->authorization_error);
+                                                       switch($this->authorization_error)
+                                                       {
+                                                               case 'invalid_request':
+                                                               case 'unauthorized_client':
+                                                               case 'access_denied':
+                                                               case 'unsupported_response_type':
+                                                               case 'invalid_scope':
+                                                               case 'server_error':
+                                                               case 'temporarily_unavailable':
+                                                               case 'user_denied':
+                                                                       return true;
+                                                               default:
+                                                                       return($this->SetError('it was returned an unknown OAuth error code'));
+                                                       }
+                                               }
+                                               return($this->SetError('it was not returned the OAuth dialog code'));
+                                       }
+                                       if(!$this->ProcessToken($code, false))
+                                               return false;
+                               }
+                               else
+                               {
+                                       if(!$this->GetRedirectURI($redirect_uri))
+                                               return false;
+                                       if(strlen($this->append_state_to_redirect_uri))
+                                               $redirect_uri .= (strpos($redirect_uri, '?') === false ? '?' : '&').$this->append_state_to_redirect_uri.'='.$stored_state;
+                                       if(!$this->GetDialogURL($url, $redirect_uri, $stored_state))
+                                               return false;
+                                       if(strlen($url) == 0)
+                                               return($this->SetError('it was not set the OAuth dialog URL'));
+                                       if($this->debug)
+                                               $this->OutputDebug('Redirecting to OAuth Dialog '.$url);
+                                       Header('HTTP/1.0 302 OAuth Redirection');
+                                       Header('Location: '.$url);
+                                       $this->exit = true;
+                               }
+                               break;
+
+                       default:
+                               return($this->SetError($this->oauth_version.' is not a supported version of the OAuth protocol'));
+               }
+               return(true);
+       }
+/*
+{metadocument}
+               </do>
+       </function>
+{/metadocument}
+*/
+
+/*
+{metadocument}
+       <function>
+               <name>Finalize</name>
+               <type>BOOLEAN</type>
+               <documentation>
+                       <purpose>Cleanup any resources that may have been used during the
+                               OAuth protocol processing or execution of API calls.</purpose>
+                       <usage>Always call this function as the last step after calling the
+                               functions <functionlink>Process</functionlink> or
+                               <functionlink>CallAPI</functionlink>.</usage>
+                       <returnvalue>This function returns <booleanvalue>1</booleanvalue> if
+                               the function cleaned up any resources successfully.</returnvalue>
+               </documentation>
+               <argument>
+                       <name>success</name>
+                       <type>BOOLEAN</type>
+                       <documentation>
+                               <purpose>Pass the last success state returned by the class or any
+                                       external code processing the class function results.</purpose>
+                       </documentation>
+               </argument>
+               <do>
+{/metadocument}
+*/
+       Function Finalize($success)
+       {
+               return($success);
+       }
+/*
+{metadocument}
+               </do>
+       </function>
+{/metadocument}
+*/
+
+/*
+{metadocument}
+       <function>
+               <name>Output</name>
+               <type>VOID</type>
+               <documentation>
+                       <purpose>Display the results of the OAuth protocol processing.</purpose>
+                       <usage>Only call this function if you are debugging the OAuth
+                               authorization process and you need to view what was its
+                               results.</usage>
+               </documentation>
+               <do>
+{/metadocument}
+*/
+       Function Output()
+       {
+               if(strlen($this->authorization_error)
+               || strlen($this->access_token_error)
+               || strlen($this->access_token))
+               {
+?>
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<title>OAuth client result</title>
+</head>
+<body>
+<h1>OAuth client result</h1>
+<?php
+                       if(strlen($this->authorization_error))
+                       {
+?>
+<p>It was not possible to authorize the application.<?php
+                               if($this->debug)
+                               {
+?>
+<br>Authorization error: <?php echo HtmlSpecialChars($this->authorization_error);
+                               }
+?></p>
+<?php
+                       }
+                       elseif(strlen($this->access_token_error))
+                       {
+?>
+<p>It was not possible to use the application access token.
+<?php
+                               if($this->debug)
+                               {
+?>
+<br>Error: <?php echo HtmlSpecialChars($this->access_token_error);
+                               }
+?></p>
+<?php
+                       }
+                       elseif(strlen($this->access_token))
+                       {
+?>
+<p>The application authorization was obtained successfully.
+<?php
+                               if($this->debug)
+                               {
+?>
+<br>Access token: <?php echo HtmlSpecialChars($this->access_token);
+                                       if(IsSet($this->access_token_secret))
+                                       {
+?>
+<br>Access token secret: <?php echo HtmlSpecialChars($this->access_token_secret);
+                                       }
+                               }
+?></p>
+<?php
+                               if(strlen($this->access_token_expiry))
+                               {
+?>
+<p>Access token expiry: <?php echo $this->access_token_expiry; ?> UTC</p>
+<?php
+                               }
+                       }
+?>
+</body>
+</html>
+<?php
+               }
+       }
+/*
+{metadocument}
+               </do>
+       </function>
+{/metadocument}
+*/
+
+};
+
+/*
+
+{metadocument}
+</class>
+{/metadocument}
+
+*/
+
+?>
\ No newline at end of file