Hello, @mrizkowsky
In that case you’ll need a webhook to accept the SMS, and a dialplan to process the incoming and outgoing SMS
Below you’ll find a node.js express server which you can use to accept and parse the incoming SMS and add it to a call file which will take it to the dialplan for processing,
For this to work you’ll need the below,
- Create a temp directory in the same directory the script is in, it’s used to create the call file before being moved to the asterisk spooler
- Install all packages required by the script
- Run the application in the background, you can create a service or start it with pm2
- Open port 8888 in your direwall, you can limit it to skyetel SMS IP (52.14.37.123)
- Get a SID and Secret from your skyetel account, used to authenticate when sending outbound messages.
- Create a file with the custom dialplans (i.e. /etc/asterisk/vitalpbx/extensions__90-custom.conf)
Webhook for inbound
#!/usr/bin/env node
const fs = require('fs')
const {exec} = require('child_process')
const express = require('express')
const cors = require("cors")
const bodyParse = require('body-parser')
const app = express()
const port = 8888;
app.use(cors())
app.use(bodyParse.json({limit:'1mb',}))
app.post('/', (req, res) => {
const {from, to, text} =req.body
if(!from || !to||!text)return res.status(422).send('An unexpected error occured')
const sanitzisedText = text.replace(/[^\w ]/g,'')
const fileName = `temp/${new Date().toISOString().match(/^[^\.]+/)[0]}.call`
fs.writeFileSync(fileName,
`Channel: Local/s@dummy-answer
Callerid: "SMS" <${from}>
Context: skyetel-sms
Extension: s
Priority: 1
Setvar: from=${from}
Setvar: to=${to}
Setvar: body=${sanitzisedText}`)
fs.renameSync(fileName, fileName.replace('temp','/var/spool/asterisk/outgoing/'))
res.send('Success!')
})
app.listen(port, () => {
try {
fs.readdirSync('temp')
} catch (error) {
fs.mkdirSync('temp')
}
console.log(`SMS app listening at http://localhost:${port}`)
})
Inbound Dialplan
[dummy-answer]
exten => s,1,Answer()
same => n,Wait(5)
same => n,Hangup()
[skyetel-sms]
exten => s,1,Answer()
same => n,Set(SMS_FROM=${FILTER(0-9,${from})})
same => n,Set(SMS_TO=${FILTER(0-9,${to})})
same => n,Set(MESSAGE(body)=${body})
same => n,Noop(From: ${SMS_FROM})
same => n,Noop(TO: ${SMS_TO})
same => n,Noop(Body: ${MESSAGE(body)})
same => n,Set(SMS_TO=${SMS_TO:-4}) ;The last 4 digits of our DIDs match the extension number, I couldn't figure out any other way to route to an extension based on the DID so you might have to hard code it ( i.e. Set(SMS_TO=${IF($["${SMS_TO}"="1234567890"]?101:102)}) )
same => n,Set(TENANT=) ;Enter your tenant path
same => n,Set(DIAL_STRING=${DB(${TENANT}/extensions/${SMS_TO}/dial)})
same => n,GotoIf($["${DIAL_STRING}"=""]?sendfailedmsg)
same => n,Set(COUNTER=1)
same => n,Set(CURRENT_DEVICE=${CUT(DIAL_STRING,&,${COUNTER})})
same => n,While($[${EXISTS(${CURRENT_DEVICE})}])
same => n,Set(TECHNOLOGY=${CUT(CURRENT_DEVICE,/,1)})
same => n,Set(USER=${CUT(CURRENT_DEVICE,/,2)})
same => n,GotoIf($[$["${TECHNOLOGY}"="IAX2"]|$["${TECHNOLOGY}"="DAHDI"]]?next)
same => n,MessageSend(${TOLOWER(${TECHNOLOGY})}:${USER},${SMS_FROM})
same => n,NoOp(SMS Status to ${CURRENT_DEVICE}: ${MESSAGE_SEND_STATUS})
same => n(next),Set(COUNTER=$[${COUNTER} + 1])
same => n,Set(CURRENT_DEVICE=${CUT(DIAL_STRING,&,${COUNTER})})
same => n,EndWhile()
same => n,Goto(h,1)
same => n(sendfailedmsg),Noop(The message to extension ${SMS_TO} has failed. Status: ${MESSAGE_SEND_STATUS})
same => n(failed),Hangup()
Outbound Dialplan
[messages]
exten => _ZXXXXXX!,1,Noop(SMS Sending) ;Accepts 7 or more digits with the first digit being [1-9]
same => n,GotoIf($["x${CUT(MESSAGE(to),<,2)}x"="xx"]?noname)
same => n,Set(SMS_NUM=${CUT(MESSAGE(to),<,2)})
same => n,Set(SMS_NUM=${CUT(SMS_NUM,>,1)})
same => n,Set(SMS_TECH=${CUT(SMS_NUM,:,1)})
same => n,Set(SMS_REAL_TECH=${CUT(MESSAGE(to),:,1)})
same => n,GotoIf($["${SMS_TECH}"="${SMS_REAL_TECH}"]?noname)
same => n,Set(MESSAGE(to)=${STRREPLACE(SMS_NUM,${SMS_TECH},${SMS_REAL_TECH})})
same => n(noname),Set(SMS_TO=${FILTER(0-9,${CUT(MESSAGE(to),@,1)})})
same => n,GotoIf($[${LEN(${SMS_TO})} < 10]?messages-internal,${EXTEN},1)
same => n,ExecIf($["${LEN(${SMS_TO})}"="10"]?Set(SMS_TO=1${SMS_TO}))
same => n,ExecIf($[${LEN(${SMS_TO})} > 11]?Hangup())
same => n,Set(FROM=${CUT(MESSAGE(from),<,2)})
same => n,Set(ACTUALFROM=${CUT(FROM,@,1)})
same => n,ExecIf($["${ACTUALFROM}"=~"_"]?Set(ACTUALFROM=${CUT(ACTUALFROM,_,1)}))
same => n,Set(SMS_FROM=${FILTER(0-9,${CUT(ACTUALFROM,:,2)})})
same => n,Set(SMS_CID=1234567${SMS_FROM}) ;Again if the last 4 of your DID matches the extension number. Note: this must be an 11 digit number and it must have SMS enabled in Skyetel
same => n,Noop(To: ${SMS_TO})
same => n,Noop(From: ${SMS_FROM})
same => n,Answer()
same => n,Set(SendSMS=${SHELL(curl -X POST -v -H "Content-type: application/json" --user <SID>:<SECRET> --data "{ \"to\": \"${SMS_TO}\", \"text\": \"${MESSAGE(body)}\" }" https://sms.skyetel.com/v1/out?from=${SMS_CID})}) ;You'll have to get the SID and SECRET from your Skytel account
same => n,Hangup()
P.S. I am not to familiar with JavaScript, but I tested this setup with Skyetel and it worked.
Hope that helps…