import unicodedata import subprocess import time def strip_accents(s): return "".join( c for c in unicodedata.normalize("NFD", s) if unicodedata.category(c) != "Mn" ) GSM_7_ALPHABET = ( "@£$¥èéùìòÇ\nØø\rÅåΔ_ΦΓΛΩΠΨΣΘΞ\x1bÆæßÉ !\"#¤%&'()*+,-./0123456789:;<=>" "?¡ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑÜ`¿abcdefghijklmnopqrstuvwxyzäöñüà" ) def is_gms_7(text: str) -> str: """Function that verify if the string is compatible with gsm 7 encoding""" for c in text: if not c in GSM_7_ALPHABET: return False return True def to_gsm_7(text: str) -> str: """Function that ensure the string is compatible with gsm 7 encoding""" return "".join([c if c in GSM_7_ALPHABET else strip_accents(c) for c in text]) def get_index_of_last_space_before_nth_char(text, n): """Function that checks where to cut the message.""" fragment = text[:n][::-1] # Split in on line feed if "\n" in fragment: return n - fragment.index("\n") # Split it on cariage return if "\r" in fragment: return n - fragment.index("\r") # Split it on white space if " " in fragment: return n - fragment.index(" ") # Split it anywhere return n def get_string_messages(msg, add_pagination=False): """Function that takes in a string message and returns an array of string messages with pagination if needed.""" if is_gms_7(msg): SMS_MAX_LENGTH = 160 SMS_CHUNK_LENGHT = 153 else: SMS_MAX_LENGTH = 70 SMS_CHUNK_LENGHT = 67 if len(msg) <= SMS_MAX_LENGTH: # No pagination is needed return [msg] else: # Pagination is needed string_messages = [] while msg: if len(msg) <= SMS_CHUNK_LENGHT: # if it's the last message then don't bother about not breaking words msg_len = len(msg) else: # check where is the last space before end of the sms to avoid breaking words msg_len = get_index_of_last_space_before_nth_char(msg, SMS_CHUNK_LENGHT) # generate new SMS msg_content = msg[:msg_len].strip() # append it to returned list string_messages.append(msg_content) # cut it out of the whole text msg = msg[msg_len:] # append pagination to each string message if add_pagination: for i in range(0, len(string_messages)): string_messages[i] += f"({i+1}/{len(string_messages)})" return string_messages # Android 9 # adb shell service call isms 7 i32 0 s16 "com.android.mms.service" s16 "+1234567890" s16 "null" s16 "Hey\ you\ !" s16 "null" s16 "null" def send_sms(phone_number, content): number = phone_number.replace(" ", "") if type(content) == list: for msg in content: send_sms(phone_number, msg) else: message = content.replace("\n", "${NL}") command = ( """adb shell "NL=$'\\n' ; service call isms 7 i32 0 s16 'com.android.mms.service' s16 \\\"""" + number + "\\\" s16 'null' s16 \\\"" + message + "\\\" s16 'null' s16 'null'\"" ) res = subprocess.check_output(command) if "Result: Parcel(00000000 '....')" in res.decode("utf-8"): return True else: raise Exception("Send SMS failed") def prepare_sms(phone_number: str, message: str, to_gsm=False): """Function that prepare the message to be send by SMS Convert it to GSM7 alphabet if required """ msg = message if to_gsm: msg = to_gsm_7(msg) content = get_string_messages(msg) send_sms(phone_number, content)