#AutoIt3Wrapper_AU3Check_Parameters=-q -d -w 1 -w 2 -w 3 -w- 4 -w 5 -w 6 -w- 7
#include-once
#include <Crypt.au3>
#include <Date.au3>
#include <Array.au3>
#include "WinHttp.au3"

; #INDEX# =======================================================================================================================
; Title .........: Twitter
; AutoIt Version : 3.3.8.1
; Language ......: English
; Description ...: Twitter library REST API v1.1.
; Author(s) .....: inververs
; Requirements...: WinHttp library by trancexx http://www.autoitscript.com/forum/topic/84133-winhttp-functions/
; Version........: 1.0
; ===============================================================================================================================

; #CURRENT# =====================================================================================================================
;_Twitter_SetKeys
;_Twitter_Open
;_Twitter_Close
;_Twitter_Tweet
;_Twitter_ReTweet
; ===============================================================================================================================


; #INTERNAL_USE_ONLY# ==========================================================
;__Twitter_ProcessRequest
;__Twitter_CreateSignature
;__Twitter_Base64Encode
;__Twitter_PercentEncode
;__Twitter_EpochEncrypt
;__Twitter_HMACSHA1
; ==============================================================================

; #VARIABLES# ==================================================================
Global $__Twitter_aInternalData[1][6]
; ==============================================================================


; #FUNCTION# ====================================================================================================================
; Name...........: _Twitter_SetKeys
; Description ...: Set key for Twitter oAuth authorization
; Syntax.........: _Twitter_SetKeys($s_Consumer_key,$s_Consumer_secret,$s_Access_token,$s_Access_token_secret)
; Parameters ....: $s_Consumer_key   		- Consumer key
; Parameters ....: $s_Consumer_secret   	- Consumer secret
; Parameters ....: $s_Access_token			- Access token
; Parameters ....: $s_Access_token_secret   - Access token secret
; Return values .: no
; Author ........: inververs
; Modified.......:
; Remarks .......: Your application must have Access level	Read, write. Keep the "Consumer secret" a secret.
; Related .......:
; Link ..........: https://dev.twitter.com/docs/auth/tokens-devtwittercom
; Example .......: no
; ===============================================================================================================================
Func _Twitter_SetKeys($s_Consumer_key, $s_Consumer_secret, $s_Access_token, $s_Access_token_secret)
	$__Twitter_aInternalData[0][2] = $s_Consumer_key
	$__Twitter_aInternalData[0][3] = $s_Consumer_secret
	$__Twitter_aInternalData[0][4] = $s_Access_token
	$__Twitter_aInternalData[0][5] = $s_Access_token_secret
EndFunc   ;==>_Twitter_SetKeys

; #FUNCTION# ====================================================================================================================
; Name...........: _Twitter_Tweet
; Description ...: Updates the authenticating user's current status, also known as tweeting
; Syntax.........: _Twitter_Tweet($sData)
; Parameters ....: $sData   - Data to tweet
; Return values .: Returns Tweet details
; Author ........: inververs
; Modified.......:
; Remarks .......: The text of your status update, typically up to 140 characters.
; Related .......: _Twitter_ReTweet
; Link ..........: https://dev.twitter.com/docs/api/1.1/post/statuses/update
; Example .......: no
; ===============================================================================================================================
Func _Twitter_Tweet($sData)
	Local $s = 'https://api.twitter.com/1.1/statuses/update.json'
	Local $a[1][2] = [['status', $sData]]
	Local $aData = __Twitter_CreateSignature('POST', $s, $a)
	Return __Twitter_ProcessRequest($aData)
EndFunc   ;==>_Twitter_Tweet

; #FUNCTION# ====================================================================================================================
; Name...........: _Twitter_ReTweet
; Description ...: Retweets a tweet
; Syntax.........: _Twitter_ReTweet($sData)
; Parameters ....: $sData	- The numerical ID of the desired status
; Return values .: Returns the original tweet with retweet details embedded
; Author ........: inververs
; Modified.......:
; Remarks .......: Twitter will ignore attempts to perform duplicate retweets
; Related .......: _Twitter_Tweet
; Link ..........: https://dev.twitter.com/docs/api/1.1/post/statuses/retweet/%3Aid
; Example .......: no
; ===============================================================================================================================
Func _Twitter_ReTweet($sData)
	Local $s = 'https://api.twitter.com/1.1/statuses/retweet/' & $sData & '.json'
	Local $aData = __Twitter_CreateSignature('POST', $s)
	Return __Twitter_ProcessRequest($aData)
EndFunc   ;==>_Twitter_ReTweet


; #FUNCTION# ====================================================================================================================
; Name...........: _Twitter_Open
; Description ...: Connects to api.twitter.com
; Syntax.........: _Twitter_Open()
; Parameters ....: no
; Return values .: no
; Author ........: inververs
; Modified.......: no
; Remarks .......: Calling this function is necessarily
; Related .......: _Twitter_Close
; Link ..........: no
; Example .......: no
; ===============================================================================================================================
Func _Twitter_Open()
	_Crypt_Startup()
	$__Twitter_aInternalData[0][0] = _WinHttpOpen('Mozilla/5.0',$WINHTTP_ACCESS_TYPE_DEFAULT_PROXY)
	$__Twitter_aInternalData[0][1] = _WinHttpConnect($__Twitter_aInternalData[0][0], "api.twitter.com", $INTERNET_DEFAULT_HTTPS_PORT)
EndFunc   ;==>_Twitter_Open

; #FUNCTION# ====================================================================================================================
; Name...........: _Twitter_Close
; Description ...: Close the twitter connection hadle
; Syntax.........: _Twitter_Close()
; Parameters ....: no
; Return values .: no
; Author ........: inververs
; Modified.......: no
; Remarks .......: Calling this function is only needed if _Twitter_Open has been called
; Related .......: _Twitter_Open
; Link ..........: no
; Example .......: no
; ===============================================================================================================================
Func _Twitter_Close()
	_WinHttpCloseHandle($__Twitter_aInternalData[0][1])
	_WinHttpCloseHandle($__Twitter_aInternalData[0][0])
	_Crypt_Shutdown()
EndFunc   ;==>_Twitter_Close


; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: __Twitter_ProcessRequest
; Description ...: Send the request to the api.twitter.com
; Syntax.........: __Twitter_ProcessRequest($aData)
; Parameters ....: $aData - array returned by __Twitter_CreateSignature
; Return values .: String in JSON format
;				   - @extended status code http request
; Author ........: inververs
; Modified.......: no
; Remarks .......: no
; Related .......: __Twitter_CreateSignature
; Link ..........: no
; Example .......: no
; ===============================================================================================================================
Func __Twitter_ProcessRequest($aData)
	Local $hRequestSSL = _WinHttpSimpleSendSSLRequest($__Twitter_aInternalData[0][1], $aData[3], $aData[2], Default, $aData[0], $aData[1])
	Local $iStatusCode = _WinHttpQueryHeaders($hRequestSSL,$WINHTTP_QUERY_STATUS_CODE)
;~ 	Local $iStatusCode = _WinHttpQueryHeaders($hRequestSSL,$WINHTTP_QUERY_RAW_HEADERS_CRLF)
;~ 	ConsoleWrite($iStatusCode & @LF)
	Local $sReturned = _WinHttpSimpleReadData($hRequestSSL)
	_WinHttpCloseHandle($hRequestSSL)
	Return SetError(0,Number($iStatusCode),$sReturned)
EndFunc   ;==>__Twitter_ProcessRequest


; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: __Twitter_CreateSignature
; Description ...: Create a oauth head
; Syntax.........: __Twitter_CreateSignature($s_HTTP_Method, $s_Resource_URL [,$2D_Parameters])
; Parameters ....: $s_HTTP_Method - GET or POST method
;                  $s_Resource_URL - Resource URL
;                  $2D_Parameters - 2 array with additional Parameters
; Return values .: array for the __Twitter_ProcessRequest
; Author ........: inververs
; Modified.......:
; Remarks .......:
; Related .......: __Twitter_ProcessRequest
; Link ..........: https://dev.twitter.com/docs/auth/creating-signature
; Example .......: no
; ===============================================================================================================================
Func __Twitter_CreateSignature($s_HTTP_Method, $s_Resource_URL, $2D_Parameters = 0)
	Local $iresult_write
	Local $tTime = _Date_Time_GetSystemTime()
	Local $oauth_timestamp = __Twitter_EpochEncrypt(_Date_Time_SystemTimeToDateTimeStr($tTime, 1))
	Local $oauth_nonce = StringTrimLeft(_Crypt_HashData($oauth_timestamp, $CALG_MD5), 2)
	Local $aResult[6][2] = _
			[ _
			['oauth_consumer_key', $__Twitter_aInternalData[0][2]], _
			['oauth_nonce', $oauth_nonce], _
			['oauth_signature_method', 'HMAC-SHA1'], _
			['oauth_timestamp', $oauth_timestamp], _
			['oauth_token', $__Twitter_aInternalData[0][4]], _
			['oauth_version', '1.0'] _
			]
	Local $sPostData
	If IsArray($2D_Parameters) Then
		$iresult_write = UBound($aResult)
		ReDim $aResult[$iresult_write + UBound($2D_Parameters)][2]
		For $i2dindex = 0 To UBound($2D_Parameters) - 1
			$aResult[$iresult_write][0] = __Twitter_PercentEncode($2D_Parameters[$i2dindex][0])
			$aResult[$iresult_write][1] = __Twitter_PercentEncode($2D_Parameters[$i2dindex][1])
			$sPostData &= $aResult[$iresult_write][0] & '=' & $aResult[$iresult_write][1] & '&'
			$iresult_write += 1
		Next
		$sPostData = StringTrimRight($sPostData, 1)
	EndIf
	Local $aURL_data = _WinHttpCrackUrl($s_Resource_URL, $ICU_DECODE)
	If Not IsArray($aURL_data) Then Return SetError(1, 0, 0)
	If $aURL_data[7] Then
		$aURL_data[7] = StringRegExpReplace($aURL_data[7], '^\s*\?', '')
		Local $aCrack_query = StringRegExp($aURL_data[7], '(?m)([^=]+)=([^&]+)(?:&|$)', 3)
		If IsArray($aCrack_query) Then
			$iresult_write = UBound($aResult)
			ReDim $aResult[$iresult_write + Int(UBound($aCrack_query) / 2)][2]
			For $iquery_index = 0 To UBound($aCrack_query) - 1 Step 2
				$aResult[$iresult_write][0] = __Twitter_PercentEncode($aCrack_query[$iquery_index])
				$aResult[$iresult_write][1] = __Twitter_PercentEncode($aCrack_query[$iquery_index + 1])
				$iresult_write += 1
			Next
		EndIf
	EndIf
	Local $sURL = $aURL_data[0] & '://' & $aURL_data[2] & $aURL_data[6]
	_ArraySort($aResult)
	# Collecting parameters
	Local $sParameterString = ''
	For $iresult_index = 0 To UBound($aResult) - 1
		$sParameterString &= $aResult[$iresult_index][0] & '=' & $aResult[$iresult_index][1] & '&'
	Next
	$sParameterString = StringTrimRight($sParameterString, 1)
	# Creating the signature base string
	Local $Signature_base_string = _
			StringUpper($s_HTTP_Method) & '&' _
			 & __Twitter_PercentEncode($sURL) & '&' _
			 & __Twitter_PercentEncode($sParameterString)
	# Getting a signing key
	Local $Signing_key = __Twitter_PercentEncode($__Twitter_aInternalData[0][3]) & '&' & __Twitter_PercentEncode($__Twitter_aInternalData[0][5])
	# Calculating the signature
	Local $oauth_signature = __Twitter_Base64Encode(__Twitter_HMACSHA1($Signing_key, $Signature_base_string))
	$oauth_signature = __Twitter_PercentEncode(StringStripWS($oauth_signature, 3))
	Local $sHead
	Select
		Case $s_HTTP_Method = 'POST'
			$sHead &= 'Content-Type: application/x-www-form-urlencoded' & @CRLF
		Case $s_HTTP_Method = 'GET'
			$sPostData = Default
			$aURL_data[6] &= '?' & $aURL_data[7]
	EndSelect
	$sHead &= 'Authorization: OAuth ' _
			 & 'oauth_consumer_key="' & $__Twitter_aInternalData[0][2] & '", ' _
			 & 'oauth_nonce="' & $oauth_nonce & '", ' _
			 & 'oauth_signature="' & $oauth_signature & '", ' _
			 & 'oauth_signature_method="HMAC-SHA1", ' _
			 & 'oauth_timestamp="' & $oauth_timestamp & '", ' _
			 & 'oauth_token="' & $__Twitter_aInternalData[0][4] & '", ' _
			 & 'oauth_version="1.0"'
	Local $aRet[4] = [$sPostData, $sHead, $aURL_data[6], $s_HTTP_Method]
	Return SetError(0, 0, $aRet)
EndFunc   ;==>__Twitter_CreateSignature


; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: __Twitter_Base64Encode
; Description ...: Do Base64 Encoding
; Syntax.........: __Twitter_Base64Encode($input)
; Parameters ....: $input	- data to encode
; Return values .: Success	- Base64 Encoding string
;							- Sets @error to 0
;                  Failure - Returns blank string and sets @error:
;                  |1 - error calculating the length of the buffer needed
;                  |2 - error encoding
; Author ........: trancexx
; Modified.......:
; Remarks .......: Client  - Requires Windows Vista or Windows XP. Server - Requires Windows Server 2008 or Windows Server 2003.
; Related .......:
; Link ..........: http://www.autoitscript.com/forum/topic/81332-base64encode-base64decode/
; Example .......: no
; ===============================================================================================================================
Func __Twitter_Base64Encode($input)
	$input = Binary($input)
	Local $struct = DllStructCreate("byte[" & BinaryLen($input) & "]")
	DllStructSetData($struct, 1, $input)
	Local $strc = DllStructCreate("int")
	Local $a_Call = DllCall("Crypt32.dll", "int", "CryptBinaryToString", _
			"ptr", DllStructGetPtr($struct), _
			"int", DllStructGetSize($struct), _
			"int", 1, _
			"ptr", 0, _
			"ptr", DllStructGetPtr($strc))
	If @error Or Not $a_Call[0] Then
		Return SetError(1, 0, "")
	EndIf
	Local $a = DllStructCreate("char[" & DllStructGetData($strc, 1) & "]")
	$a_Call = DllCall("Crypt32.dll", "int", "CryptBinaryToString", _
			"ptr", DllStructGetPtr($struct), _
			"int", DllStructGetSize($struct), _
			"int", 1, _
			"ptr", DllStructGetPtr($a), _
			"ptr", DllStructGetPtr($strc))
	If @error Or Not $a_Call[0] Then
		Return SetError(2, 0, "")
	EndIf
	Return DllStructGetData($a, 1)
EndFunc   ;==>__Twitter_Base64Encode

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: __Twitter_PercentEncode
; Description ...: URL encoding process
; Syntax.........: __Twitter_PercentEncode($sData)
; Parameters ....: $sData	- data to process
; Return values .: URL encoding data
; Author ........: inververs
; Modified.......:
; Remarks .......: No plus encoded
; Related .......:
; Link ..........: https://dev.twitter.com/docs/auth/percent-encoding-parameters
; Example .......: no
; ===============================================================================================================================
Func __Twitter_PercentEncode($sData)
	Local $aData = StringToASCIIArray($sData, Default, Default, 2)
	Local $sOut
	For $i = 0 To UBound($aData) - 1
		Switch $aData[$i]
			Case 45, 46, 48 To 57, 65 To 90, 95, 97 To 122, 126
				$sOut &= Chr($aData[$i])
			Case Else
				$sOut &= "%" & Hex($aData[$i], 2)
		EndSwitch
	Next
	Return $sOut
EndFunc   ;==>__Twitter_PercentEncode

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: __Twitter_EpochEncrypt
; Description ...: Calculate the Timestamp
; Syntax.........: __Twitter_EpochEncrypt($date)
; Parameters ....: $date	- time string yyyy/mm/dd hh:mm:ss formatted
; Return values .: Success	- number of seconds since the Unix epoch
;							- Sets @error to 0
;                  Failure - Returns blank string and sets @error:
;                  1 - invalid time format
; Author ........: trancexx
; Modified.......:
; Remarks .......:
; Related .......:
; Link ..........: http://www.autoitscript.com/forum/topic/83667-epoch-time
; Example .......: no
; ===============================================================================================================================
Func __Twitter_EpochEncrypt($date)
	Local $main_split = StringSplit($date, " ")
	If $main_split[0] - 2 Then
		Return SetError(1, 0, "")
	EndIf
	Local $asDatePart = StringSplit($main_split[1], "/")
	Local $asTimePart = StringSplit($main_split[2], ":")
	If $asDatePart[0] - 3 Or $asTimePart[0] - 3 Then
		Return SetError(1, 0, "")
	EndIf
	If $asDatePart[2] < 3 Then
		$asDatePart[2] += 12
		$asDatePart[1] -= 1
	EndIf
	Local $i_aFactor = Int($asDatePart[1] / 100)
	Local $i_bFactor = Int($i_aFactor / 4)
	Local $i_cFactor = 2 - $i_aFactor + $i_bFactor
	Local $i_eFactor = Int(1461 * ($asDatePart[1] + 4716) / 4)
	Local $i_fFactor = Int(153 * ($asDatePart[2] + 1) / 5)
	Local $aDaysDiff = $i_cFactor + $asDatePart[3] + $i_eFactor + $i_fFactor - 2442112
	Local $iTimeDiff = $asTimePart[1] * 3600 + $asTimePart[2] * 60 + $asTimePart[3]
	Return SetError(0, 0, $aDaysDiff * 86400 + $iTimeDiff)
EndFunc   ;==>__Twitter_EpochEncrypt


; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name...........: __Twitter_HMACSHA1
; Description ...: implements HMAC-SHA1 hashing algorithm (keyed-hash message authentication code)
; Syntax.........: __Twitter_HMACSHA1($key, $message)
; Parameters ....: $key	- key
;				   $message - message
; Return values .: binary hash
; Author ........: SkinnyWhiteGuy
; Modified.......: inververs
; Remarks .......:
; Related .......:
; Link ..........: http://en.wikipedia.org/wiki/HMAC|http://www.autoitscript.com/forum/topic/145556-solved-hmac-sha1/
; Example .......: no
; ===============================================================================================================================
Func __Twitter_HMACSHA1($key, $message)
	Local $blocksize = 64
	Local $a_opad[$blocksize], $a_ipad[$blocksize]
	Local Const $oconst = 0x5C, $iconst = 0x36
	Local $opad = Binary(''), $ipad = Binary('')
	$key = Binary($key)
	If BinaryLen($key) > $blocksize Then $key = _Crypt_HashData($key, $CALG_SHA1)
	For $i = 1 To BinaryLen($key)
		$a_ipad[$i - 1] = Number(BinaryMid($key, $i, 1))
		$a_opad[$i - 1] = Number(BinaryMid($key, $i, 1))
	Next
	For $i = 0 To $blocksize - 1
		$a_opad[$i] = BitXOR($a_opad[$i], $oconst)
		$a_ipad[$i] = BitXOR($a_ipad[$i], $iconst)
	Next
	For $i = 0 To $blocksize - 1
		$ipad &= Binary('0x' & Hex($a_ipad[$i], 2))
		$opad &= Binary('0x' & Hex($a_opad[$i], 2))
	Next
	Return _Crypt_HashData($opad & _Crypt_HashData($ipad & Binary($message), $CALG_SHA1), $CALG_SHA1)
EndFunc   ;==>__Twitter_HMACSHA1