Приём и обработка SMS-сообщений на Linux-машине
В одном из наших свежих проектов команде разработчиков была поставлена задача собрать максимально реальные контактные данные о пользователях нашего сайта. Жаркое обсуждение правильных и неправильных форм регистрации, одно- и двушаговые, дополнение информации по мере пользования сайтом… Казалось поток идей не остановится. Однако ни одна из них не гарантировала, что в результате мы не получим кучу никчемных данных. Валидировать? Можно, но разве все предусмотришь? Активация учетной записи через почтовый ящик для его валидации? Но куча сервисов типа 10 Minute Mail сводят на нет эффект. К тому же, специфика проекта не позволяла слишком растягивать процесс регистрации. Решено было, что пользователь должен зайти, сделать своё дело, а потом уже активировать или нет свою учетную запись. В конце концов прозвучала фраза «А давайте активировать по SMS!». Поиск провайдеров, изучение прайс-листов и отказ от идеи взвалить обработку SMS на стороннюю контору… Стало понятно, что принимать и обрабатывать их придется самим.
Скромный опыт работы с VOIP/Asterisk и подбора оборудования для VOIP-шлюза имелся. Полез по старым ссылкам к китайским братьям искать SMS-gateway. Но во-первых время поджимало, во-вторых по опыту работы с ними с первого раза редко что-то выходит, поэтому стало интересно, сможет ли обычный USB GSM-модем справиться. И, забегая вперед, скажу что это решение было правильным. По крайней мере на данном этапе.
Настройка сервера
Итак, ко мне в руки попал модемчик Huawei E1750 (HSPA USB Stick) с контрактом. Первое с чем столкнется человек взявшийся за подобную задачу, это то, что все свежие модели GSM-модемов, в угоду пользователям Windows, опознаются в системе сначала как устройство хранения данных (SCSI CD-ROM). С него запускается autorun, который установит драйвера и переключит модем в режим модема (о как!). Сразу как я узнал это, я решил «приехали». Однако еще полчаса, и была найдена утилита usb_modeswitch, которая выполняет переключение режимов модема. Только после этого модем заработает по его прямому назначению. Запускается и настраивается она просто, тут писать особо нечего.
Ну, с богом! Информации к этому моменту уже было нарыто не сказать чтоб много, но достаточно, чтобы копать в нужном направлении. Существующие решения были отфильтрованы по признаку «работает как демон», в итоге остался один кандидат — SMS Server Tools. Нужно отметить, что оригинальный пакет уже не развивается, но его продолжение SMS Server Tools 3 не только развивается, но и отлично поддерживается своим создателем Mr. Keijo «Keke» Kasvi.
К сожалению, в моей любимой Gentoo не нашлось ebuild-а для свежей версии, последняя имеющаяся версия 2.2.20. Но, недолго погуглив, я нашел уже готовый ebuild для 3-й версии, который и скомпилировал после небольшой его правки. На данный момент у меня установлена и стабильно работает версия 3.1.14.
Как оказалось, настройка smstools является настолько простой, что практически с начальным конфигом можно уже начинать принимать сообщения. Нет, ну конечно, если у вас симка закрыта пин-кодом, Вам его придется добавить в конфигурацию, но это делается очень просто.
Структура файла конфигурации тоже понятна до безобразия (viva unix-way!). В начале файла прописываем глобальные настройки демона, а затем в секциях описываем настройки наших устройств:
# Глобальные настройки демона
.
.
# Наш модем и его настройки
[Huawei E1750 ]
.
# И еще одно устройство, если оно у нас есть, со своими настройками
[AnotherModem]
.
Глобальные настройки
Самый важный параметр, это какие устройства демон будет опрашивать на предмет наличия новых сообщений. Если у вас всего одно устройство, как у меня, просто пропишите devices = HuaweiE1750 , если их у Вас несколько, перечислите их тут через запятую.
Еще два важных параметра — это user = smsd и group = sms . Людям, знакомым с линукс, объяснять их значение не надо, я же ограничусь лишь напоминанием о правильных правах на все ресурсы, к которым демон должен иметь доступ. Ну и упомяну про такие инструкции, как pidfile = /var/run/smsd/smsd.pid , logfile = /var/log/smsd/smsd.log , значение которых тоже должно быть понятно. Кстати, на момент отладки рекомендую вставить в конфигурацию также инструкцию loglevel = 7 , это позволит Вам отслеживать, что же происходит внутри демона. В дальнейшем я выставил loglevel = 5 .
Настройки модема
В принципе, тут тоже, как было обещано, все просто. Однако я столкнулся с некоторыми проблемами, из-за которых я собственно и решился поделиться с Вами информацией.
Одной проблемой стало жгучее желание модема все время соскочить на новое устройство. Один раз он определялся как /dev/ttyUSB0 , в другой раз под другим номером. Такое положение дел не устраивало меня. Поэтому, я стал искать как писать udev правила для устройств. Однако, когда я уже был готов внести свои изменения, обнаружилось, что ebuild usb_modeswitch уже сделал это за меня добавив в систему файл /lib64/udev/rules.d/40-usb_modeswitch.rules , согласно которому в системе появлялся симлинк на девайс по адресу /dev/gsmmodem . Его мы и пропишем в конфигурации.
Второй проблемой стало зависание модема время от времени. К сожалению, вычитывать матчасть времени уже не было, да и гугл выдал такое количество вариантов, что пробовать их все не имело смысла. Поэтому, не особо рассчитывая на помощь, я пополз на форум smstools3. Каковы же были мои удивление и радость, когда keke ответил на мой пост через жалких 2-3 часа. Нет, точного решения он не давал, однако две строки которые он рекомендовал добавить в конфиг раз и навсегда избавили меня от зависаний. Для меня до сих пор остаётся загадкой, где брать значения для них, я не нашел технической документации по модему:
check_memory_method = 1
memory_start = 0
Ну, и третьей проблемой, из-за которой затевался весь сыр-бор, стало написание обработчика SMS. Для этого в конфиг была добавлена инструкция eventhandler = /usr/local/scripts/activate , внутри которого происходила отправка на сервер проекта запроса на активацию учетной записи. Скрипт, получает два параметра — тип события и файл сообщения. Выдергивает из него нужные нам данные, и отсылает на сервер.
Итого, получили вот такой короткий конфиг:
devices = Huawei
loglevel = 5
user = smsd
group = sms
logfile = /var/log/smsd/smsd.log
infofile = /var/run/smsd/smsd.running
pidfile = /var/run/smsd/smsd.pid
alarmlevel = 7
alarmhandler = /usr/local/scripts/activate/smsd-alarm
[Huawei]
device = /dev/gsmmodem
baudrate = 115200
pin = 1111
incoming = high
cmgl_value = 0
check_memory_method = 1
memory_start = 0
eventhandler = /usr/local/scripts/activate
Неожиданный profit
Изначально форма регистрации содержала поле Мобильный телефон — это было в требованиях проекта. Пришедшее SMS должно было быть отправлено с указанного телефона, и учетная запись с этим телефоном активировалась. Однако, как оказалось, пользователи становятся в тупик, когда им в сообщении ничего не надо писать. Сначала после регистрации появилась инструкция «Отправьте на номер 12345678 сообщение с текстом «F»». Потом родилась другая, гениальная как сейчас кажется, идея: из формы было убрано поле Мобильный телефон, после короткой регистрации (Имя, Фамилия, E-mail/login, Пароль), пользователю выдается код, который он должен отправить на указанный номер. По этому коду находится учетная запись, а телефон, с которого пришла СМС-ка заносится в профиль пользователя. Вуаля, у нас есть пользователь, есть его реальный телефон, есть возможность добавить кучу телефонов в свой профиль, и сменить номер телефона в профиле в случае утери старого, отправив еще одну СМС и удалив старый номер.
Источник
Отправка SMS с 3G/GSM модема
Рождение идеи
Всё началось с того, что в одной небольшой сети магазинов возникла необходимость ежедневно информировать начальство о выручке по каждому магазину за день. В центральном офисе скапливается информация о продажах, её то и нужно донести до начальника. Ген.дир. (заказчик) — человек очень занятой, и как директору ему необходимо своевременно получать данные о выручке магазинов, интернет порой недоступен, а мобильник всегда под рукой, вот и было решено отправлять ему на телефон SMS с данными о выручке по каждому магазину, в простом и читабельном виде.
Пример SMS:
08.11.2011
1.Магазин A, 123045 р.
2.Магазин B, 134520 р.
3.Магазин C, 215403 р.
. ;
Как выяснилось в последующем это ещё не всё что требуется, но об этом чуть позже.
Сначала было предложено отправлять SMS через гейт, коих сейчас великое множество. Но заказчик сразу же отверг это предложение из соображений безопасности, ибо данные о дневной выручке — вещь довольно конфиденциальная. Затем было решено отправлять SMS просто с телефона подключенного к компу по USB кабелю, а в итоге и вовсе вместо телефона был задействован USB модем который уже давненько валялся без дела.
С чего начать
С COM портом конечно работать приходилось, а вот общаться с модемом по средствам AT команд, до этого как то не доводилось. AT команд конечно довольно много, но всё оказалось гораздо проще чем я ожидал, т.к. для нашей цели потребовались всего 5 команд:
AT+CMGF — задаёт режим работы: 0-цифровой или 1-текстовый. Эта команда будет вызываться первой, от этого зависит формат последующих команд и ответов модема.
AT+CMGS — отправка сообщения, формат параметра сильно зависти от режима (т.е. от прошлой команды).
AT+CMGL — чтение сообщений с модема, в качестве параметра можно передать одно из пяти значений, стоит обратить внимание что в зависимости от режима (AT+CMGF) следует передавать цифровые или строковые значения:
AT+CMGD — удаление одного сообщения с модема, в качестве параметра передаём номер сообщения.
AT+CMGR — чтение одного сообщения с модема, так же передаём номер сообщения.
Первые результаты
После нескольких часов (проб/ошибок) выяснил, что отправить SMS сообщение с модема ненамного сложнее чем сделать это с обычного мобильного телефона. Как уже упоминалось выше, для отправки SMS следует использовать команду «AT+CMGS». И так, открыл hyperterm, подключился к модему (через COM порт), и настрочил в порт следующие команды:
Пример того же самого на Delphi:
Вуаля, и карманный девайс сообщил о ожидаемом событии.
Но увы положительные эмоции возникшие у меня в момент этого успеха продлились недолго, а если точнее до того момента когда было обнаружено что с русским текстом всё гораздо сложнее. Во первых для отправки сообщений на русском нужно переключить режим с текстового на цифровой (AT+CMGF=0), а во вторых само сообщение должно быть отправлено в кодировке UCS2. И если с первым проблем минимум, то со вторым пришлось повозиться.
Кодировка текста в UCS и обратно (опять таки на Delphi):
Не скажу что всё получилось сразу и легко, но всё же получилось. Если раньше я отправлял в модем:
то для того чтобы отправить сообщение на русском нужно будет отправить:
Сначала переключение режима (в цифровой), затем отправляется длинна сообщения (84), а последняя строка содержит: номер телефона, текст сообщения и различные настройки (такие как: номер SMS-центра, сохранять ли сообщение у получателя и др.).
Пример на Delphi:
Развитие идеи
Сказать что я был счастлив когда на мобилу пришёл долгожданные русский текст, вместо «кракозябр», значит не сказать ничего. На следующий день дописал основную часть программы, и вроде бы всё. Сообщения с данными о выручке отправляются на телефон заказчику, вроде бы и жизнь то удалась, но не тут то было. Где то через неделю заказчик попросил доработать приложение, а именно сделать так чтобы после того как ему пришло SMS с текстом:
08.11.2011
1.Магазин A, 123045 р.
2.Магазин B, 134520 р.
3.Магазин C, 215403 р.
.
он бы мог в ответ на это сообщении отправить номер магазина и пришло бы новое сообщение, но уже с более детальной информацией по указанному магазину.
Ну в общем то логика простая: программа должна хранить последней отправленный «отчёт» по всем магазинам и читать входящие сообщения, как только появляется сообщение с условным текстом (например «магазин=12»), вытаскивать от туда номер магазина, смотреть в последнем отправленном сообщении что было под этим номером и отправлять детальную информацию по этому магазину (к сожалению на данный момент заказчик так и не определился с форматом и содержанием «подробного отчёта», так что в качестве примера привести нечего). Для реализации вышеупомянутой логики от модема требуется: прочитать SMS из памяти, удалить SMS из памяти (чтобы не скапливались). Для чтения сообщений использовал команды AT+CMGR и AT+CMGL (их краткое описание приводилось ранее). Чтение всех сообщений будет выглядеть как:
Здесь всё проще чем было раньше. Каждое сообщение состоит из 2х строк, в первой содержатся данные о сообщении (такие как: от кого, когда, номер сообщения), а во второй сам текст сообщения (опять таки в кодировке UCS, функция UCSToAnsi приводилась выше). Чтение одного сообщение осуществляется как:
Аналогичным образом происходит и удаление сообщений. Если например в моём случае отправить команду AT+CMGD=7, то при следующем AT+CMGL=«ALL» я уже не увижу сообщение номер 7, т.к. оно будет удалено.
Заключение
И так, были разобраны основные команды для работы с SMS сообщениями через GSM модем, была рассмотрена отправка, чтение, удаление сообщений. На последок хотелось бы отметить что область применения такого использования SMS сообщений довольно широка (особенно потому что можно организовать двухстороннюю связь). Например так: пользователь отправляет SMS, модем принимает, наша программа считывает, выполняет какие то действия исходя из текста сообщения и отправляет пользователю результата. Или наоборот: на ПК происходит какое то событие, и программа отправляет пользователю сообщение об этом событии. Удачи вам в ваших экспериментах, спасибо!
Источник
Управляем сервером посредством СМС
Настраиваем модем
Для начала необходимо подружить наш модем и Linux (кстати, я использую Centos 5.5). Втыкаем модем в один из свободных usb-портов. Первое, с чем приходится столкнуться, это то что модем определяется как CD-ROM, а с CD-ROM-а как известно смс-ки не отправишь и тем более не получишь. Для того чтоб это дело нам поправить, необходимо всего лишь скормить модему эту команду: AT^U2DIAG=0 (0 – только modem, 1 – modem + cd-rom, 255 – modem + cd-rom + cardreader, 256 – modem + cardreader). Если у вас есть под рукой компьютер, с установленной Windows, то открывайте HyperTerminal, подключайтесь к модему, вводите команду: AT^U2DIAG=0 и пропускайте следующий шаг.
Итак, заставляем модем быть модемом, а не каким-то CD-ROM-ом под Linux. Для начала необходимо поставить пакеты usb_modeswitch и minicom yum —enablerepo=rpmforge install usb_modeswitch minicom , затем создаем/правим /etc/usb-modeswitch.conf:
DefaultVendor = 0x12d1
DefaultProduct = 0x1446
MessageEndPoint = «0x01»
MessageContent = «55534243000000000000000000000011060000000000000000000000000000»
И перетыкаем модем в другой порт, необходимо подождать 5-10 секунд (необходимо чтоб модем определился как CD-ROM) и от root-а запускаем usb_modeswitch и видим примерно следующие:
Looking for target devices .
No devices in target mode or class found
Looking for default devices .
Found default devices (1)
Accessing device 004 on bus 007 .
Using endpoints 0x01 (out) and 0x81 (in)
Inquiring device details; driver will be detached .
Looking for active driver .
OK, driver found («usb-storage»)
OK, driver «usb-storage» detached
SCSI inquiry data (for identification)
————————-
Vendor String: HUAWEI
Model String: Mass Storage
Revision String: 2.31
————————-
USB description data (for identification)
————————-
Manufacturer: HUAWEI Technology
Product: HUAWEI Mobile
Serial No.: not provided
————————-
Setting up communication with interface 0 .
Trying to send the message to endpoint 0x01 .
OK, message successfully sent
Device is gone, skipping any further commands
-> Run lsusb to note any changes. Bye.
Должны появится новые устройства ttyUSB
ls /dev | grep ttyUSB :
ttyUSB0
ttyUSB1
ttyUSB2
Запускаем minicom –s настраиваем последовательный порт на работу с /dev/ttyUSB0,
Выходим из настроек, запускается терминал, затем необходимо отдать команду AT^U2DIAG=0 и получить в ответ ok
Процедура превращения модема в модем закончена, преступаем к установке/настройке smstools.
Smstools
Как ни странно, в огромных репозитариях rpmforge не нашлось места такому наиполезнейшему пакету как smstools. Но не беда, на просторах Интернета и на сайте производителя её достаточно. Я нашел пакет: smstools-3.0.10-4.el5.i386.rpm и «воспользовался» им rpm –i smstools-3.0.10-4.el5.i386.rpm. Настраиваем smstools, файл /etc/sms.conf:
devices = huaweiE1550
logfile = /var/log/smsd.log
loglevel = 2
[huaweiE1550]
device = /dev/ttyUSB0
baudrate = 115200
rtscts = no
init = at+cpms=»sm»,»sm»,»»
incoming = yes
incoming = high
настройки примерно понятные, запускаем демона, service smsd start и проверяем сие чудо: smssend 9128141111 ‘test message’ (не понимает кириллицу, необходимо конвертировать в UCS-2BE, в рамках этой статьи рассматривать не буду) и ждать смс-ки на мобильник. Если заветное сообщение не пришло, ставим в конфиге loglevel = 7 и идем за бубном. У меня поднялось все с первого раза.
smsctrl daemon
Итак разговаривать мы умеем, необходимо научиться слушать!
Если отправить смс-ку на номер симки в модеме, через некоторое время smsd создаст файл в /var/spool/sms/incoming/huaweiE1550.* примерно следующего содержания:
From: 79128141111
From_TOA: 91 international, ISDN/telephone
From_SMSC: 79126313431
Sent: 11-03-02 08:05:46
Received: 11-03-02 08:08:09
Subject: huaweiE1550
IMSI: 2500XXXXXXXXXXX
Report: no
Alphabet: ISO
UDH: false
Test message
Соответственно эти файлики мы и будем проверять на наличие команд для управления сервером. Для этого два способа 1-й небольшой демон на bash-е, 2-й встроеный обработчик событий в smsd.
1-й способ
COMMAND_CHAR=»#» – Признак команды
INCOMING_DIR=/var/spool/sms/incoming – Директория для входящих смс-ок
ALLOW_PHONES=»79128141111 79128141112″ – Номера с которых разрешены команды
SEND_BACK_REPORT=YES – Отправлять вывод смс-ой обратно
Чтобы не заморачиваться всякими пас фразами и т.д. было принято решение принимать команды только от определенных номеров (не проверял как будут выглядеть смс-ки от подменных номеров) и делать проверку на наличие спец символа перед командой, дабы отгородить от случайной смс-ки.
Сохраняем демона в /etc/init.d/smsctrl, chkconfig —add smsctrl , service smsctrl start
2-й способ
Дописываем в /etc/smsd.conf:
eventhandler = /root/bin/sms_event.sh
создаем /root/bin/sms_events.sh
Проверка
Создаем файлик /root/bin/test.sh следующего содержания:
Затем берем в руки телефон и посылаем смс с текстом #/root/bin/test.sh sms на заветный номер и смотрим в лог tail –f /var/log/smsctrl.log , если все хорошо — в ответ прилетит смс-ка вида: smsd.conf
Заключение
У меня данное решение, по смс-ке открывает ssh порт для входящих подключений. Я думаю, это не единственное применение, достаточно включить немного воображения.
Спасибо за внимание, с нетерпением жду Ваших комментариев.
UPD По замечанию моего хорошего друга, дополнил реализацию обработки водящих смс сообщений средствами smsd.
Источник