SMS/MMS in VitXiWebRTC and Mobile apps

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,

  1. 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
  2. Install all packages required by the script
  3. Run the application in the background, you can create a service or start it with pm2
  4. Open port 8888 in your direwall, you can limit it to skyetel SMS IP (52.14.37.123)
  5. Get a SID and Secret from your skyetel account, used to authenticate when sending outbound messages.
  6. 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…

2 Likes