This commit is contained in:
commit
89b7caaacc
3
.env.example
Normal file
3
.env.example
Normal file
@ -0,0 +1,3 @@
|
||||
PB_APIKEY=xxxxxxxxx
|
||||
PIN=0000
|
||||
GW_API=192.168.1.1
|
||||
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
launch.sh
|
||||
app/__pycache__
|
||||
data/*
|
||||
12
Dockerfile
Normal file
12
Dockerfile
Normal file
@ -0,0 +1,12 @@
|
||||
FROM "python:3.7-alpine"
|
||||
LABEL maintainer="Cabillot Julien <dockerimages@cabillot.eu>"
|
||||
|
||||
COPY app /app
|
||||
|
||||
WORKDIR "/app"
|
||||
|
||||
RUN pip install -r requirements.txt
|
||||
|
||||
USER "nobody"
|
||||
|
||||
ENTRYPOINT [ "/app/entrypoint" ]
|
||||
38
Jenkinsfile
vendored
Normal file
38
Jenkinsfile
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
pipeline {
|
||||
environment {
|
||||
registry = 'https://registry.hub.docker.com'
|
||||
registryCredential = 'dockerhub_jcabillot'
|
||||
dockerImage = 'jcabillot/huawei-3g-sms-api'
|
||||
}
|
||||
|
||||
agent any
|
||||
|
||||
triggers {
|
||||
cron('@midnight')
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Clone repository') {
|
||||
steps{
|
||||
checkout scm
|
||||
}
|
||||
}
|
||||
|
||||
stage('Build image') {
|
||||
steps{
|
||||
sh 'docker build -t ${dockerImage} .'
|
||||
}
|
||||
}
|
||||
|
||||
stage('Deploy Image') {
|
||||
steps{
|
||||
script {
|
||||
withCredentials([usernamePassword(credentialsId: 'dockerhub_jcabillot', usernameVariable: 'DOCKER_USER', passwordVariable: 'DOCKER_PASS')]) {
|
||||
sh 'docker login --username ${DOCKER_USER} --password ${DOCKER_PASS}'
|
||||
sh 'docker push ${dockerImage}'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
app/README.md
Normal file
11
app/README.md
Normal file
@ -0,0 +1,11 @@
|
||||
# huawei-3G-SMS-API
|
||||
|
||||
Program to check for SMS messages, archive and send via email
|
||||
|
||||
In future it will also include sending SMS
|
||||
|
||||
|
||||
Thanks to:
|
||||
https://github.com/juslop/3G-tunnel/blob/master/pi_sms.py
|
||||
https://github.com/trick77/huawei-hilink-status/blob/master/hstatus.py
|
||||
https://trick77.com/query-status-information-huaweis-hilink-3g-lte-modems/
|
||||
21
app/entrypoint.sh
Normal file
21
app/entrypoint.sh
Normal file
@ -0,0 +1,21 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [[ -z "${PB_APIKEY}" ]]
|
||||
then
|
||||
echo 'Please define the env var PB_APIKEY, exit' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "${PIN}" ]]
|
||||
then
|
||||
echo 'Please define the env var PIN, exit' >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if [[ -z "${GW_API}" ]]
|
||||
then
|
||||
echo 'Please define the env var GW_API, exit' >&2
|
||||
exit 3
|
||||
fi
|
||||
|
||||
python3 "/app/sms.py"
|
||||
2
app/requirements.txt
Normal file
2
app/requirements.txt
Normal file
@ -0,0 +1,2 @@
|
||||
pushbullet.py==0.11.0
|
||||
xmltodict==0.12.0
|
||||
14
app/sendEmail.py
Normal file
14
app/sendEmail.py
Normal file
@ -0,0 +1,14 @@
|
||||
import smtplib
|
||||
|
||||
def sendmail(subject, message, to):
|
||||
fromaddr = 'EMAIL-ADDRESS'
|
||||
toaddrs = to
|
||||
msg = "Subject: %s\n\n%s" % (subject, message)
|
||||
username = 'EMAIL-ADDRESS'
|
||||
password = 'PASSWORD'
|
||||
server = smtplib.SMTP('smtp.gmail.com:587') #default server for gmail, change if not using gmail
|
||||
server.ehlo()
|
||||
server.starttls()
|
||||
server.login(username,password)
|
||||
server.sendmail(fromaddr, toaddrs, msg)
|
||||
server.quit()
|
||||
180
app/sms.py
Normal file
180
app/sms.py
Normal file
@ -0,0 +1,180 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import sys, os
|
||||
import xmltodict
|
||||
import requests
|
||||
import json
|
||||
import time
|
||||
from pushbullet import Pushbullet
|
||||
|
||||
pb = Pushbullet(os.environ['PB_APIKEY'])
|
||||
|
||||
pin = os.environ['PIN']
|
||||
|
||||
PIN_ENTER_TEMPLATE = '''<request>
|
||||
<OperateType>0</OperateType>
|
||||
<CurrentPin>''' + PIN + '''</CurrentPin>
|
||||
<NewPin></NewPin>
|
||||
<PukCode></PukCode>
|
||||
</request>'''
|
||||
|
||||
SMS_LIST_TEMPLATE = '''<request>
|
||||
<PageIndex>1</PageIndex>
|
||||
<ReadCount>20</ReadCount>
|
||||
<BoxType>1</BoxType>
|
||||
<SortType>0</SortType>
|
||||
<Ascending>0</Ascending>
|
||||
<UnreadPreferred>0</UnreadPreferred>
|
||||
</request>'''
|
||||
|
||||
SMS_DEL_TEMPLATE = '<request><Index>{index}</Index></request>'
|
||||
|
||||
"""SMS_SEND_TEMPLATE = '''<request>
|
||||
<Index>-1</Index>
|
||||
<Phones><Phone>{phone}</Phone></Phones>
|
||||
<Sca></Sca>
|
||||
<Content>{content}</Content>
|
||||
<Length>{length}</Length>
|
||||
<Reserved>1</Reserved>
|
||||
<Date>{timestamp}</Date>
|
||||
</request>'''
|
||||
"""
|
||||
|
||||
__location__ = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__)))
|
||||
|
||||
def isHilink(device_ip):
|
||||
try:
|
||||
r = requests.get(url='http://' + device_ip + '/api/device/information', timeout=(2.0,2.0))
|
||||
except requests.exceptions.RequestException as e:
|
||||
return False;
|
||||
|
||||
if r.status_code != 200:
|
||||
return False
|
||||
return True
|
||||
|
||||
def getHeaders(device_ip):
|
||||
token = None
|
||||
sessionID = None
|
||||
try:
|
||||
r = requests.get(url='http://' + device_ip + '/api/webserver/SesTokInfo')
|
||||
except requests.exceptions.RequestException as e:
|
||||
return (token, sessionID)
|
||||
try:
|
||||
d = xmltodict.parse(r.text, xml_attribs=True)
|
||||
if 'response' in d and 'TokInfo' in d['response']:
|
||||
token = d['response']['TokInfo']
|
||||
d = xmltodict.parse(r.text, xml_attribs=True)
|
||||
if 'response' in d and 'SesInfo' in d['response']:
|
||||
sessionID = d['response']['SesInfo']
|
||||
headers = {'__RequestVerificationToken': token, 'Cookie': sessionID}
|
||||
except:
|
||||
pass
|
||||
return headers
|
||||
|
||||
|
||||
def getSMS(device_ip, headers):
|
||||
r = requests.post(url = 'http://' + device_ip + '/api/sms/sms-list', data = SMS_LIST_TEMPLATE, headers = headers)
|
||||
d = xmltodict.parse(r.text, xml_attribs=True)
|
||||
numMessages = int(d['response']['Count'])
|
||||
messagesR = d['response']['Messages']['Message']
|
||||
if numMessages == 1:
|
||||
temp = messagesR
|
||||
messagesR = [temp]
|
||||
messages = getContent(messagesR, numMessages)
|
||||
return messages, messagesR
|
||||
|
||||
def statusPin(device_ip, headers):
|
||||
r = requests.get(url = 'http://' + device_ip + '/api/pin/status', headers = headers)
|
||||
d = xmltodict.parse(r.text, xml_attribs=True)
|
||||
state = int(d['response']['SimState'])
|
||||
return state
|
||||
|
||||
def enterPin(pin, device_ip, headers):
|
||||
r = requests.post(url = 'http://' + device_ip + '/api/pin/operate', data = PIN_ENTER_TEMPLATE, headers = headers)
|
||||
d = xmltodict.parse(r.text, xml_attribs=True)
|
||||
print(d['response'])
|
||||
|
||||
def getContent(data, numMessages):
|
||||
messages = []
|
||||
for i in range(numMessages):
|
||||
message = data[i]
|
||||
number = message['Phone']
|
||||
content = message['Content']
|
||||
date = message['Date']
|
||||
messages.append('Message from ' + number + ' recieved ' + date + ' : ' + str(content))
|
||||
return messages
|
||||
|
||||
def delMessage(device_ip, headers, ind):
|
||||
r = requests.post(url = 'http://' + device_ip + '/api/sms/delete-sms', data = SMS_DEL_TEMPLATE.format(index=ind), headers = headers)
|
||||
d = xmltodict.parse(r.text, xml_attribs=True)
|
||||
print(d['response'])
|
||||
|
||||
def getUnread(device_ip, headers):
|
||||
r = requests.get(url = 'http://' + device_ip + '/api/monitoring/check-notifications', headers = headers)
|
||||
d = xmltodict.parse(r.text, xml_attribs=True)
|
||||
unread = int(d['response']['UnreadMessage'])
|
||||
return unread
|
||||
|
||||
if __name__ == "__main__":
|
||||
while True:
|
||||
device_ip = os.environ['GW_IP']
|
||||
if not isHilink(device_ip):
|
||||
print("Can't find a Huawei HiLink device on " + device_ip + ", exit")
|
||||
print('')
|
||||
sys.exit(-1)
|
||||
|
||||
headers = getHeaders(device_ip)
|
||||
# Require to enter the PIN to unlock device
|
||||
if statusPin(device_ip, headers) == 260:
|
||||
print('# Configure PIN')
|
||||
enterPin(os.environ['PIN'], device_ip, headers)
|
||||
|
||||
unread = getUnread(device_ip, headers)
|
||||
print('# Unread message(s) : %d' % unread)
|
||||
if unread != 0:
|
||||
messages, messagesR = getSMS(device_ip, headers)
|
||||
|
||||
#Read
|
||||
if not os.path.exists(os.path.join(__location__,'data',)):
|
||||
os.makedirs(os.path.join(__location__,'data'))
|
||||
try:
|
||||
f1 = open(os.path.join(__location__,'data',"sms.json"), 'r')
|
||||
data = json.load(f1)
|
||||
f1.close()
|
||||
except:
|
||||
data = []
|
||||
|
||||
f3 = open(os.path.join(__location__,'data',"sms.txt"), 'a')
|
||||
|
||||
# Ok, fonctionnel
|
||||
for i in range(len(messages)):
|
||||
# Json
|
||||
print('# Log JSON')
|
||||
data.append(messagesR[i])
|
||||
|
||||
# Text
|
||||
f3.write(messages[i] + '\n')
|
||||
# Pushbullet
|
||||
print('# Notif pushbullet')
|
||||
pb.push_note("SMS", "From: %s\nDate: %s\n%s" % (messagesR[i]['Phone'], messagesR[i]['Date'], messagesR[i]['Content']))
|
||||
|
||||
# Log HTTP
|
||||
print('# Notif HTTP')
|
||||
datam = {'sender' : messagesR[i]['Phone'], 'date': messagesR[i]['Date'], 'content': messagesR[i]['Content']}
|
||||
r = requests.post(url="https://sms.cabillot.eu", headers={'Content-Type': 'application/json' }, json=datam)
|
||||
#print(r.status_code)
|
||||
|
||||
#Save
|
||||
f2 = open(os.path.join(__location__,'data',"sms.json"), 'w')
|
||||
json.dump(data, f2)
|
||||
f2.close()
|
||||
|
||||
f3.close()
|
||||
|
||||
#delete from device
|
||||
for i in range(len(messagesR)):
|
||||
headers = getHeaders(device_ip)
|
||||
delMessage(device_ip, headers, messagesR[i]['Index'])
|
||||
|
||||
time.sleep(30)
|
||||
20
docker-compose.yml
Normal file
20
docker-compose.yml
Normal file
@ -0,0 +1,20 @@
|
||||
version: '2.3'
|
||||
|
||||
services:
|
||||
offlineimap:
|
||||
image: "jcabillot/huawei-3g-sms-api"
|
||||
container_name: "huawei-3g-sms-api"
|
||||
restart: "unless-stopped"
|
||||
mem_limit: "256m"
|
||||
cpus: 0.3
|
||||
cpu_shares: 1024
|
||||
pids_limit: 200
|
||||
volumes:
|
||||
# To store plain text & json logs
|
||||
- "./data:/app/data"
|
||||
environment:
|
||||
- "PB_APIKEY"
|
||||
- "PIN"
|
||||
- "GW_API"
|
||||
security_opt:
|
||||
- "no-new-privileges"
|
||||
Loading…
x
Reference in New Issue
Block a user