#INCLUDE "hbClass.ch"
#include "hbcurl.ch"
#include "fivewin.ch"
#include "tdata.ch"
CLASS TTwilioSMS
// Class Data
DATA cAcctSID
DATA cAuthToken
DATA cAcctPhone
DATA hCurl
DATA httpcode
DATA cLogFile INIT "Twilio.log"
DATA cResponse
DATA cDestinationNum
DATA cSMSscript
DATA cUrl
DATA nError INIT 0
DATA nMaxLogSize INIT 32768
DATA cDateStart, cDateEnd
DATA cvoiceMail, cReplyEmail
DATA lDebug INIT .F.
// Class Methods
METHOD New()
METHOD End()
METHOD Send()
METHOD Reset()
METHOD GetMessagesLog()
ENDCLASS
//------------------------------------------------------------------------------------------------
METHOD New( cTo, cText ) CLASS TTwilioSMS
// Initialize the class
::hCurl := curl_easy_init()
// Obtain data constants
oConfig := tConfig():New()
::cAcctSID := TRIM( oConfig:sysus25 ). // Account number, stored in the dbf file
::cAuthToken := TRIM( oConfig:sysus26 ) // Authorization code also stored in the dbf file
::cAcctPhone := TRIM( oConfig:sysus27 ) // The Twillio phone number assigned to the client.
oConfig:close()
::cUrl := "https://api.twilio.com/2010-04-01/Accounts/" + TRIM( ::cAcctSID ) + "/Messages.json"
RETURN Self
//------------------------------------------------------------------------------------------------
METHOD Send( cTo, cText, cAcrnum, cWrkord ) CLASS TTwilioSMS
Local cPostFields, lDidSend := .f.
Local httpcode, hInitData := { => }
// Set the text and desitination
::cDestinationNum := cTo
::cSMSscript := cText
// Setup cURL options
curl_easy_setopt( ::hCurl, HB_CURLOPT_POST, 1 )
curl_easy_setopt( ::hCurl, HB_CURLOPT_URL, ::cUrl )
curl_easy_setopt( ::hCurl, HB_CURLOPT_USERPWD, ::cAcctSID + ':' + ::cAuthToken )
curl_easy_setopt( ::hCurl, HB_CURLOPT_DL_BUFF_SETUP )
curl_easy_setopt( ::hCurl, HB_CURLOPT_SSL_VERIFYPEER, .F. )
cPostFields := 'To=' + ::cDestinationNum + ; // Line[ 3 ] +;
'&From=' + ::cAcctPhone +;
'&Body=' + curl_easy_escape( ::hCurl, AllTrim( ::cSMSscript ) )
curl_easy_setopt( ::hcurl, HB_CURLOPT_POSTFIELDS, cPostFields )
::nError := curl_easy_perform( ::hCurl )
curl_easy_getinfo( ::hCurl, HB_CURLINFO_RESPONSE_CODE, @httpcode )
::httpcode := httpcode
// If the initialization is OK, run the process
IF ::nError = HB_CURLE_OK
::cResponse = curl_easy_dl_buff_get( ::hCurl )
lDidSend := .t.
Else
cReply := "Text send failure"
ENDIF
// Lets decode the response
hb_JsonDecode( ::cResponse, @hInitData )
cReply := HB_HGET( hInitData, "sid") // Message id
// Lets append a log entry
oUsers := tdata():new(, "twlog" )
oUsers:use()
oUsers:append()
oUsers:smsdate := DATE()
oUsers:smstime := TIME()
oUsers:smsto := ::cDestinationNum
oUsers:smsbody := ::cSMSscript
oUsers:acrnum := cAcrnum
oUsers:wrkord := cWrkord
oUsers:SMSmode := "S"
oUsers:SMStype := "G"
oUsers:SMSreply := cReply
oUsers:save()
oUsers:close()
return( lDidSend )
//------------------------------------------------------------------------------------------------
METHOD Reset() CLASS TTwilioSMS
curl_easy_reset( ::hCurl )
return NIL
//------------------------------------------------------------------------------------------------
METHOD End() CLASS TTwilioSMS
curl_easy_cleanup( ::hCurl )
::hCurl := Nil
hb_gcAll( .t. )
return NIL
//------------------------------------------------------------------------------------------------
//must define ::cDateStart and ::cDateEnd before calling this method.
METHOD GetMessagesLog() CLASS TTwilioSMS
Local cparms := '?DateSent%3E=' + ::cDateStart + "&DateSent%3C=" + ::cDateEnd + "&PageSize=600"
Local httpcode
curl_easy_setopt( ::hCurl, HB_CURLOPT_HTTPGET, 1 )
curl_easy_setopt( ::hCurl, HB_CURLOPT_URL, ::cUrl + cParms )
curl_easy_setopt( ::hCurl, HB_CURLOPT_USERPWD, cAcctSID + ':' + cAuthToken )
curl_easy_setopt( ::hCurl, HB_CURLOPT_DL_BUFF_SETUP )
curl_easy_setopt( ::hCurl, HB_CURLOPT_SSL_VERIFYPEER, .F. )
::nError := curl_easy_perform( ::hCurl )
curl_easy_getinfo( ::hCurl, HB_CURLINFO_RESPONSE_CODE, @httpcode )
::httpcode := httpcode
IF ::nError = HB_CURLE_OK
::cResponse = curl_easy_dl_buff_get( ::hCurl )
::cResponse := StrTran( ::cResponse, Chr(10), "" )
Else
/*
LogData( ::cLogFile, { "Twilio error sending SMS. Details below:" }, ::nMaxLogSize )
LogData( ::cLogFile, { "To", ::cDestinationNum, "SMS Text:", ::cSMSscript }, ::nMaxLogSize )
LogData( ::cLogFile, { "Error Num:", ::nError, "Httpcode:", ::httpcode }, ::nMaxLogSize )
LogData( ::cLogFile, curl_easy_strerror( ::nError ), ::nMaxLogSize )
*/
ENDIF
MemoWrit( "Twilio.log", ::cResponse )
RETURN NIL
/*
Send an SMS text with cTo, cBody, cAcrNum, cWrkord
*/
FUNCTION SendSMS( cTo, cAcrNum, cWrkOrd )
LOCAL oTest, lOK := .f., lDoSend := .f., cScript := " ", lx := 0, cToC := ""
LOCAL cBody := SPACE(300), aSMScode := {}, aSMSscript := {}
DEFAULT cTo := " ", cAcrNum := " ", cWrkOrd := " "
// Load scripts array
AADD( aSMScode, " ")
AADD( aSMSscript, " ")
oESMS := tData():New( ,"SMSscript" )
oESMS:Use()
oESMS:gotop()
DO WHILE ! oESMS:EOF()
AADD( aSMScode, oESMS:smscode )
AADD( aSMSscript, oESMS:SMSscript )
oESMS:skip()
ENDDO
oESMS:close()
// Provide for edit of text
DEFINE DIALOG oeText RESOURCE "ETEXT" BRUSH oBrush TRANSPARENT // OF oWnd
REDEFINE GET cTo ID 100 OF oeText PICTURE "##################" MESSAGE "Enter the phone number to which you are sending the message"
REDEFINE GET cAcrNum ID 101 OF oeText MESSAGE "Enter the client account number"
REDEFINE GET cWrkOrd ID 102 OF oeText MESSAGE "Enter the workorder number"
REDEFINE COMBOBOX oCbxA1 VAR cScript ID 106 OF oeText ;
ITEMS aSMScode ON CHANGE ( lx := oCbxA1:nAt, cBody := aSMSscript[lx], oGet1:refresh() ) ;
MESSAGE "Select a script" STYLE CBS_DROPDOWN UPDATE
REDEFINE GET oGet1 VAR cBody MEMO ID 103 OF oeText MESSAGE "Enter the text of your message" UPDATE
REDEFINE BTNBMP ID 104 OF oeText RESOURCE "HROK" PROMPT "Send" NOBORDER TRANSPARENT ;
ACTION ( lDoSend := .t., oeText:end() ) MESSAGE "Send the SMS text message"
REDEFINE BTNBMP ID 105 OF oeText RESOURCE "HREXIT" PROMPT "Cancel" NOBORDER TRANSPARENT ;
ACTION oeText:end() MESSAGE "Cancel the text message"
// Activate the dialog
ACTIVATE DIALOG oeText CENTER
IF lDoSend
// Clean the phone number
cTo := "+1" + CharOnly( "0123456789", cTo)
// Send the text
oTest := tTwilioSMS():New( )
lOK := oTest:Send( cTo, cBody, cAcrnum, cWrkord )
oTest:End()
// Show Result
IF lOK
MsgInfo( "Your text message was sent" )
ELSE
MsgInfo( "There was an error sending your message" )
ENDIF
ENDIF
RETURN NIL
FUNCTION TwilioSetup
// Declare EXTERNAL variables
MEMVAR oWnd
// Declare LOCAL variables
LOCAL ofBrush, cTitle := "Twilio SMS Account Setup", lOK := .f.
LOCAL oDlg, cAcctSID, cAuthToken, cAcctPhone, lUseTwilio
oConfig := tConfig():New()
cAcctSID := oConfig:sysus25
cAuthToken := oConfig:sysus26
cAcctPhone := oConfig:sysus27
lUseTwilio := oConfig:sysuf12
oConfig:close()
// Create the dialog
DEFINE DIALOG oDlg RESOURCE "TWILIO" BRUSH oBrush TRANSPARENT TITLE cTitle
// Create the button controls
REDEFINE BTNBMP RESOURCE "HROK" ID 332 of oDlg PROMPT "Accept" NOBORDER TRANSPARENT ;
ACTION ( lOk := .t., oDlg:End( ) ) MESSAGE "Use the values entered above"
REDEFINE BTNBMP RESOURCE "HREXIT" ID 333 of oDlg PROMPT "Cancel" NOBORDER TRANSPARENT ;
ACTION ( oDlg:End( ), lOk := .f. ) MESSAGE "Exit without using these values"
// Now add the edit controls
REDEFINE GET cAcctSID ID 339 OF oDlg
REDEFINE GET cAuthToken ID 338 OF oDlg
REDEFINE GET cAcctPhone ID 337 OF oDlg
REDEFINE CHECKBOX lUseTwilio ID 336 OF oDlg
// Activate the dialog
ACTIVATE DIALOG oDlg CENTERED
IF lOk // If desired, return the get values
oConfig := tConfig():New()
oConfig:sysus25 := cAcctSID
oConfig:sysus26 := cAuthToken
oConfig:sysus27 := cAcctPhone
oConfig:sysuf12 := lUseTwilio
oConfig:save()
oConfig:close()
ENDIF
RETURN NIL
FUNCTION TextLogView( cView, cValue )
LOCAL oELog, oBrw, bDate := DATE(), eDate := DATE( )
oELog := tData():New( ,"twlog" )
oELog:Use()
IF cView = "D"
DateGet2( "Text Date Range Browse", "Beginning date:", @bDate, "Ending date:", @eDate )
oELog:setorder(1)
oELog:setscopetop( bdate )
oELog:setscopebottom( edate )
ELSEIF cView = "A"
oELog:setorder(2)
oELog:setscopetop( cValue )
oELog:setscopebottom( cValue )
ELSEIF cView = "W"
oELog:setorder(3)
oELog:setscopetop( cValue )
oELog:setscopebottom( cValue )
ENDIF
oELog:gotop()
oBrw := XBROWSER oELog TITLE "Sent Email Log" SETUP oBrw:cHeaders := { "Date", "Time", "To", "Message", "Account", "Order", "Type", "Mode", "Response"} AUTOFIT
oELog:close( )
RETURN NIL
Function SMSscripts
// Create scripts list
// Open script database
oESMS := tData():New( ,"SMSscript" )
oESMS:Use()
oESMS:gotop()
// Open the dialog using a resource from EMS.DLL
DEFINE DIALOG oDlg RESOURCE "ESCRIPTS" BRUSH oBrush transparent OF oWnd TITLE "Text message scripts"
oDlg:nHelpID := 5
// Build the edit controls
REDEFINE SAY oSa1 PROMPT "Code" ID 4900 OF oDlg
REDEFINE GET oESMS:SMScode ID 102 OF oDlg MESSAGE "The script code" UPDATE
REDEFINE SAY oSa2 PROMPT "Script" ID 4901 OF oDlg
REDEFINE GET oESMS:SMSscript ID 103 OF oDlg MESSAGE "Enter a script for this code" UPDATE
REDEFINE XBROWSE oLbx1 ;
DATASOURCE oESMS ;
HEADERS " Code ", " SCRIPT ", " " ;
COLUMNS "SMScode", "SMSscript", " " ;
ON CHANGE oDlg:update() ;
ID 101 OF oDlg ;
UPDATE
// Provide the header gradient
oLbx1:bClrGrad := aPubGrad
// Set the styles
oLbx1:nMarqueeStyle := MARQSTYLE_HIGHLROW
oLbx1:nColDividerStyle := LINESTYLE_RAISED
oLbx1:nRowDividerStyle := LINESTYLE_RAISED
oLbx1:nHeadStrAligns := AL_CENTER
oLbx1:nStretchCol := STRETCHCOL_LAST
REDEFINE BUTTONBAR oBarLst ID 105 SIZE 60,60 OF oDlg 2015
oBarLst:bClrGrad := aPubGrad
// Build the button controls
DEFINE BUTTON OF oBarLst RESOURCE "HRADD" PROMPT "Add" TOOLTIP "Add a record" ;
ACTION ( oLbx1:gobottom(), oESMS:append( ), oESMS:blank( ), oLbx1:refresh(), oDlg:update( ) ) ;
MESSAGE "Add a new item"
DEFINE BUTTON OF oBarLst RESOURCE "HRSAVE" PROMPT "Save" TOOLTIP "Save changes" ;
ACTION ( oESMS:save( ), oDlg:update( ), oLbx1:refresh(), oLbx1:setfocus( ) ) ;
MESSAGE "Save any changes made to the current item"
DEFINE BUTTON OF oBarLst RESOURCE "HRDELETE" PROMPT "Delete" TOOLTIP "Delete selected record" ;
ACTION ( IIF( MsgYesNo( "Do you wish to delete this item ?"), ( oESMS:delete( ),;
oESMS:skip(1), oLbx1:refresh(), oDlg:update()),)) MESSAGE "Delete the current item"
DEFINE BUTTON OF oBarLst RESOURCE "HREXIT" PROMPT "Exit" TOOLTIP "Exit this list" ;
ACTION oDlg:end() MESSAGE "Exit this list" GROUP BTNRIGHT
// Activate the dialog screen
ACTIVATE DIALOG oDlg ON INIT (oReBar:hide(), oBarLst:lTransparent := .F.) CENTERED
// Redisplay the bar
oReBar:show()
// Close the database
oESMS:close()
RETURN NIL