EZTexting Send Message

EZTexting Send Message

Postby byron.hopp » Tue Jul 02, 2024 7:18 pm

I have this example for sending a text message using cUrl:
curl --request POST \
--url https://a.eztexting.com/v1/messages \
--header 'accept: */*' \
--header 'authorization: Basic YmhvcHBAbWF0cml4Y29tcHV0ZXIuY29tOjc3U2V2ZW50eVNldmVuIQ==' \
--header 'content-type: application/json' \
--data '
{
"message": "Test of EzTexting",
"toNumbers": [
"17147263600"
]
}

How do I duplicate this in Fivewin, seems like there is a set of curl functions.

I tried doing this:

Function SendTextEZ()
Local oParms := GetEmptyHash()
Local cParms := ""
Local cEndPoint := ""
Local cResponse := ""
Local oResponse := nil
Local nResponse := 0
Local oHttp := CreateObject( "MSXML2.XmlHttp" )
Local cLogFile := Mcs_AppPath() + "JSONSend.txt"

If File( cLogFile )
Ferase( cLogFile )
Endif

Begin Sequence
oParms["message" ] := "Test Text from the EZ Texting API."
oParms["PhoneNumbers"] := { "17147263600" }

cParms := hb_JsonEncode( oParms )
cEndPoint := [https:] + [/] + [/] + [a.eztexting.com/v1/messages]

oHttp:Open( "POST",cEndPoint,.f. )

oHttp:SetRequestHeader( 'accept','*' + [/] + '*' )
oHttp:SetRequestHeader( 'authorization','Basic MyEncryptedUserNamePassWordString' )
oHttp:SetRequestHeader( 'content-type', 'application/json' )

Logit( cLogFile,"EndPoint:" + cEndPoint )
Logit( cLogFile,"Parameters:" + cParms )

oHttp:Send( cParms )

If oHttp:status == 200 .OR. oHttp:status == 201
cResponse := oHttp:ResponseText()
nResponse := hb_JsonDecode( cResponse,@oResponse )
Else
MsgStop( oHttp:status,oHttp:statusText )
Endif
End Sequence
oHttp := nil
Return nil

Always get 401 error.

Thanks,
Thanks,
Byron Hopp
Matrix Computer Services
byron.hopp
 
Posts: 382
Joined: Sun Nov 06, 2005 3:55 pm
Location: Southern California, USA

Re: EZTexting Send Message

Postby TimStone » Wed Jul 03, 2024 1:09 am

I use Twillio for an SMS service. I wanted to see if my clients would actually use it, so I did not expand the class to include receiving replies. That is a whole other layer of complication, but I may do it.

Here is my complete program which includes logging, and also the ability to do scripts ( which I call from a button on the button bar, where it applies ).

I hope this helps.

Tim

Code: Select all  Expand view

#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
 
Tim Stone
http://www.MasterLinkSoftware.com
http://www.autoshopwriter.com
timstone@masterlinksoftware.com
Using: FWH 23.10 with Harbour 3.2.0 / Microsoft Visual Studio Community 2022-24 32/64 bit
User avatar
TimStone
 
Posts: 2944
Joined: Fri Oct 07, 2005 1:45 pm
Location: Trabuco Canyon, CA USA

Re: EZTexting Send Message

Postby byron.hopp » Wed Jul 03, 2024 2:52 am

Wow Tim, Thanks. I'll check it out.
Thanks,
Byron Hopp
Matrix Computer Services
byron.hopp
 
Posts: 382
Joined: Sun Nov 06, 2005 3:55 pm
Location: Southern California, USA

Re: EZTexting Send Message

Postby byron.hopp » Mon Jul 08, 2024 11:34 pm

Is there any documentation on the Curl lib in Harbour. Seems I have several examples of curl using C++ but some of the commands do not exists in the harbour curl ch file. Mr. Stone has left a very complete class, but I am working with EXTexting, and his class is for Twillo. It may be worth switching to Twillo in the long run. I already have an account with EZTexting.
Thanks,
Byron Hopp
Matrix Computer Services
byron.hopp
 
Posts: 382
Joined: Sun Nov 06, 2005 3:55 pm
Location: Southern California, USA

Re: EZTexting Send Message

Postby byron.hopp » Mon Jul 08, 2024 11:40 pm

Here is a code example, but I am guessing, WHACK == "/"
Function SendTextCurl()
Local aHeaders := {}
Local oCurl := curl_easy_init()
Local uRet := nil

curl_easy_setopt( oCurl,HB_CURLOPT_CUSTOM_REQUEST,"POST" )
curl_easy_setopt( oCurl,HB_CURLOPT_WRITEDATA ,stdout )
curl_easy_setopt( oCurl,HB_CURLOPT_URL ,"https:" + WHACK + WHACK +"a.eztexting.com/v1/messages" )

AAdd( aHeaders,"accept: *" + WHACK + "*")
AAdd( aHeaders,"content-type: application/json" )
AAdd( aHeaders,"authorization: Basic XXXXOOOOMyPasswordXXXXOOOO" )

curl_easy_setopt( oCurl,HB_CURLOPT_HTTPHEADER, aHeaders )
curl_easy_setopt( oCurl,HB_CURLOPT_POSTFIELDS,[{"message":"Test Text from the EZ Texting API.","PhoneNumbers":["17147263600"]}] )

uRet := curl_easy_preform( oCurl )
MsgInfo( uRet,"Curl Ret" )
Return nil
Thanks,
Byron Hopp
Matrix Computer Services
byron.hopp
 
Posts: 382
Joined: Sun Nov 06, 2005 3:55 pm
Location: Southern California, USA

Re: EZTexting Send Message

Postby TimStone » Tue Jul 09, 2024 3:12 am

If you look at my code you will see it implemented. I am out of the office this week but will send yo curl info as soon as possible


Sent from my iPhone using Tapatalk
Tim Stone
http://www.MasterLinkSoftware.com
http://www.autoshopwriter.com
timstone@masterlinksoftware.com
Using: FWH 23.10 with Harbour 3.2.0 / Microsoft Visual Studio Community 2022-24 32/64 bit
User avatar
TimStone
 
Posts: 2944
Joined: Fri Oct 07, 2005 1:45 pm
Location: Trabuco Canyon, CA USA

Re: EZTexting Send Message

Postby byron.hopp » Tue Jul 09, 2024 5:27 pm

I'll look forward to it. Have a great time off.
Byron ...
Thanks,
Byron Hopp
Matrix Computer Services
byron.hopp
 
Posts: 382
Joined: Sun Nov 06, 2005 3:55 pm
Location: Southern California, USA

Re: EZTexting Send Message

Postby reinaldocrespo » Tue Jul 16, 2024 12:27 pm

Hello Byron and Tim;

This link will show you my initial post when I shared the TTwilio class on this forum back in 2022: https://forums.fivetechsupport.com/viewtopic.php?f=3&t=40019&sid=9aaac815084955aeea18479527c26320
And you can see I'm not using aHeaders here. Instead I allow curl_easy_setopt() do the job.

I have expanded the class to send WhatsApp, Voice calls, and receive texts back and forth. I use it to send patients reminders about their appointments and receive confirmations or cancellations back via SMS. However, at this point I'm interested on learning about how you plan on sending texts without a service like Twilio. Twilio is a paid for service. Not expensive but still there is an ongoing cost to sending and receiving texts and as you add voice calls and WhatsApp, more costs are added.

I'm interested on learning about the service you intend to use. I will be glad to write code if it turns out to be a better or less expensive option than Twilio. Please share this information.

Thank you.
User avatar
reinaldocrespo
 
Posts: 979
Joined: Thu Nov 17, 2005 5:49 pm
Location: Fort Lauderdale, FL

Re: EZTexting Send Message

Postby TimStone » Tue Jul 16, 2024 5:01 pm

Reinaldo,

I am using Twillio outbound, but would love to see your implementation for inbound text messages.

Tim
Tim Stone
http://www.MasterLinkSoftware.com
http://www.autoshopwriter.com
timstone@masterlinksoftware.com
Using: FWH 23.10 with Harbour 3.2.0 / Microsoft Visual Studio Community 2022-24 32/64 bit
User avatar
TimStone
 
Posts: 2944
Joined: Fri Oct 07, 2005 1:45 pm
Location: Trabuco Canyon, CA USA


Return to FiveWin for Harbour/xHarbour

Who is online

Users browsing this forum: No registered users and 79 guests