WhatTheIanni
22-07-22, 14:49
Σας παραθέτω ένα κύριο script & δύο helper scripts για να προωθεί το Tik σας μέσω Telegram τα SMS που έρχονται στο LTE interface.
Υπάρχουν κάποιες έτοιμες λύσεις αλλά προϋποθέτουν το loading ενός σκασμού από global functions και δεν μου άρεσε η ιδέα, οπότε το έφτιαξα μόνος μου.
Τι κάνει το script:
Τραβάει την λίστα των SMS από το Inbox, και αν υπάρχουν SMS:
1. Παίρνει για κάθε μήνυμα τον αποστολέα και το περιεχόμενο.
2. Τα κάνει URL Encode για να στηθεί σωστά το request στο Telegram API.
3. Τα συγκεντρώνει όλα σε ένα μήνυμα με διαχωριστικές παύλες για οικονομία request.
4. Εκτελεί το request στο Telegram API για την αποστολή του μηνύματος.
5. Αν πετύχει το request, σβήνει τα SMS από το Inbox
Προαπαιτούμενα:
- Να έχετε φτιάξει ένα bot μέσω του @BotFather (https://t.me/BotFather) (απόστολή /newbot, ακολουθείτε οδηγίες και στο τέλος παίρνετε το token που σας επιστρέφει ο @BotFather)
- Να πάρετε το chat id σας (ανοίγετε κουβέντα με το @getidsbot (https://t.me/getidsbot), πατάτε [START] και στις πληροφορίες που θα σας δώσει, κάτω από το You είναι το chat id σας)
Βήμα 1: Δημιουργία script με τον helper για το URL Encoding
Πάμε System -> Scripts και φτιάχνουμε ένα νέο script με όνομα UrlEncode και περιεχόμενο:
:global UrlEncode;
:set UrlEncode do={
:local Input [ :tostr $1 ];
:log info "UrlEncode started";
:log info "input $Input";
:if ([ :len $Input ] = 0) do={
:return "";
}
:local Return "";
:local Chars ("\n\r !\"#\$%&'()*+,:;<=>\?@[\\]^`{|}~");
:local Subs { "%0A"; "%0D"; "%20"; "%21"; "%22"; "%23"; "%24"; "%25"; "%26"; "%27";
"%28"; "%29"; "%2A"; "%2B"; "%2C"; "%3A"; "%3B"; "%3C"; "%3D"; "%3E"; "%3F";
"%40"; "%5B"; "%5C"; "%5D"; "%5E"; "%60"; "%7B"; "%7C"; "%7D"; "%7E" };
:log info "UrlEncode middle";
:log info "$Subs";
:for I from=0 to=([ :len $Input ] - 1) do={
:local Char [ :pick $Input $I ];
:local Replace [ :find $Chars $Char ];
:if ([ :typeof $Replace ] = "num") do={
:set Char ($Subs->$Replace);
}
:set Return ($Return . $Char);
}
:log info "UrlEncode ended";
:log info "return value $Return";
:return $Return;
}
Πηγή: routeros-scripts @ GitHub (https://github.com/eworm-de/routeros-scripts/blob/50178e2a3c6067c4148e3f814b60e51d1c8ced69/global-functions#L1175)
Βήμα 2: Δημιουργία script με τον helper για το JSON Parsing
Πάμε System -> Scripts και φτιάχνουμε ένα νέο script με όνομα JParseFunctions και περιεχόμενο:
# -------------------------------- JParseFunctions ---------------------------------------------------
# ------------------------------- fJParsePrint ----------------------------------------------------------------
:global fJParsePrint
:if (!any $fJParsePrint) do={ :global fJParsePrint do={
:global JParseOut
:local TempPath
:global fJParsePrint
:if ([:len $1] = 0) do={
:set $1 "\$JParseOut"
:set $2 $JParseOut
}
:foreach k,v in=$2 do={
:if ([:typeof $k] = "str") do={
:set k "\"$k\""
}
:set TempPath ($1. "->" . $k)
:if ([:typeof $v] = "array") do={
:if ([:len $v] > 0) do={
$fJParsePrint $TempPath $v
} else={
:put "$TempPath = [] ($[:typeof $v])"
}
} else={
:put "$TempPath = $v ($[:typeof $v])"
}
}
}}
# ------------------------------- fJParsePrintVar ----------------------------------------------------------------
:global fJParsePrintVar
:if (!any $fJParsePrintVar) do={ :global fJParsePrintVar do={
:global JParseOut
:local TempPath
:global fJParsePrintVar
:local fJParsePrintRet ""
:if ([:len $1] = 0) do={
:set $1 "\$JParseOut"
:set $2 $JParseOut
}
:foreach k,v in=$2 do={
:if ([:typeof $k] = "str") do={
:set k "\"$k\""
}
:set TempPath ($1. "->" . $k)
:if ($fJParsePrintRet != "") do={
:set fJParsePrintRet ($fJParsePrintRet . "\r\n")
}
:if ([:typeof $v] = "array") do={
:if ([:len $v] > 0) do={
:set fJParsePrintRet ($fJParsePrintRet . [$fJParsePrintVar $TempPath $v])
} else={
:set fJParsePrintRet ($fJParsePrintRet . "$TempPath = [] ($[:typeof $v])")
}
} else={
:set fJParsePrintRet ($fJParsePrintRet . "$TempPath = $v ($[:typeof $v])")
}
}
:return $fJParsePrintRet
}}
# ------------------------------- fJSkipWhitespace ----------------------------------------------------------------
:global fJSkipWhitespace
:if (!any $fJSkipWhitespace) do={ :global fJSkipWhitespace do={
:global Jpos
:global JSONIn
:global Jdebug
:while ($Jpos < [:len $JSONIn] and ([:pick $JSONIn $Jpos] ~ "[ \r\n\t]")) do={
:set Jpos ($Jpos + 1)
}
:if ($Jdebug) do={:put "fJSkipWhitespace: Jpos=$Jpos Char=$[:pick $JSONIn $Jpos]"}
}}
# -------------------------------- fJParse ---------------------------------------------------------------
:global fJParse
:if (!any $fJParse) do={ :global fJParse do={
:global Jpos
:global JSONIn
:global Jdebug
:global fJSkipWhitespace
:local Char
:if (!$1) do={
:set Jpos 0
}
$fJSkipWhitespace
:set Char [:pick $JSONIn $Jpos]
:if ($Jdebug) do={:put "fJParse: Jpos=$Jpos Char=$Char"}
:if ($Char="{") do={
:set Jpos ($Jpos + 1)
:global fJParseObject
:return [$fJParseObject]
} else={
:if ($Char="[") do={
:set Jpos ($Jpos + 1)
:global fJParseArray
:return [$fJParseArray]
} else={
:if ($Char="\"") do={
:set Jpos ($Jpos + 1)
:global fJParseString
:return [$fJParseString]
} else={
# :if ([:pick $JSONIn $Jpos ($Jpos+2)]~"^-\?[0-9]") do={
:if ($Char~"[eE0-9.+-]") do={
:global fJParseNumber
:return [$fJParseNumber]
} else={
:if ($Char="n" and [:pick $JSONIn $Jpos ($Jpos+4)]="null") do={
:set Jpos ($Jpos + 4)
:return []
} else={
:if ($Char="t" and [:pick $JSONIn $Jpos ($Jpos+4)]="true") do={
:set Jpos ($Jpos + 4)
:return true
} else={
:if ($Char="f" and [:pick $JSONIn $Jpos ($Jpos+5)]="false") do={
:set Jpos ($Jpos + 5)
:return false
} else={
:put "Err.Raise 8732. No JSON object could be fJParseed"
:set Jpos ($Jpos + 1)
:return []
}
}
}
}
}
}
}
}}
#-------------------------------- fJParseString ---------------------------------------------------------------
:global fJParseString
:if (!any $fJParseString) do={ :global fJParseString do={
:global Jpos
:global JSONIn
:global Jdebug
:global fUnicodeToUTF8
:local Char
:local StartIdx
:local Char2
:local TempString ""
:local UTFCode
:local Unicode
:set StartIdx $Jpos
:set Char [:pick $JSONIn $Jpos]
:if ($Jdebug) do={:put "fJParseString: Jpos=$Jpos Char=$Char"}
:while ($Jpos < [:len $JSONIn] and $Char != "\"") do={
:if ($Char="\\") do={
:set Char2 [:pick $JSONIn ($Jpos + 1)]
:if ($Char2 = "u") do={
:set UTFCode [:tonum "0x$[:pick $JSONIn ($Jpos+2) ($Jpos+6)]"]
:if ($UTFCode>=0xD800 and $UTFCode<=0xDFFF) do={
# Surrogate pair
:set Unicode (($UTFCode & 0x3FF) << 10)
:set UTFCode [:tonum "0x$[:pick $JSONIn ($Jpos+8) ($Jpos+12)]"]
:set Unicode ($Unicode | ($UTFCode & 0x3FF) | 0x10000)
:set TempString ($TempString . [:pick $JSONIn $StartIdx $Jpos] . [$fUnicodeToUTF8 $Unicode])
:set Jpos ($Jpos + 12)
} else= {
# Basic Multilingual Plane (BMP)
:set Unicode $UTFCode
:set TempString ($TempString . [:pick $JSONIn $StartIdx $Jpos] . [$fUnicodeToUTF8 $Unicode])
:set Jpos ($Jpos + 6)
}
:set StartIdx $Jpos
:if ($Jdebug) do={:put "fJParseString Unicode: $Unicode"}
} else={
:if ($Char2 ~ "[\\bfnrt\"]") do={
:if ($Jdebug) do={:put "fJParseString escape: Char+Char2 $Char$Char2"}
:set TempString ($TempString . [:pick $JSONIn $StartIdx $Jpos] . [[:parse "(\"\\$Char2\")"]])
:set Jpos ($Jpos + 2)
:set StartIdx $Jpos
} else={
:if ($Char2 = "/") do={
:if ($Jdebug) do={:put "fJParseString /: Char+Char2 $Char$Char2"}
:set TempString ($TempString . [:pick $JSONIn $StartIdx $Jpos] . "/")
:set Jpos ($Jpos + 2)
:set StartIdx $Jpos
} else={
:put "Err.Raise 8732. Invalid escape"
:set Jpos ($Jpos + 2)
}
}
}
} else={
:set Jpos ($Jpos + 1)
}
:set Char [:pick $JSONIn $Jpos]
}
:set TempString ($TempString . [:pick $JSONIn $StartIdx $Jpos])
:set Jpos ($Jpos + 1)
:if ($Jdebug) do={:put "fJParseString: $TempString"}
:return $TempString
}}
#-------------------------------- fJParseNumber ---------------------------------------------------------------
:global fJParseNumber
:if (!any $fJParseNumber) do={ :global fJParseNumber do={
:global Jpos
:local StartIdx
:global JSONIn
:global Jdebug
:local NumberString
:local Number
:set StartIdx $Jpos
:set Jpos ($Jpos + 1)
:while ($Jpos < [:len $JSONIn] and [:pick $JSONIn $Jpos]~"[eE0-9.+-]") do={
:set Jpos ($Jpos + 1)
}
:set NumberString [:pick $JSONIn $StartIdx $Jpos]
:set Number [:tonum $NumberString]
:if ([:typeof $Number] = "num") do={
:if ($Jdebug) do={:put "fJParseNumber: StartIdx=$StartIdx Jpos=$Jpos $Number ($[:typeof $Number])"}
:return $Number
} else={
:if ($Jdebug) do={:put "fJParseNumber: StartIdx=$StartIdx Jpos=$Jpos $NumberString ($[:typeof $NumberString])"}
:return $NumberString
}
}}
#-------------------------------- fJParseArray ---------------------------------------------------------------
:global fJParseArray
:if (!any $fJParseArray) do={ :global fJParseArray do={
:global Jpos
:global JSONIn
:global Jdebug
:global fJParse
:global fJSkipWhitespace
:local Value
:local ParseArrayRet [:toarray ""]
$fJSkipWhitespace
:while ($Jpos < [:len $JSONIn] and [:pick $JSONIn $Jpos]!= "]") do={
:set Value [$fJParse true]
:set ($ParseArrayRet->([:len $ParseArrayRet])) $Value
:if ($Jdebug) do={:put "fJParseArray: Value="; :put $Value}
$fJSkipWhitespace
:if ([:pick $JSONIn $Jpos] = ",") do={
:set Jpos ($Jpos + 1)
$fJSkipWhitespace
}
}
:set Jpos ($Jpos + 1)
# :if ($Jdebug) do={:put "ParseArrayRet: "; :put $ParseArrayRet}
:return $ParseArrayRet
}}
# -------------------------------- fJParseObject ---------------------------------------------------------------
:global fJParseObject
:if (!any $fJParseObject) do={ :global fJParseObject do={
:global Jpos
:global JSONIn
:global Jdebug
:global fJSkipWhitespace
:global fJParseString
:global fJParse
# Syntax :local ParseObjectRet ({}) don't work in recursive call, use [:toarray ""] for empty array!!!
:local ParseObjectRet [:toarray ""]
:local Key
:local Value
:local ExitDo false
$fJSkipWhitespace
:while ($Jpos < [:len $JSONIn] and [:pick $JSONIn $Jpos]!="}" and !$ExitDo) do={
:if ([:pick $JSONIn $Jpos]!="\"") do={
:put "Err.Raise 8732. Expecting property name"
:set ExitDo true
} else={
:set Jpos ($Jpos + 1)
:set Key [$fJParseString]
$fJSkipWhitespace
:if ([:pick $JSONIn $Jpos] != ":") do={
:put "Err.Raise 8732. Expecting : delimiter"
:set ExitDo true
} else={
:set Jpos ($Jpos + 1)
:set Value [$fJParse true]
:set ($ParseObjectRet->$Key) $Value
:if ($Jdebug) do={:put "fJParseObject: Key=$Key Value="; :put $Value}
$fJSkipWhitespace
:if ([:pick $JSONIn $Jpos]=",") do={
:set Jpos ($Jpos + 1)
$fJSkipWhitespace
}
}
}
}
:set Jpos ($Jpos + 1)
# :if ($Jdebug) do={:put "ParseObjectRet: "; :put $ParseObjectRet}
:return $ParseObjectRet
}}
# ------------------- fByteToEscapeChar ----------------------
:global fByteToEscapeChar
:if (!any $fByteToEscapeChar) do={ :global fByteToEscapeChar do={
# :set $1 [:tonum $1]
:return [[:parse "(\"\\$[:pick "0123456789ABCDEF" (($1 >> 4) & 0xF)]$[:pick "0123456789ABCDEF" ($1 & 0xF)]\")"]]
}}
# ------------------- fUnicodeToUTF8----------------------
:global fUnicodeToUTF8
:if (!any $fUnicodeToUTF8) do={ :global fUnicodeToUTF8 do={
:global fByteToEscapeChar
# :local Ubytes [:tonum $1]
:local Nbyte
:local EscapeStr ""
:if ($1 < 0x80) do={
:set EscapeStr [$fByteToEscapeChar $1]
} else={
:if ($1 < 0x800) do={
:set Nbyte 2
} else={
:if ($1 < 0x10000) do={
:set Nbyte 3
} else={
:if ($1 < 0x20000) do={
:set Nbyte 4
} else={
:if ($1 < 0x4000000) do={
:set Nbyte 5
} else={
:if ($1 < 0x80000000) do={
:set Nbyte 6
}
}
}
}
}
:for i from=2 to=$Nbyte do={
:set EscapeStr ([$fByteToEscapeChar ($1 & 0x3F | 0x80)] . $EscapeStr)
:set $1 ($1 >> 6)
}
:set EscapeStr ([$fByteToEscapeChar (((0xFF00 >> $Nbyte) & 0xFF) | $1)] . $EscapeStr)
}
:return $EscapeStr
}}
# ------------------- Load JSON from arg --------------------------------
global JSONLoads
if (!any $JSONLoads) do={ global JSONLoads do={
global JSONIn $1
global fJParse
local ret [$fJParse]
set JSONIn
global Jpos; set Jpos
global Jdebug; if (!$Jdebug) do={set Jdebug}
return $ret
}}
# ------------------- Load JSON from file --------------------------------
global JSONLoad
if (!any $JSONLoad) do={ global JSONLoad do={
if ([len [/file find name=$1]] > 0) do={
global JSONLoads
return [$JSONLoads [/file get $1 contents]]
}
}}
# ------------------- Unload JSON parser library ----------------------
global JSONUnload
if (!any $JSONUnload) do={ global JSONUnload do={
global JSONIn; set JSONIn
global Jpos; set Jpos
global Jdebug; set Jdebug
global fByteToEscapeChar; set fByteToEscapeChar
global fJParse; set fJParse
global fJParseArray; set fJParseArray
global fJParseNumber; set fJParseNumber
global fJParseObject; set fJParseObject
global fJParsePrint; set fJParsePrint
global fJParsePrintVar; set fJParsePrintVar
global fJParseString; set fJParseString
global fJSkipWhitespace; set fJSkipWhitespace
global fUnicodeToUTF8; set fUnicodeToUTF8
global JSONLoads; set JSONLoads
global JSONLoad; set JSONLoad
global JSONUnload; set JSONUnload
}}
# ------------------- End JParseFunctions----------------------
Πηγή: mikrotik-json-parser @ GitHub (https://github.com/Winand/mikrotik-json-parser)
Βήμα 3: Δημιουργία του βασικού script ελέγχου και προώθησης
Πάμε System -> Scripts και φτιάχνουμε ένα νέο script με όνομα sms-telegram και περιεχόμενο:
(Αντικαθιστάτε τα {BOT_TOKEN} και {CHAT_ID} με αυτά που αναφέρθηκαν στα προαπαιτούμενα.)
:local botToken "{BOT_TOKEN}";
:local chatId "{CHAT_ID}";
:local parseMode "HTML";
:local smsPhone;
:local encodedPhone;
:local smsMessage;
:local encodedMessage;
:local smsEntry;
:local totalContent;
:local messageList [/tool sms inbox find];
:local messageListCount [:len $messageList];
:if ($messageListCount > 0) do={
/system script run "UrlEncode"; global UrlEncode;
:foreach i in=$messageList do={
:set smsPhone ("<b>" . [/tool sms inbox get $i phone] . "</b>");
:set encodedPhone [$UrlEncode $smsPhone];
:set smsMessage [/tool sms inbox get $i message];
:set encodedMessage [$UrlEncode $smsMessage];
:set smsEntry ($encodedPhone . "%0A" . $encodedMessage);
:set totalContent ($totalContent . $smsEntry . "%0A%2D%2D%2D%0A");
}
:local result [:tool fetch url="https://api.telegram.org/bot$botToken/sendMessage?parse_mode=$parseMode&chat_id=-$chatId&text=$totalContent" as-value output=user];
:local resultData ($result->"data");
/system script run "JParseFunctions"; global JSONLoads; global JSONUnload
:local finishResult ([$JSONLoads $resultData]->"ok");
:if ($finishResult = true) do={
:log info "SMS -> Telegram: Successfully forwarded $messageListCount SMS messages";
:foreach i in=$messageList do={
/tool sms inbox remove $i;
}
} else {
:log error "SMS -> Telegram: Error while forwarding $messageListCount SMS messages";
}
$JSONUnload;
}
Πηγή: @WhatTheIanni
Βήμα 4: Δημιουργία Scheduler entry για να εκτελείται περιοδικά το script μας
Πάμε System -> Scheduler και φτιάχνουμε ένα νέο entry με ότι όνομα θέλουμε, ορίζουμε το Start Time σε startup ώστε να ξεκινάει μετά από κάθε reboot και το Interval ανάλογα με το πόσο συχνά θέλουμε να γίνεται ο έλεγχος.
Στο On Event ορίζουμε:
/system/script/run sms-telegram;
Υπάρχουν κάποιες έτοιμες λύσεις αλλά προϋποθέτουν το loading ενός σκασμού από global functions και δεν μου άρεσε η ιδέα, οπότε το έφτιαξα μόνος μου.
Τι κάνει το script:
Τραβάει την λίστα των SMS από το Inbox, και αν υπάρχουν SMS:
1. Παίρνει για κάθε μήνυμα τον αποστολέα και το περιεχόμενο.
2. Τα κάνει URL Encode για να στηθεί σωστά το request στο Telegram API.
3. Τα συγκεντρώνει όλα σε ένα μήνυμα με διαχωριστικές παύλες για οικονομία request.
4. Εκτελεί το request στο Telegram API για την αποστολή του μηνύματος.
5. Αν πετύχει το request, σβήνει τα SMS από το Inbox
Προαπαιτούμενα:
- Να έχετε φτιάξει ένα bot μέσω του @BotFather (https://t.me/BotFather) (απόστολή /newbot, ακολουθείτε οδηγίες και στο τέλος παίρνετε το token που σας επιστρέφει ο @BotFather)
- Να πάρετε το chat id σας (ανοίγετε κουβέντα με το @getidsbot (https://t.me/getidsbot), πατάτε [START] και στις πληροφορίες που θα σας δώσει, κάτω από το You είναι το chat id σας)
Βήμα 1: Δημιουργία script με τον helper για το URL Encoding
Πάμε System -> Scripts και φτιάχνουμε ένα νέο script με όνομα UrlEncode και περιεχόμενο:
:global UrlEncode;
:set UrlEncode do={
:local Input [ :tostr $1 ];
:log info "UrlEncode started";
:log info "input $Input";
:if ([ :len $Input ] = 0) do={
:return "";
}
:local Return "";
:local Chars ("\n\r !\"#\$%&'()*+,:;<=>\?@[\\]^`{|}~");
:local Subs { "%0A"; "%0D"; "%20"; "%21"; "%22"; "%23"; "%24"; "%25"; "%26"; "%27";
"%28"; "%29"; "%2A"; "%2B"; "%2C"; "%3A"; "%3B"; "%3C"; "%3D"; "%3E"; "%3F";
"%40"; "%5B"; "%5C"; "%5D"; "%5E"; "%60"; "%7B"; "%7C"; "%7D"; "%7E" };
:log info "UrlEncode middle";
:log info "$Subs";
:for I from=0 to=([ :len $Input ] - 1) do={
:local Char [ :pick $Input $I ];
:local Replace [ :find $Chars $Char ];
:if ([ :typeof $Replace ] = "num") do={
:set Char ($Subs->$Replace);
}
:set Return ($Return . $Char);
}
:log info "UrlEncode ended";
:log info "return value $Return";
:return $Return;
}
Πηγή: routeros-scripts @ GitHub (https://github.com/eworm-de/routeros-scripts/blob/50178e2a3c6067c4148e3f814b60e51d1c8ced69/global-functions#L1175)
Βήμα 2: Δημιουργία script με τον helper για το JSON Parsing
Πάμε System -> Scripts και φτιάχνουμε ένα νέο script με όνομα JParseFunctions και περιεχόμενο:
# -------------------------------- JParseFunctions ---------------------------------------------------
# ------------------------------- fJParsePrint ----------------------------------------------------------------
:global fJParsePrint
:if (!any $fJParsePrint) do={ :global fJParsePrint do={
:global JParseOut
:local TempPath
:global fJParsePrint
:if ([:len $1] = 0) do={
:set $1 "\$JParseOut"
:set $2 $JParseOut
}
:foreach k,v in=$2 do={
:if ([:typeof $k] = "str") do={
:set k "\"$k\""
}
:set TempPath ($1. "->" . $k)
:if ([:typeof $v] = "array") do={
:if ([:len $v] > 0) do={
$fJParsePrint $TempPath $v
} else={
:put "$TempPath = [] ($[:typeof $v])"
}
} else={
:put "$TempPath = $v ($[:typeof $v])"
}
}
}}
# ------------------------------- fJParsePrintVar ----------------------------------------------------------------
:global fJParsePrintVar
:if (!any $fJParsePrintVar) do={ :global fJParsePrintVar do={
:global JParseOut
:local TempPath
:global fJParsePrintVar
:local fJParsePrintRet ""
:if ([:len $1] = 0) do={
:set $1 "\$JParseOut"
:set $2 $JParseOut
}
:foreach k,v in=$2 do={
:if ([:typeof $k] = "str") do={
:set k "\"$k\""
}
:set TempPath ($1. "->" . $k)
:if ($fJParsePrintRet != "") do={
:set fJParsePrintRet ($fJParsePrintRet . "\r\n")
}
:if ([:typeof $v] = "array") do={
:if ([:len $v] > 0) do={
:set fJParsePrintRet ($fJParsePrintRet . [$fJParsePrintVar $TempPath $v])
} else={
:set fJParsePrintRet ($fJParsePrintRet . "$TempPath = [] ($[:typeof $v])")
}
} else={
:set fJParsePrintRet ($fJParsePrintRet . "$TempPath = $v ($[:typeof $v])")
}
}
:return $fJParsePrintRet
}}
# ------------------------------- fJSkipWhitespace ----------------------------------------------------------------
:global fJSkipWhitespace
:if (!any $fJSkipWhitespace) do={ :global fJSkipWhitespace do={
:global Jpos
:global JSONIn
:global Jdebug
:while ($Jpos < [:len $JSONIn] and ([:pick $JSONIn $Jpos] ~ "[ \r\n\t]")) do={
:set Jpos ($Jpos + 1)
}
:if ($Jdebug) do={:put "fJSkipWhitespace: Jpos=$Jpos Char=$[:pick $JSONIn $Jpos]"}
}}
# -------------------------------- fJParse ---------------------------------------------------------------
:global fJParse
:if (!any $fJParse) do={ :global fJParse do={
:global Jpos
:global JSONIn
:global Jdebug
:global fJSkipWhitespace
:local Char
:if (!$1) do={
:set Jpos 0
}
$fJSkipWhitespace
:set Char [:pick $JSONIn $Jpos]
:if ($Jdebug) do={:put "fJParse: Jpos=$Jpos Char=$Char"}
:if ($Char="{") do={
:set Jpos ($Jpos + 1)
:global fJParseObject
:return [$fJParseObject]
} else={
:if ($Char="[") do={
:set Jpos ($Jpos + 1)
:global fJParseArray
:return [$fJParseArray]
} else={
:if ($Char="\"") do={
:set Jpos ($Jpos + 1)
:global fJParseString
:return [$fJParseString]
} else={
# :if ([:pick $JSONIn $Jpos ($Jpos+2)]~"^-\?[0-9]") do={
:if ($Char~"[eE0-9.+-]") do={
:global fJParseNumber
:return [$fJParseNumber]
} else={
:if ($Char="n" and [:pick $JSONIn $Jpos ($Jpos+4)]="null") do={
:set Jpos ($Jpos + 4)
:return []
} else={
:if ($Char="t" and [:pick $JSONIn $Jpos ($Jpos+4)]="true") do={
:set Jpos ($Jpos + 4)
:return true
} else={
:if ($Char="f" and [:pick $JSONIn $Jpos ($Jpos+5)]="false") do={
:set Jpos ($Jpos + 5)
:return false
} else={
:put "Err.Raise 8732. No JSON object could be fJParseed"
:set Jpos ($Jpos + 1)
:return []
}
}
}
}
}
}
}
}}
#-------------------------------- fJParseString ---------------------------------------------------------------
:global fJParseString
:if (!any $fJParseString) do={ :global fJParseString do={
:global Jpos
:global JSONIn
:global Jdebug
:global fUnicodeToUTF8
:local Char
:local StartIdx
:local Char2
:local TempString ""
:local UTFCode
:local Unicode
:set StartIdx $Jpos
:set Char [:pick $JSONIn $Jpos]
:if ($Jdebug) do={:put "fJParseString: Jpos=$Jpos Char=$Char"}
:while ($Jpos < [:len $JSONIn] and $Char != "\"") do={
:if ($Char="\\") do={
:set Char2 [:pick $JSONIn ($Jpos + 1)]
:if ($Char2 = "u") do={
:set UTFCode [:tonum "0x$[:pick $JSONIn ($Jpos+2) ($Jpos+6)]"]
:if ($UTFCode>=0xD800 and $UTFCode<=0xDFFF) do={
# Surrogate pair
:set Unicode (($UTFCode & 0x3FF) << 10)
:set UTFCode [:tonum "0x$[:pick $JSONIn ($Jpos+8) ($Jpos+12)]"]
:set Unicode ($Unicode | ($UTFCode & 0x3FF) | 0x10000)
:set TempString ($TempString . [:pick $JSONIn $StartIdx $Jpos] . [$fUnicodeToUTF8 $Unicode])
:set Jpos ($Jpos + 12)
} else= {
# Basic Multilingual Plane (BMP)
:set Unicode $UTFCode
:set TempString ($TempString . [:pick $JSONIn $StartIdx $Jpos] . [$fUnicodeToUTF8 $Unicode])
:set Jpos ($Jpos + 6)
}
:set StartIdx $Jpos
:if ($Jdebug) do={:put "fJParseString Unicode: $Unicode"}
} else={
:if ($Char2 ~ "[\\bfnrt\"]") do={
:if ($Jdebug) do={:put "fJParseString escape: Char+Char2 $Char$Char2"}
:set TempString ($TempString . [:pick $JSONIn $StartIdx $Jpos] . [[:parse "(\"\\$Char2\")"]])
:set Jpos ($Jpos + 2)
:set StartIdx $Jpos
} else={
:if ($Char2 = "/") do={
:if ($Jdebug) do={:put "fJParseString /: Char+Char2 $Char$Char2"}
:set TempString ($TempString . [:pick $JSONIn $StartIdx $Jpos] . "/")
:set Jpos ($Jpos + 2)
:set StartIdx $Jpos
} else={
:put "Err.Raise 8732. Invalid escape"
:set Jpos ($Jpos + 2)
}
}
}
} else={
:set Jpos ($Jpos + 1)
}
:set Char [:pick $JSONIn $Jpos]
}
:set TempString ($TempString . [:pick $JSONIn $StartIdx $Jpos])
:set Jpos ($Jpos + 1)
:if ($Jdebug) do={:put "fJParseString: $TempString"}
:return $TempString
}}
#-------------------------------- fJParseNumber ---------------------------------------------------------------
:global fJParseNumber
:if (!any $fJParseNumber) do={ :global fJParseNumber do={
:global Jpos
:local StartIdx
:global JSONIn
:global Jdebug
:local NumberString
:local Number
:set StartIdx $Jpos
:set Jpos ($Jpos + 1)
:while ($Jpos < [:len $JSONIn] and [:pick $JSONIn $Jpos]~"[eE0-9.+-]") do={
:set Jpos ($Jpos + 1)
}
:set NumberString [:pick $JSONIn $StartIdx $Jpos]
:set Number [:tonum $NumberString]
:if ([:typeof $Number] = "num") do={
:if ($Jdebug) do={:put "fJParseNumber: StartIdx=$StartIdx Jpos=$Jpos $Number ($[:typeof $Number])"}
:return $Number
} else={
:if ($Jdebug) do={:put "fJParseNumber: StartIdx=$StartIdx Jpos=$Jpos $NumberString ($[:typeof $NumberString])"}
:return $NumberString
}
}}
#-------------------------------- fJParseArray ---------------------------------------------------------------
:global fJParseArray
:if (!any $fJParseArray) do={ :global fJParseArray do={
:global Jpos
:global JSONIn
:global Jdebug
:global fJParse
:global fJSkipWhitespace
:local Value
:local ParseArrayRet [:toarray ""]
$fJSkipWhitespace
:while ($Jpos < [:len $JSONIn] and [:pick $JSONIn $Jpos]!= "]") do={
:set Value [$fJParse true]
:set ($ParseArrayRet->([:len $ParseArrayRet])) $Value
:if ($Jdebug) do={:put "fJParseArray: Value="; :put $Value}
$fJSkipWhitespace
:if ([:pick $JSONIn $Jpos] = ",") do={
:set Jpos ($Jpos + 1)
$fJSkipWhitespace
}
}
:set Jpos ($Jpos + 1)
# :if ($Jdebug) do={:put "ParseArrayRet: "; :put $ParseArrayRet}
:return $ParseArrayRet
}}
# -------------------------------- fJParseObject ---------------------------------------------------------------
:global fJParseObject
:if (!any $fJParseObject) do={ :global fJParseObject do={
:global Jpos
:global JSONIn
:global Jdebug
:global fJSkipWhitespace
:global fJParseString
:global fJParse
# Syntax :local ParseObjectRet ({}) don't work in recursive call, use [:toarray ""] for empty array!!!
:local ParseObjectRet [:toarray ""]
:local Key
:local Value
:local ExitDo false
$fJSkipWhitespace
:while ($Jpos < [:len $JSONIn] and [:pick $JSONIn $Jpos]!="}" and !$ExitDo) do={
:if ([:pick $JSONIn $Jpos]!="\"") do={
:put "Err.Raise 8732. Expecting property name"
:set ExitDo true
} else={
:set Jpos ($Jpos + 1)
:set Key [$fJParseString]
$fJSkipWhitespace
:if ([:pick $JSONIn $Jpos] != ":") do={
:put "Err.Raise 8732. Expecting : delimiter"
:set ExitDo true
} else={
:set Jpos ($Jpos + 1)
:set Value [$fJParse true]
:set ($ParseObjectRet->$Key) $Value
:if ($Jdebug) do={:put "fJParseObject: Key=$Key Value="; :put $Value}
$fJSkipWhitespace
:if ([:pick $JSONIn $Jpos]=",") do={
:set Jpos ($Jpos + 1)
$fJSkipWhitespace
}
}
}
}
:set Jpos ($Jpos + 1)
# :if ($Jdebug) do={:put "ParseObjectRet: "; :put $ParseObjectRet}
:return $ParseObjectRet
}}
# ------------------- fByteToEscapeChar ----------------------
:global fByteToEscapeChar
:if (!any $fByteToEscapeChar) do={ :global fByteToEscapeChar do={
# :set $1 [:tonum $1]
:return [[:parse "(\"\\$[:pick "0123456789ABCDEF" (($1 >> 4) & 0xF)]$[:pick "0123456789ABCDEF" ($1 & 0xF)]\")"]]
}}
# ------------------- fUnicodeToUTF8----------------------
:global fUnicodeToUTF8
:if (!any $fUnicodeToUTF8) do={ :global fUnicodeToUTF8 do={
:global fByteToEscapeChar
# :local Ubytes [:tonum $1]
:local Nbyte
:local EscapeStr ""
:if ($1 < 0x80) do={
:set EscapeStr [$fByteToEscapeChar $1]
} else={
:if ($1 < 0x800) do={
:set Nbyte 2
} else={
:if ($1 < 0x10000) do={
:set Nbyte 3
} else={
:if ($1 < 0x20000) do={
:set Nbyte 4
} else={
:if ($1 < 0x4000000) do={
:set Nbyte 5
} else={
:if ($1 < 0x80000000) do={
:set Nbyte 6
}
}
}
}
}
:for i from=2 to=$Nbyte do={
:set EscapeStr ([$fByteToEscapeChar ($1 & 0x3F | 0x80)] . $EscapeStr)
:set $1 ($1 >> 6)
}
:set EscapeStr ([$fByteToEscapeChar (((0xFF00 >> $Nbyte) & 0xFF) | $1)] . $EscapeStr)
}
:return $EscapeStr
}}
# ------------------- Load JSON from arg --------------------------------
global JSONLoads
if (!any $JSONLoads) do={ global JSONLoads do={
global JSONIn $1
global fJParse
local ret [$fJParse]
set JSONIn
global Jpos; set Jpos
global Jdebug; if (!$Jdebug) do={set Jdebug}
return $ret
}}
# ------------------- Load JSON from file --------------------------------
global JSONLoad
if (!any $JSONLoad) do={ global JSONLoad do={
if ([len [/file find name=$1]] > 0) do={
global JSONLoads
return [$JSONLoads [/file get $1 contents]]
}
}}
# ------------------- Unload JSON parser library ----------------------
global JSONUnload
if (!any $JSONUnload) do={ global JSONUnload do={
global JSONIn; set JSONIn
global Jpos; set Jpos
global Jdebug; set Jdebug
global fByteToEscapeChar; set fByteToEscapeChar
global fJParse; set fJParse
global fJParseArray; set fJParseArray
global fJParseNumber; set fJParseNumber
global fJParseObject; set fJParseObject
global fJParsePrint; set fJParsePrint
global fJParsePrintVar; set fJParsePrintVar
global fJParseString; set fJParseString
global fJSkipWhitespace; set fJSkipWhitespace
global fUnicodeToUTF8; set fUnicodeToUTF8
global JSONLoads; set JSONLoads
global JSONLoad; set JSONLoad
global JSONUnload; set JSONUnload
}}
# ------------------- End JParseFunctions----------------------
Πηγή: mikrotik-json-parser @ GitHub (https://github.com/Winand/mikrotik-json-parser)
Βήμα 3: Δημιουργία του βασικού script ελέγχου και προώθησης
Πάμε System -> Scripts και φτιάχνουμε ένα νέο script με όνομα sms-telegram και περιεχόμενο:
(Αντικαθιστάτε τα {BOT_TOKEN} και {CHAT_ID} με αυτά που αναφέρθηκαν στα προαπαιτούμενα.)
:local botToken "{BOT_TOKEN}";
:local chatId "{CHAT_ID}";
:local parseMode "HTML";
:local smsPhone;
:local encodedPhone;
:local smsMessage;
:local encodedMessage;
:local smsEntry;
:local totalContent;
:local messageList [/tool sms inbox find];
:local messageListCount [:len $messageList];
:if ($messageListCount > 0) do={
/system script run "UrlEncode"; global UrlEncode;
:foreach i in=$messageList do={
:set smsPhone ("<b>" . [/tool sms inbox get $i phone] . "</b>");
:set encodedPhone [$UrlEncode $smsPhone];
:set smsMessage [/tool sms inbox get $i message];
:set encodedMessage [$UrlEncode $smsMessage];
:set smsEntry ($encodedPhone . "%0A" . $encodedMessage);
:set totalContent ($totalContent . $smsEntry . "%0A%2D%2D%2D%0A");
}
:local result [:tool fetch url="https://api.telegram.org/bot$botToken/sendMessage?parse_mode=$parseMode&chat_id=-$chatId&text=$totalContent" as-value output=user];
:local resultData ($result->"data");
/system script run "JParseFunctions"; global JSONLoads; global JSONUnload
:local finishResult ([$JSONLoads $resultData]->"ok");
:if ($finishResult = true) do={
:log info "SMS -> Telegram: Successfully forwarded $messageListCount SMS messages";
:foreach i in=$messageList do={
/tool sms inbox remove $i;
}
} else {
:log error "SMS -> Telegram: Error while forwarding $messageListCount SMS messages";
}
$JSONUnload;
}
Πηγή: @WhatTheIanni
Βήμα 4: Δημιουργία Scheduler entry για να εκτελείται περιοδικά το script μας
Πάμε System -> Scheduler και φτιάχνουμε ένα νέο entry με ότι όνομα θέλουμε, ορίζουμε το Start Time σε startup ώστε να ξεκινάει μετά από κάθε reboot και το Interval ανάλογα με το πόσο συχνά θέλουμε να γίνεται ο έλεγχος.
Στο On Event ορίζουμε:
/system/script/run sms-telegram;