├── .gitignore
├── LICENSE
├── README.md
├── config.ini
├── config.py
├── config_files
├── nginx
│ ├── tgbot.conf
│ └── vps.conf
└── supervisor
│ ├── bot.conf
│ └── sms.conf
├── data
├── Sketch.png
├── Sketch2.png
├── Sketch3.png
├── Sketch4.png
├── dump
└── last
├── relay.py
├── tg_callback.py
└── utils
├── TG_Bot.py
├── __init__.py
├── aws.py
├── contact_book.py
├── misc.py
├── reboot.sh
├── setwebhooks.py
├── sms.py
└── vcf_convertor.py
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | env/
12 | build/
13 | develop-eggs/
14 | dist/
15 | downloads/
16 | eggs/
17 | .eggs/
18 | lib/
19 | lib64/
20 | parts/
21 | sdist/
22 | var/
23 | wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 |
28 | # PyInstaller
29 | # Usually these files are written by a python script from a template
30 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
31 | *.manifest
32 | *.spec
33 |
34 | # Installer logs
35 | pip-log.txt
36 | pip-delete-this-directory.txt
37 |
38 | # Unit test / coverage reports
39 | htmlcov/
40 | .tox/
41 | .coverage
42 | .coverage.*
43 | .cache
44 | nosetests.xml
45 | coverage.xml
46 | *.cover
47 | .hypothesis/
48 |
49 | # Translations
50 | *.mo
51 | *.pot
52 |
53 | # Django stuff:
54 | *.log
55 | local_settings.py
56 |
57 | # Flask stuff:
58 | instance/
59 | .webassets-cache
60 |
61 | # Scrapy stuff:
62 | .scrapy
63 |
64 | # Sphinx documentation
65 | docs/_build/
66 |
67 | # PyBuilder
68 | target/
69 |
70 | # Jupyter Notebook
71 | .ipynb_checkpoints
72 |
73 | # pyenv
74 | .python-version
75 |
76 | # celery beat schedule file
77 | celerybeat-schedule
78 |
79 | # SageMath parsed files
80 | *.sage.py
81 |
82 | # dotenv
83 | .env
84 |
85 | # virtualenv
86 | .venv
87 | venv/
88 | ENV/
89 |
90 | # Spyder project settings
91 | .spyderproject
92 | .spyproject
93 |
94 | # Rope project settings
95 | .ropeproject
96 |
97 | # mkdocs documentation
98 | /site
99 |
100 | # mypy
101 | .mypy_cache/
102 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 ihc童鞋@提不起劲
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Android SMS Relay
2 | Script to forward android(with root) sms using adb
3 |
4 | Useful when you have another phone number but unwilling to carry 2 phones out.
5 |
6 | ### Features
7 |
8 | - Forward sms to telegram chat.
9 | - Match contacts automatically.
10 | - Send sms using telegram.
11 | - Some useful features:
12 | - Query phone number(You can import contacts from iCloud).
13 | - Query curriculum.
14 | - Dual sim card to different users.
15 | - Reply telegram message to reply sms quickly.
16 |
17 |
18 | ### Prerequisite
19 |
20 | - An android device with root and debug mode open.
21 | - I use an android 4.0.4 because of poor, on other versions you should check the debug and lock screen settings.
22 | - A linux server(Rpi for example) with adb tools installed.
23 | - Proper network connection
24 | - I use shadowsocks to provide a socks5 proxy for connecting to telegram server due to the GFW.
25 | - Also a tinc VPN is used to forward requests to inner server:
26 | - Flask ===SOCK FILE=== nginx(Rpi, Fudan Uni.) ===TINC=== VPS nginx(AWS, Seoul)
27 | - Python 2.7, requests, requests[socks], flask, uwsgi, nginx, supervisor
28 |
29 |
30 | ### How it works
31 |
32 | - Pull the database every several seconds, then check new sms from it. This process only cost about 0.01 sec, so it's fine.
33 | - Set a webhook to telegram bot, then it can receive message sent by the user.
34 | - Simulate key press when entering PIN code after reboot.
35 |
36 | 
37 | (Send and receive sms, contacts matching automatically)
38 |
39 |
40 |
41 | 
42 | (Query contacts)
43 |
44 |
45 |
46 |
47 | 
48 | (Quick reply && Message for sending status)
49 |
50 |
51 |
52 |
53 | 
54 | (Message update to sent status)
55 |
--------------------------------------------------------------------------------
/config.ini:
--------------------------------------------------------------------------------
1 | [uwsgi]
2 | wsgi-file = /opt/sms/tg_callback.py
3 | callable = app
4 | #http = 192.168.102.130:11100
5 | socket = /opt/sms/flask.sock
6 | chmod-socket = 666
7 | processes = 1
8 | threads = 1
9 | no-site=true
10 | pythonpath = /usr/local/lib/python2.7/dist-packages
11 | #pythonpath = /root/.local/lib/python2.7/site-packages
12 | #pythonpath = /usr/lib/python2.7/dist-packages
13 | #pythonpath = /usr/local/lib/python2.7/site-packages
14 | buffer-size = 32768
15 |
--------------------------------------------------------------------------------
/config.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Your telegram token (Create one if you haven't got it: https://telegram.me/botfather)
4 | TG_TOKEN = "YOUR_TELEGRAM_TOKEN"
5 | CHAT_ID = [259444514, 259444514] # Your chat id to yourself (2 items for dual sim card)
6 |
7 | KB_COMMAND = ["kb", u"课表"]
8 | KB_IMAGE = "https://unknown"
9 | KB_IMAGE_CAPTION = "小海的课表"
10 |
11 | FIND_CONTACT_COMMAND = ["search", "contact", "num"] # Commands to query contact book
12 |
13 | AWS_COMMAND = ["aws", u"流量"]
14 |
15 | SMS_COMMAND = ["sms"] # Commands to send sms
16 |
17 | # Proxy to connect to telegram
18 | USE_PROXY = True
19 | _PROXY = dict(http='socks5://127.0.0.1:16801', https='socks5://127.0.0.1:16801')
20 | PROXY = None if not USE_PROXY else _PROXY
21 |
22 | CONTACT = "/opt/sms/data/dump" # Path to contact json file
23 | MEM_SAVE_PATH = "/dev/shm/mmssms.db" # DB saving path when /dev/shm is available
24 | SAVE_PATH = "/tmp/mmssms.db" # DB saving path when /dev/shm is not available
25 | LAST_FILE = "/opt/sms/data/last" # File to save the time of last checking
26 | LOCK = "/dev/shm/sms-lock"
27 | MAX_LOCK_WAIT = 20
28 |
29 | FREE_SIZE = 50
30 | CHECK_INTERVAL = 10
31 |
--------------------------------------------------------------------------------
/config_files/nginx/tgbot.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 192.168.102.130:11100;
3 | server_name ihc.im default_server;
4 | charset utf-8;
5 | client_max_body_size 75M;
6 | location / { try_files $uri @yourapplication; }
7 | location @yourapplication {
8 | include uwsgi_params;
9 | uwsgi_pass unix:/opt/sms/flask.sock;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/config_files/nginx/vps.conf:
--------------------------------------------------------------------------------
1 | # Add this to your VPS nginx conf(NOT overwrite) to forward telegram requests to inner server.
2 |
3 | location = /YOUR_TG_TOKEN {
4 | proxy_pass http://192.168.102.130:11100;
5 | }
6 |
--------------------------------------------------------------------------------
/config_files/supervisor/bot.conf:
--------------------------------------------------------------------------------
1 | [program:bot]
2 | directory = /opt/sms
3 | command = /usr/local/bin/uwsgi -c /opt/sms/config.ini
4 | autostart = true
5 | autorestart = true
6 | startsecs = 5
7 | startretries = 30
8 | user = root
9 |
10 |
--------------------------------------------------------------------------------
/config_files/supervisor/sms.conf:
--------------------------------------------------------------------------------
1 | [program:sms]
2 | directory = /opt/sms
3 | command = /usr/bin/python /opt/sms/relay.py
4 | autostart = true
5 | autorestart = true
6 | startsecs = 5
7 | startretries = 30
8 | user = root
9 |
10 |
--------------------------------------------------------------------------------
/data/Sketch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ihciah/AndroidSMSRelay/3e8cc1842bc3b72adf446e4f6f88e559529da38c/data/Sketch.png
--------------------------------------------------------------------------------
/data/Sketch2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ihciah/AndroidSMSRelay/3e8cc1842bc3b72adf446e4f6f88e559529da38c/data/Sketch2.png
--------------------------------------------------------------------------------
/data/Sketch3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ihciah/AndroidSMSRelay/3e8cc1842bc3b72adf446e4f6f88e559529da38c/data/Sketch3.png
--------------------------------------------------------------------------------
/data/Sketch4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ihciah/AndroidSMSRelay/3e8cc1842bc3b72adf446e4f6f88e559529da38c/data/Sketch4.png
--------------------------------------------------------------------------------
/data/dump:
--------------------------------------------------------------------------------
1 | {"10001": "China Telecom", "10000": "China Telecom"}
2 |
--------------------------------------------------------------------------------
/data/last:
--------------------------------------------------------------------------------
1 | 1505196857314
--------------------------------------------------------------------------------
/relay.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import datetime
4 | import os
5 | import sqlite3
6 | import time
7 |
8 | from config import CHECK_INTERVAL, CONTACT
9 | from utils.TG_Bot import TGBot
10 | from utils.contact_book import Contact
11 | from utils.misc import LastFile, clean_env, get_db_save_path
12 |
13 | __author__ = 'ihciah'
14 |
15 | contact_book = Contact(CONTACT)
16 | last_time = LastFile()
17 |
18 |
19 | def send_telegram(address, date, date_sent, body, user=0):
20 | message = u"%s\n\nRecv at %s\nSend at %s\n\nSender: %s (%s)"
21 | date, date_sent = [datetime.datetime.fromtimestamp(int(d) / 1000).strftime('%m-%d %H:%M:%S')
22 | for d in (date, date_sent)]
23 | ret, sender_name = contact_book.num2name(address)
24 | if not ret:
25 | sender_name = "No matching contact"
26 | result = None
27 | try:
28 | result = TGBot.send_message(message % (body, date, date_sent, address, sender_name), user)
29 | except:
30 | pass
31 | return result
32 |
33 |
34 | def read_db():
35 | db_path = get_db_save_path()
36 | DOWNLOAD_COMMAND = "/usr/bin/adb pull /data/data/com.android.providers.telephony/databases/mmssms.db %s"
37 | os.system(DOWNLOAD_COMMAND % db_path)
38 | if not os.path.isfile(db_path) or os.path.getsize(db_path) == 0:
39 | clean_env()
40 | return
41 | conn = sqlite3.connect(db_path)
42 | cursor = conn.cursor()
43 | SQL = 'SELECT _id,address,date,date_sent,body,sub_id FROM sms WHERE date>%d AND type=1 ORDER BY date ASC'
44 | cursor.execute(SQL % last_time.get_last_time())
45 | values = cursor.fetchall()
46 | print values
47 | for _id, address, date, date_sent, body, sub_id in values:
48 | if send_telegram(address, date, date_sent, body, sub_id) is not None:
49 | last_time.update_time(date)
50 | conn.close()
51 | clean_env()
52 |
53 | if __name__ == "__main__":
54 | while True:
55 | try:
56 | read_db()
57 | except:
58 | pass
59 | time.sleep(CHECK_INTERVAL)
60 |
--------------------------------------------------------------------------------
/tg_callback.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from flask import Flask, request
4 | from config import KB_COMMAND, KB_IMAGE_CAPTION, FIND_CONTACT_COMMAND, SMS_COMMAND, AWS_COMMAND
5 | from config import TG_TOKEN, KB_IMAGE, CHAT_ID, CONTACT
6 | from utils.TG_Bot import TGBot
7 | from utils.contact_book import Contact
8 | from utils.misc import FileLock
9 | from utils.sms import send_sms, reply_sms
10 | from utils.aws import get_used_bandwidth
11 |
12 | __author__ = 'ihciah'
13 |
14 | contact = Contact(CONTACT)
15 |
16 | app = Flask(__name__)
17 |
18 |
19 | def parse_authorized_message(message):
20 | if 'text' not in message:
21 | return
22 | original_text = message['text'].strip()
23 | card = CHAT_ID.index(message['chat']['id'])
24 |
25 | # Send sms
26 | text = original_text.split(" ", 2)
27 | if len(text) >= 3 and text[0] in SMS_COMMAND:
28 | send_sms(text[1], text[2], card)
29 | return True
30 |
31 | # Reply sms
32 | if 'reply_to_message' in message and len(original_text):
33 | reply_sms(message['reply_to_message'], original_text, card)
34 | return True
35 |
36 | # Lookup contact
37 | text = original_text.split(" ", 1)
38 | if len(text) == 2 and text[0] in FIND_CONTACT_COMMAND:
39 | contact.send_contact(text[1], card)
40 | return True
41 |
42 | # KB command
43 | text = original_text
44 | if text in KB_COMMAND:
45 | TGBot.send_image(KB_IMAGE, KB_IMAGE_CAPTION)
46 | return True
47 |
48 | # AWS bandwidth command
49 | text = original_text
50 | if text in AWS_COMMAND:
51 | message_id = TGBot.send_message("[Working] Query AWS bandwidth...", card)
52 | used = get_used_bandwidth() / (1000 ** 3)
53 | TGBot.update_message("AWS bandwidth used: %.2f GB / 15 GB" % used, message_id, card)
54 | return True
55 |
56 | return False
57 |
58 |
59 | def parse_normal_message(message):
60 | if 'text' not in message:
61 | return
62 | chat_id = message['chat']['id']
63 |
64 | # Reply chat ID
65 | if message['text'] == "id":
66 | TGBot.send_message(str(chat_id), chat_id)
67 | else:
68 | TGBot.send_message("Command not found:\n%s" % message['text'], chat_id)
69 |
70 |
71 | def handle_message(msg):
72 | message = msg['message']
73 | flag = False
74 | if message['chat']['id'] in CHAT_ID:
75 | FileLock.wait_lock()
76 | try:
77 | FileLock.create_lock()
78 | flag = parse_authorized_message(message)
79 | finally:
80 | FileLock.delete_lock()
81 | if not flag:
82 | parse_normal_message(message)
83 |
84 |
85 | @app.route('/'+TG_TOKEN, methods=['POST'])
86 | def recv():
87 | j = request.get_json(force=True)
88 | try:
89 | handle_message(j)
90 | except:
91 | pass
92 | return "ok", 200
93 |
94 | if __name__ == '__main__':
95 | app.run(host="192.168.102.130", port=11100)
96 |
--------------------------------------------------------------------------------
/utils/TG_Bot.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import requests
4 | from config import TG_TOKEN, USE_PROXY, PROXY, CHAT_ID
5 |
6 | __author__ = 'ihciah'
7 |
8 |
9 | class TGBot:
10 | @staticmethod
11 | def send_message(text, user=0):
12 | tg_message_url = "https://api.telegram.org/bot%s/sendMessage" % TG_TOKEN
13 | user = int(user)
14 | data = {"chat_id": CHAT_ID[user] if user < len(CHAT_ID) else user,
15 | "text": text,
16 | "disable_notification": False
17 | }
18 | res = requests.post(tg_message_url, data, proxies=PROXY).json()
19 | if res["ok"]:
20 | return res["result"]["message_id"]
21 | return None
22 |
23 | @staticmethod
24 | def send_image(image_url, caption="", user=0):
25 | tg_photo_url = "https://api.telegram.org/bot%s/sendPhoto" % TG_TOKEN
26 | user = int(user)
27 | data = {"chat_id": CHAT_ID[user] if user < len(CHAT_ID) else user,
28 | "photo": image_url,
29 | "disable_notification": False,
30 | }
31 | if caption:
32 | data["caption"] = caption
33 | requests.post(tg_photo_url, data, proxies=PROXY)
34 |
35 | @staticmethod
36 | def update_message(text, message_id, user=0):
37 | tg_update_url = "https://api.telegram.org/bot%s/editMessageText" % TG_TOKEN
38 | user = int(user)
39 | data = {"chat_id": CHAT_ID[user] if user < len(CHAT_ID) else user,
40 | "text": text,
41 | "message_id": message_id
42 | }
43 | requests.post(tg_update_url, data, proxies=PROXY)
44 |
--------------------------------------------------------------------------------
/utils/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
--------------------------------------------------------------------------------
/utils/aws.py:
--------------------------------------------------------------------------------
1 | # -*-coding: utf-8 -*-
2 | __author__ = 'ihciah'
3 |
4 | from datetime import datetime
5 | from dateutil.tz import tzutc
6 |
7 | def get_used_bandwidth():
8 | import boto3
9 | now = datetime.utcnow()
10 | client = boto3.client('cloudwatch')
11 | response = client.get_metric_statistics(
12 | Namespace='AWS/EC2',
13 | MetricName='NetworkOut',
14 | Dimensions=[
15 | {
16 | 'Name': 'InstanceId',
17 | 'Value': 'i-068fb997b5721188c'
18 | },
19 | ],
20 | StartTime=datetime(now.year, now.month, 1, 0, 0, tzinfo=tzutc()),
21 | EndTime=datetime(now.year, now.month, now.day, 23, 59, tzinfo=tzutc()),
22 | Period=31*24*3600,
23 | Statistics=[
24 | 'Sum',
25 | ],
26 | #Unit='Gigabytes'
27 | )
28 | return response['Datapoints'][0]['Sum']
29 |
30 | if __name__ == "__main__":
31 | used = get_used_bandwidth()
32 | print "%.2f GB" % (used/(1000**3))
33 |
--------------------------------------------------------------------------------
/utils/contact_book.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import os
4 | import json
5 | from utils.TG_Bot import TGBot
6 |
7 | __author__ = 'ihciah'
8 |
9 |
10 | class Contact:
11 | def __init__(self, path="data/dump"):
12 | self.book = {}
13 | if os.path.isfile(path):
14 | with open(path) as f:
15 | try:
16 | d = json.loads(f.read())
17 | except:
18 | d = {}
19 | self.book = d
20 | self.rd = dict([(v.replace(" ", ""), k) for k, v in self.book.items()])
21 |
22 | def num2name(self, number):
23 | number = str(number)
24 | if len(number) == 13:
25 | number = number[-11:]
26 | if number in self.book:
27 | return True, self.book[number]
28 | return False, ""
29 |
30 | def search_name(self, name):
31 | ret = []
32 | if isinstance(name, (str, unicode)):
33 | name = [name]
34 | # if len(name) == 1 and name[0] in self.rd:
35 | # ret.append([name, self.rd[name]])
36 | # return ret
37 | for w, num in self.rd.items():
38 | for word in name:
39 | if w.find(word) == -1:
40 | break
41 | else:
42 | ret.append([w, num])
43 | return ret
44 |
45 | def send_contact(self, names, card):
46 | result = self.search_name(names.split())
47 | if result:
48 | result_message = ("Results for %s:\n" % names) + "\n".join(["%s %s" % (who, num) for who, num in result])
49 | TGBot.send_message(result_message, card)
50 | else:
51 | TGBot.send_message("No result for %s" % names, card)
52 |
--------------------------------------------------------------------------------
/utils/misc.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import os
4 | import time
5 |
6 | from config import MEM_SAVE_PATH, FREE_SIZE, SAVE_PATH, LAST_FILE, MAX_LOCK_WAIT, LOCK
7 |
8 | __author__ = 'ihciah'
9 |
10 |
11 | def clean_env():
12 | to_delete = ['/dev/shm/mmssms.db', '/dev/shm/mmssms.db-journal',
13 | '/tmp/mmssms.db', '/tmp/mmssms.db-journal']
14 | for f in to_delete:
15 | if os.path.exists(f):
16 | os.remove(f)
17 |
18 |
19 | def get_db_save_path():
20 | statvfs = os.statvfs('/dev/shm')
21 | free = statvfs.f_frsize * statvfs.f_bavail / 1024 / 1024
22 | return MEM_SAVE_PATH if free > FREE_SIZE else SAVE_PATH
23 |
24 |
25 | class LastFile:
26 | def __init__(self):
27 | self.last_time = self.get_last_time_on_disk()
28 |
29 | def get_last_time_on_disk(self):
30 | if os.path.isfile(LAST_FILE):
31 | with open(LAST_FILE) as f:
32 | last = f.read().strip()
33 | if last.isdigit() and len(last) > 9:
34 | return int(last)
35 | last = int(time.time() * 1000)
36 | self.dump_to_disk(last)
37 | return last
38 |
39 | def get_last_time(self):
40 | return self.last_time
41 |
42 | def dump_to_disk(self, t):
43 | with open(LAST_FILE, "w") as fw:
44 | fw.write(str(t))
45 |
46 | def update_time(self, t):
47 | if self.last_time >= t:
48 | return
49 | self.last_time = t
50 | self.dump_to_disk(t)
51 |
52 |
53 | class FileLock:
54 | @staticmethod
55 | def wait_lock():
56 | wait_time = 0.0
57 | while True:
58 | if wait_time > MAX_LOCK_WAIT:
59 | FileLock.delete_lock()
60 | if os.path.isfile(LOCK):
61 | time.sleep(0.5)
62 | wait_time += 0.5
63 | else:
64 | break
65 |
66 | @staticmethod
67 | def create_lock():
68 | open(LOCK, 'a').close()
69 |
70 | @staticmethod
71 | def delete_lock():
72 | try:
73 | os.remove(LOCK)
74 | finally:
75 | pass
76 |
--------------------------------------------------------------------------------
/utils/reboot.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # Script for input PIN code of SIM card(0000 in this case) when rebooting.
3 | # Use this only when you open the PIN lock on your SIM card.
4 | adb shell reboot
5 | sleep 45
6 | adb shell input text 0000
7 | sleep 2
8 | adb shell input keyevent 66
9 |
10 |
--------------------------------------------------------------------------------
/utils/setwebhooks.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Script to set telegram webhooks
3 |
4 | import requests
5 | from config import PROXY, TG_TOKEN
6 |
7 | __author__ = 'ihciah'
8 |
9 | CALLBACK = "https://ihc.im/" + TG_TOKEN # Modify this url to your callback url.
10 |
11 | url = "https://api.telegram.org/bot%s/setWebhook" % TG_TOKEN
12 | res = requests.post(url, {"url": CALLBACK}, proxies=PROXY)
13 | print res.content
14 |
--------------------------------------------------------------------------------
/utils/sms.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | import subprocess
3 | import re
4 |
5 | from utils.TG_Bot import TGBot
6 |
7 | __author__ = 'ihciah'
8 |
9 |
10 | def sms_escape(sms):
11 | sms = sms.replace("\"", "\\\"").replace("\\", "\\\\")
12 | sms = sms.replace("`", "\\`")
13 | return sms
14 |
15 |
16 | def send_sms(number, content, card):
17 | receiver = str(number).replace("+", "").replace(".", "")
18 | if receiver[:2] in ["13", "18", "17", "15", "14"] and len(receiver) == 11:
19 | receiver = "86" + receiver
20 | if not receiver.isdigit():
21 | TGBot.send_message("Number %s is invalid." % number, card)
22 | return
23 | sms = content
24 | sms = sms_escape(sms)
25 |
26 | message_id = TGBot.send_message("[Working] Sending message to %s:\n%s" % (receiver, content), card)
27 |
28 | if card == 0:
29 | # Send message using default sim card
30 | subprocess.call(['adb', 'shell', 'service', 'call', 'isms', '5', 's16',
31 | receiver, 'i32', '0', 'i32', '0', 's16', sms
32 | ])
33 | else:
34 | # Send message using secondary sim card
35 | # 61: Tab; 66: Enter; 20: Arrow_Down; 3: Home
36 | subprocess.call(['adb', 'shell', 'am', 'start', '-a', 'android.intent.action.SENDTO',
37 | '-d', 'sms:%s' % receiver, '--es', 'sms_body', '\"%s\"' % sms,
38 | '--ez', 'exit_on_sent', 'true', '-S'])
39 | subprocess.call(['sleep', '3'])
40 | exec_keycode = [61, 66, 20, 66, 3]
41 | for key in exec_keycode:
42 | subprocess.call(['adb', 'shell', 'input', 'keyevent', str(key)])
43 | subprocess.call(['sleep', '1'])
44 |
45 | if message_id is not None:
46 | TGBot.update_message("SMS to %s has been sent:\n%s" % (receiver, content), message_id, card)
47 | else:
48 | TGBot.send_message("SMS to %s has been sent:\n%s" % (receiver, content), card)
49 |
50 |
51 | def reply_sms(message_to_reply, sms_content, card):
52 | if 'text' in message_to_reply:
53 | reply_text = message_to_reply['text']
54 | last_line = reply_text.split("\n")[-1]
55 | pattern = re.compile(r'(\d{3,})')
56 | m = re.search(pattern, last_line)
57 | if m:
58 | send_sms(m.group(0), sms_content, card)
59 | return
60 | TGBot.send_message("Cannot reply message!", card)
61 |
--------------------------------------------------------------------------------
/utils/vcf_convertor.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import re
4 | import json
5 |
6 | __author__ = 'ihciah'
7 |
8 | person_patten = re.compile(r'BEGIN:VCARD(.*?)END:VCARD', re.DOTALL)
9 | fullname_patten = re.compile(r'FN:(.*?)\n')
10 | mobile_patten = re.compile(r':\+*?(\d{9}\d*?)\n')
11 |
12 | f = open(r'data/iCloud vCard.vcf')
13 | fc = f.read()
14 | people = person_patten.findall(fc)
15 | f.close()
16 |
17 | names = {}
18 | for p in people:
19 | for i in fullname_patten.findall(p):
20 | name = i
21 | if len(name.strip()) == 0:
22 | continue
23 | p = p.replace("-", "")
24 | for i in mobile_patten.findall(p):
25 | if len(i) == 13 and i[:2] == "86":
26 | i = i[2:]
27 | names[i] = name
28 |
29 | fl = open("dump", "w")
30 | fl.write(json.dumps(names))
31 | fl.close()
32 |
--------------------------------------------------------------------------------