International SMS in encoding UCS2
#Скрипт пересылки SMS на email.
# Автор: pepelxl, 07.2019.
# Немного памятки:
# из модема sms можно извлечь в двух режимах – PDU и text
# Текст передаётся в трёх кодировках :
# 7bit – 160 символов
# 8bit – 140 символов
# UCS2 – 70 символов
# в режиме text, модем сам распарсит sms из 7bit и 8bit, но не сможет распасить ucs2.
# Мой скрип работает с режимом text, из минусов:
# - нет возможности сортировать и склеивать сообщения.
# - 7bit базируется на кодировке alphabet, не известно как передаст модем символы отличные от ANSII
# - 8bit может содержать кодировки на национальных языках, опять же проблема поведения и передачи символов.
# Обработчик ошибок так и не осилил, возможно сделаю позже.
# UCS2 по байтно совместим с UTF-16(базис план, 2byte), можно слать его сразу на почту,
# но тогда придётся разбивать шапку и тело, а поскольку национальное sms
# как правило состоит из нескольких штук, - будет не удобно.
# Кроме того, не все почтовые клиенты правильно обрабатывают ucs2.
# скрипт конвертирует UCS2 в UTF-8 и отсылает собранные sms в один email.
# текст будет в том же виде, как и пришел.
# cкрипт проверялся на оборудовании: Huawei me909, basebox2, routerOS 6.45.1(на более
# ранних версиях присутствует баг извлечения sms из модема).
#:log info "Running...";
# Переводим модем в режим чтения TEXT
/interface lte at-chat lte1 input="AT+CMGF=1";
# Читаем все сообщения
:local content [/interface lte at-chat lte1 input="AT+CMGL=\"all\"" as-value];
# Извлекаем элемент массива output в переменную
:set content ($content->"output");
# Проверяем, что сообщение есть
:if ([:len $content]>2) do={
:local lineEnd;
:local lineStart;
:local line "";
:local smsTo "";
:local smsDate "";
:local smsBody "";
:local ucs2text true;
:local outUtf "";
:local emailBody "";
:local flagEnd true;
:while ($flagEnd) do={
#ищем начало SMS
:set lineStart [ find $content "+CMGL:" $lineStart ] ;
# Проверяем что поиск завершился успешно
:if ([ typeof $lineStart ]="num") do={
# Ищем конец SMS
:set $lineEnd [ find $content "+CMGL:" $lineStart ];
:if ([ typeof $lineEnd ] = "nil") do={
:set $lineEnd [ find $content "OK" $lineStart ];
};
# вынимаем сообщение
:set line [ pick $content $lineStart ($lineEnd - 1) ];
# вынимаем телефон отправителя
:set $smsTo [ pick $line ([:find $line "\",\""] + 3) ([:find $line ",,"] - 1)];
# вынимаем дату
:set $smsDate [ pick $line ([:find $line ",,"] + 3) ([:find $line "\n"] - 2)];
# вынимаем тело
:set smsBody [:pick $line ([:find $line "\n"]+1) ([:len $line]-1)];
# проверяем в каком формате находится тело
:local iter [:len $smsBody];
:local hexCap "0123456789ABCDEF";
:while ($iter > 0) do={
:if ([:typeof [:find $hexCap [:pick $smsBody ($iter - 1) $iter]]] != "num") do={
:set $ucs2text false;
:set $iter 0;};
:set $iter ($iter - 1);
};
# Следующий блок конвертирует usc2 в utf-8
:if ($ucs2text) do={
:set $outUtf;
:local symbolsHex {"\00";"\01";"\02";"\03";"\04";"\05";"\06";"\07";"\08";"\09";"\0A";"\0B";"\0C";"\0D";"\0E";"\0F";"\10";"\11";"\12";"\13";"\14";"\15";"\16";"\17";"\18";"\19";"\1A";"\1B";"\1C";"\1D";"\1E";"\1F";"\20";"\21";"\22";"\23";"\24";"\25";"\26";"\27";"\28";"\29";"\2A";"\2B";"\2C";"\2D";"\2E";"\2F";"\30";"\31";"\32";"\33";"\34";"\35";"\36";"\37";"\38";"\39";"\3A";"\3B";"\3C";"\3D";"\3E";"\3F";"\40";"\41";"\42";"\43";"\44";"\45";"\46";"\47";"\48";"\49";"\4A";"\4B";"\4C";"\4D";"\4E";"\4F";"\50";"\51";"\52";"\53";"\54";"\55";"\56";"\57";"\58";"\59";"\5A";"\5B";"\5C";"\5D";"\5E";"\5F";"\60";"\61";"\62";"\63";"\64";"\65";"\66";"\67";"\68";"\69";"\6A";"\6B";"\6C";"\6D";"\6E";"\6F";"\70";"\71";"\72";"\73";"\74";"\75";"\76";"\77";"\78";"\79";"\7A";"\7B";"\7C";"\7D";"\7E";"\7F";"\80";"\81";"\82";"\83";"\84";"\85";"\86";"\87";"\88";"\89";"\8A";"\8B";"\8C";"\8D";"\8E";"\8F";"\90";"\91";"\92";"\93";"\94";"\95";"\96";"\97";"\98";"\99";"\9A";"\9B";"\9C";"\9D";"\9E";"\9F";"\A0";"\A1";"\A2";"\A3";"\A4";"\A5";"\A6";"\A7";"\A8";"\A9";"\AA";"\AB";"\AC";"\AD";"\AE";"\AF";"\B0";"\B1";"\B2";"\B3";"\B4";"\B5";"\B6";"\B7";"\B8";"\B9";"\BA";"\BB";"\BC";"\BD";"\BE";"\BF";"\C0";"\C1";"\C2";"\C3";"\C4";"\C5";"\C6";"\C7";"\C8";"\C9";"\CA";"\CB";"\CC";"\CD";"\CE";"\CF";"\D0";"\D1";"\D2";"\D3";"\D4";"\D5";"\D6";"\D7";"\D8";"\D9";"\DA";"\DB";"\DC";"\DD";"\DE";"\DF";"\E0";"\E1";"\E2";"\E3";"\E4";"\E5";"\E6";"\E7";"\E8";"\E9";"\EA";"\EB";"\EC";"\ED";"\EE";"\EF";"\F0";"\F1";"\F2";"\F3";"\F4";"\F5";"\F6";"\F7";"\F8";"\F9";"\FA";"\FB";"\FC";"\FD";"\FE";"\FF"};
:for curposition from=0 to=[:len $smsBody] step=4 do={
:local i [:tonum ("0x".[:pick $smsBody $curposition ($curposition +4)])];
:if ($i < 0x80) do={
:set $outUtf ($outUtf.($symbolsHex->$i));
};
:if (($i >= 0x80) and ($i < 0x800)) do={
:local byteA (($i >> 6) | 192);
:local byteB (($i & 63) | 128);
:set $outUtf ($outUtf.($symbolsHex->$byteA).($symbolsHex->$byteB));
};
:if ($i >= 0x800) do={
:local byteA (($i >> 12) | 224);
:local byteB ((($i >> 6) & 63) | 128);
:local byteC (($i & 63) | 128);
:set $outUtf ($outUtf.($symbolsHex->$byteA).($symbolsHex->$byteB).($symbolsHex->$byteC));
};
};
} else={:set $outUtf $smsBody;};
########## Здесь собираем тело письма в нужной последовательности ######
:set $emailBody ($emailBody."from: ".$smsTo."\r\nDate: ".$smsDate."\r\nMessage: ".$outUtf."\r\n\r\n");
#######################################################################
# Возвращаем флаг формата sms для следующего сообщения.
:set $ucs2text true;
# Останавливаем цикл, если прочитано последнее сообщение
} else={ :set $flagEnd false;};
};
#Отправляем письмо
:if ( [:len $emailBody] > 0 ) do={/tool e-mail send to=your@mail.ru subject="Mikrotik\r\nMIME-Version: 1.0\r\nContent-Type: text/plain; charset=utf-8" body=$emailBody;
:delay 10s;
#Удаляем все прочитанные sms
:if ( [ /tool e-mail get last-status ] = "succeeded") do={/interface lte at-chat lte1 input="at+cmgd=1,2";};
};
};
#:log info "END";