Collection of Huawei API scripts for use with MikroTik
(Tested on a Huawei E3372h-320 modem)
Token Parser Library
(Main Script base)
# TOKEN PARSER LIBRARY
# v1.0.0 pkt
# :put [($tokenParser->"getTag") source=$xml tag="SessionInfo"]
# ($tokenParser->"getBetween")
# get delimited value
# source - source string
# fromTok - (optional) text AFTER this token (or from source beginning) will be returned
# toTok - (optional) text BEFORE this token (or until source finish) will be returned
# startPos - (optional) start position (default 0 = beginning)
# returns an array with fields data and pos
#
# ($tokenParser->"getTag")
# get value for XML tag
# source - xml string
# tag - tag which value is to be returned
# startPos - (optional, text index) start position (if not specified, it will search from the beginning of the string)
# returns the tag content
#
# ($tokenParser->"getTagDetailed")
# get value and end position for XML tag
# source - xml string
# tag - tag which value is to be returned
# startPos - (optional, text index) start position (if not specified, it will search from the beginning of the string)
# returns an array with fields "data" (tag content) and "pos" (where tag ends)
#
# ($tokenParser->"getTagList")
# get a list with the content of each appearance of tag
# source - xml string
# tag - tag which value is to be returned
# returns an array with tag contents
#
# ($tokenParser->"forEachTag")
# incremental parser that calls the callback with the content of each appearance of tag
# source - xml string
# tag - tag which value is to be returned
# callback - callback (with param content) to be called for each appearance of tag
# callbackArgs - callback will be called passing this value in param args
:global tokenParser ({})
:set ($tokenParser->"getBetween") do={ # get delimited value
# source - source string
# fromTok - (optional) text AFTER this token (or from source beginning) will be returned
# toTok - (optional) text BEFORE this token (or until source finish) will be returned
# startPos - (optional) start position (default 0 = beginning)
# returns an array with fields data and pos
# if fromTok and/or toTok are specified and neither of them appear in source, empty string "" will be returned as data
# based on function getBetween by CuriousKiwi, modified by pkt
:local posStart
if ([:len $startPos] = 0) do={
:set posStart -1
} else={
:set posStart ($startPos-1)
}
:local found true
:local data
:local resultStart
:if ([:len $fromTok] > 0) do={
:set resultStart [:find $source $fromTok $posStart]
:if ([:len $resultStart] = 0) do={ # start token not found
:set found false
:set data ""
}
:set resultStart ($resultStart + [:len $fromTok])
} else={
:set resultStart 0
}
:local resultEnd
:if (found = true && [:len $toTok] > 0) do={
:set resultEnd [:find $source $toTok ($resultStart-1)]
:if ([:len $resultEnd] = 0) do={ # end token not found
:set found false
:set data ""
}
} else={
:set resultEnd [:len $source]
}
:if ($found = true) do={ :set data [:pick $source $resultStart $resultEnd] }
:return { data=$data; pos=$resultEnd }
}
:set ($tokenParser->"getTag") do={ # get value for XML tag
# source - xml string
# tag - tag which value is to be returned
# startPos - (optional, text index) start position (if not specified, it will search from the beginning of the string)
# returns the tag content
:global tokenParser
:return ([($tokenParser->"getBetween") source=$source fromTok=("<$tag>") toTok=("</$tag>") startPos=$startPos]->"data")
}
:set ($tokenParser->"getTagDetailed") do={ # get value and end position for XML tag
# source - xml string
# tag - tag which value is to be returned
# startPos - (optional, text index) start position (if not specified, it will search from the beginning of the string)
# returns an array with fields "data" (tag content) and "pos" (where tag ends)
:global tokenParser
:return [($tokenParser->"getBetween") source=$source fromTok=("<$tag>") toTok=("</$tag>") startPos=$startPos]
}
:set ($tokenParser->"getTagList") do={ # get a list with the content of each appearance of tag
# source - xml string
# tag - tag which value is to be returned
# returns an array with tag contents
:global tokenParser
:local result ({})
:local doneTags false
:local startPos 0
:do {
:local tagContent [($tokenParser->"getTagDetailed") source=$source tag=$tag startPos=$startPos]
:local content ($tagContent->"data")
:if ($content != "") do={
:set ($result->[:len $result]) $content
# advance start pos to search for next tag
:set startPos ($tagContent->"pos")
} else={
:set doneTags true
}
} while=($doneTags = false)
:return $result
}
:set ($tokenParser->"forEachTag") do={ # incremental parser that calls the callback with the content of each appearance of tag
# source - xml string
# tag - tag which value is to be returned
# callback - callback (with param content) to be called for each appearance of tag
# callbackArgs - callback will be called passing this value in param args
:global tokenParser
:local doneTags false
:local startPos 0
:do {
:local tagContent [($tokenParser->"getTagDetailed") source=$source tag=$tag startPos=$startPos]
:local content ($tagContent->"data")
:if ($content != "") do={
[$callback tagContent=$content args=$callbackArgs]
# advance start pos to search for next tag
:set startPos ($tagContent->"pos")
} else={
:set doneTags true
}
} while=($doneTags = false)
}
Function to get a list of SMS messages
:global recvSMS do={
:local lteIP "192.168.8.1"
:global tokenParser
# get SessionID and Token via LTE modem API
:local urlSesTokInfo "http://$lteIP/api/webserver/SesTokInfo"
:local api [/tool fetch $urlSesTokInfo output=user as-value]
:local apiData ($api->"data")
# parse SessionID and Token from API session data
:local apiSessionID [($tokenParser->"getTag") source=$apiData tag="SesInfo"]
:local apiToken [($tokenParser->"getTag") source=$apiData tag="TokInfo"]
# header and data config
:local apiHead "Content-Type:text/xml,Cookie: $apiSessionID,__RequestVerificationToken:$apiToken"
:local recvData "<?xml version=\"1.0\" encoding=\"UTF-8\"?><request><PageIndex>1</PageIndex><ReadCount>20</ReadCount><BoxType>1</BoxType><SortType>0</SortType><Ascending>0</Ascending><UnreadPreferred>1</UnreadPreferred></request>"
# recv SMS via LTE modem API with fetch
:return [/tool fetch http-method=post http-header-field=$apiHead url="http://$lteIP/api/sms/sms-list" http-data=$recvData output=user as-value]
}
Function to delete SMS messages (Inbox)
:global delSMS do={
:local lteIP "192.168.8.1"
:global tokenParser
# get SessionID and Token via LTE modem API
:local urlSesTokInfo "http://$lteIP/api/webserver/SesTokInfo"
:local api [/tool fetch $urlSesTokInfo output=user as-value]
:local apiData ($api->"data")
# parse SessionID and Token from API session data
:local apiSessionID [($tokenParser->"getTag") source=$apiData tag="SesInfo"]
:local apiToken [($tokenParser->"getTag") source=$apiData tag="TokInfo"]
# header and data config
:local apiHead "Content-Type:text/xml,Cookie: $apiSessionID,__RequestVerificationToken:$apiToken"
:local delData "<?xml version=\"1.0\" encoding=\"UTF-8\"?><request><Index>$index</Index></request>"
# delete SMS via LTE modem API with fetch
:return [/tool fetch http-method=post http-header-field=$apiHead url="http://$lteIP/api/sms/delete-sms" http-data=$delData output=user as-value]
}
Script to delete SMS messages (Sentbox)
:global recvSMSsentbox do={
:local lteIP "192.168.8.1"
:global tokenParser
# get SessionID and Token via LTE modem API
:local urlSesTokInfo "http://$lteIP/api/webserver/SesTokInfo"
:local api [/tool fetch $urlSesTokInfo output=user as-value]
:local apiData ($api->"data")
# parse SessionID and Token from API session data
:local apiSessionID [($tokenParser->"getTag") source=$apiData tag="SesInfo"]
:local apiToken [($tokenParser->"getTag") source=$apiData tag="TokInfo"]
# header and data config
:local apiHead "Content-Type:text/xml,Cookie: $apiSessionID,__RequestVerificationToken:$apiToken"
:local recvData "<?xml version=\"1.0\" encoding=\"UTF-8\"?><request><PageIndex>1</PageIndex><ReadCount>20</ReadCount><BoxType>2</BoxType><SortType>0</SortType><Ascending>0</Ascending><UnreadPreferred>1</UnreadPreferred></request>"
# delete SMS via LTE modem API with fetch
:return [/tool fetch http-method=post http-header-field=$apiHead url="http://$lteIP/api/sms/sms-list" http-data=$recvData output=user as-value]
}
:global tokenParser
:global delSMS
:local xmlSmsList ([$recvSMSsentbox]->"data")
:local smsList [($tokenParser->"getTagList") source=$xmlSmsList tag="Message"]
:local smsCount [:tonum [($tokenParser->"getTag") source=$xmlSmsList tag="Count"]]
:if ($smsCount > 0) do={
:delay 5s
:foreach tagContent in=$smsList do={
:local index [($tokenParser->"getTag") source=$tagContent tag="Index"]
[$delSMS index=$index]
}
}
Function to send SMS messages
:global sendSMS do={
# Example:
# :put [$sendSMS lteIP="192.168.8.1" phone="+34XXXXXXXXX" sms="test sms via lte api"]
:local lteIP "192.168.8.1"
:global tokenParser
# get SessionID and Token via LTE modem API
:local urlSesTokInfo "http://$lteIP/api/webserver/SesTokInfo"
:local api [/tool fetch $urlSesTokInfo output=user as-value]
:local apiData ($api->"data")
# parse SessionID and Token from API session data
:local apiSessionID [($tokenParser->"getTag") source=$apiData tag="SesInfo"]
:local apiToken [($tokenParser->"getTag") source=$apiData tag="TokInfo"]
# header and data config
:local apiHead "Content-Type:text/xml,Cookie: $apiSessionID,__RequestVerificationToken:$apiToken"
:local sendData "<?xml version=\"1.0\" encoding=\"UTF-8\"?><request><Index>-1</Index><Phones><Phone>$phone</Phone></Phones><Sca></Sca><Content>$sms</Content><Length>-1</Length><Reserved>1</Reserved><Date>-1</Date></request>"
# send SMS via LTE modem API with fetch
:return [/tool fetch http-method=post http-header-field=$apiHead url="http://$lteIP/api/sms/send-sms" http-data=$sendData output=user as-value]
}
Script to get a list of SMS messages from Inbox, forward them by email and SMS, then delete them.
:global tokenParser
:global recvSMS
:global delSMS
:global sendSMS
:local xmlSmsList ([$recvSMS]->"data")
:local smsList [($tokenParser->"getTagList") source=$xmlSmsList tag="Message"]
:local smsCount [:tonum [($tokenParser->"getTag") source=$xmlSmsList tag="Count"]]
:if ($smsCount > 0) do={
:foreach tagContent in=$smsList do={
:local index [($tokenParser->"getTag") source=$tagContent tag="Index"]
:local date [($tokenParser->"getTag") source=$tagContent tag="Date"]
:local phone [($tokenParser->"getTag") source=$tagContent tag="Phone"]
:local content [($tokenParser->"getTag") source=$tagContent tag="Content"]
:local read ([($tokenParser->"getTag") source=$tagContent tag="Smstat"] = 1)
:if ($content != "") do={
:put "$index $read $date $phone $content"
/tool e-mail send to=user@mail.com subject="SMS $phone" body="$index $read $date $phone $content"
:execute [$sendSMS lteIP="192.168.8.1" phone="+34XXXXXXXXX" sms="$phone $content"]
}
}
:delay 5s
:foreach tagContent in=$smsList do={
:local index [($tokenParser->"getTag") source=$tagContent tag="Index"]
[$delSMS index=$index]
}
}
TIP:
Change DHCP server IP address range (modem) to be able to configure a single IP for the Mikrotik DHCP client.
- Run the following script to create the global variable dhcpSMS.
- From the Terminal type:
:put [$dhcpSMS lteIP="192.168.8.1" startIP="192.168.8.100" endIP="192.168.8.100"]
- Done! you have now changed the IP address range.
Script contents:
:global dhcpSMS do={
# Example:
# :put [$dhcpSMS lteIP="192.168.8.1" startIP="192.168.8.100" endIP="192.168.8.100"]
:global tokenParser
# get SessionID and Token via LTE modem API
:local urlSesTokInfo "http://$lteIP/api/webserver/SesTokInfo"
:local api [/tool fetch $urlSesTokInfo output=user as-value]
:local apiData ($api->"data")
# parse SessionID and Token from API session data
:local apiSessionID [($tokenParser->"getTag") source=$apiData tag="SesInfo"]
:local apiToken [($tokenParser->"getTag") source=$apiData tag="TokInfo"]
# header and data config
:local apiHead "Content-Type:text/xml,Cookie: $apiSessionID,__RequestVerificationToken:$apiToken"
:local dhcpData "<?xml version=\"1.0\" encoding=\"UTF-8\"?><request><DnsStatus>1</DnsStatus><DhcpStartIPAddress>$startIP</DhcpStartIPAddress><DhcpIPAddress>192.168.8.1</DhcpIPAddress><accessipaddress></accessipaddress><homeurl>hi.link</homeurl><DhcpStatus>1</DhcpStatus><DhcpLanNetmask>255.255.255.0</DhcpLanNetmask><SecondaryDns>192.168.8.1</SecondaryDns><PrimaryDns>192.168.8.1</PrimaryDns><DhcpEndIPAddress>$endIP</DhcpEndIPAddress><DhcpLeaseTime>86400</DhcpLeaseTime></request>"
# change IP address range with fetch
:return [/tool fetch http-method=post http-header-field=$apiHead url="http://$lteIP/api/dhcp/settings" http-data=$dhcpData output=user as-value]
}
Enjoy!.