#!/usr/bin/env python3 import os import sys import uuid import base64 import getopt import requests import tempfile from libs.pysignald.signald import Signal from configparser import ConfigParser def usage(): print(os.path.basename(sys.argv[0]) + " [-h|--help] [-r|--register]") print("Runs the signal frontend to N. Reads the number to use from n_signal.ini") print(" -h|--help prints this help and exits") print(" -r|--register register the number with signal") def read_config(): config_object = ConfigParser() # config_object.read(os.environ.get('XDG_CONFIG_HOME') + "/n_signal.ini") config_object.read("n_signal.ini") info = config_object["INFO"] return info["number"] def register_signald(number): s = Signal(number) s.register(voice=False) code = input(f"Please input register code send via sms to {number}: ") s.verify(code) def handle_replies(replies): answer = "" if type(replies) is not list: replies = [replies] for reply in replies: l_answer = reply['text'] for annotation in reply["annotations"]: a_type = annotation["type"] a_extra, is_attachment = handle_replies(annotation["extra"]) if a_type == "command": l_answer = f"/{l_answer}: {a_extra}\n" elif a_type == "link": l_answer = f"{a_extra} ({l_answer})" elif a_type == "bold": l_answer = f"*{l_answer}*" elif a_type == "italic": l_answer = f"_{l_answer}_" elif a_type == "strikethrough": l_answer = f"~{l_answer}~" elif a_type == "attachment": [file_name, file_type, file_content] = a_extra.split(';') try: tmp_path = "/tmp/" + str(uuid.uuid1()) os.mkdir(tmp_path) # hack, do clean file_content = base64.b64decode(file_content) file_path = tmp_path + '/' + file_name with open(file_path, "wb") as f: f.write(file_content) return file_path, True except Exception as e: print(str(e)) answer += l_answer return answer, False def handle_response(response): replies = response.json()['reply'] return handle_replies(replies) def startup(number): s = Signal(number) # with args @s.chat_handler("^/([^\\s]+)\\s+([^$]*)$", order=10) # This is case-insensitive. def klinger(message, match): # Returning `False` as the first argument will cause matching to continue # after this handler runs. stop = True # TODO: try catch response = requests.post('http://localhost:18080', json={"command": match.group(1), "arguments": match.group(2).strip()}) answer, is_attachment = handle_response(response) return stop, answer, is_attachment # no args @s.chat_handler("^/(.+)$", order=20) # This is case-insensitive. def klinger(message, match): # Returning `False` as the first argument will cause matching to continue # after this handler runs. stop = True # TODO: try catch response = requests.post('http://localhost:18080', json={"command": match.group(1), "arguments": ""}) answer, is_attachment = handle_response(response) return stop, answer, is_attachment s.run_chat() def main(): number = read_config() try: opts, args = getopt.getopt(sys.argv[1:], "hr", ["help", "register"]) except getopt.GetoptError as err: # print help information and exit: print(err) # will print something like "option -a not recognized" usage() sys.exit(2) for o, a in opts: if o in ("-h", "--help"): usage() sys.exit() elif o in ("-r", "--register"): register_signald(number) sys.exit() else: assert False, "unhandled option: " + o startup(number) if __name__ == "__main__": main()