diff --git a/backup.sh b/backup.sh index df1fdb9..2afb14f 100644 --- a/backup.sh +++ b/backup.sh @@ -57,6 +57,7 @@ log "Backing up FreeSWITCH config" cp /etc/freeswitch/vars.xml freeswitch/ 2>/dev/null || true cp /etc/freeswitch/freeswitch.xml freeswitch/ 2>/dev/null || true cp /etc/freeswitch/extensions.conf freeswitch/ 2>/dev/null || true +mkdir -p freeswitch/chatplan scripts systemd_custom; rsync -a --delete /etc/freeswitch/chatplan/ freeswitch/chatplan/ 2>/dev/null || true; cp /usr/local/bin/fax-to-email.py /usr/local/bin/sms-inbound-consumer.py /usr/local/bin/sms-outbound-send.py scripts/ 2>/dev/null || true; cp /etc/systemd/system/sms-inbound.service systemd_custom/ 2>/dev/null || true # SIP profiles (noload — managed by FusionPBX, but useful as reference) rsync -a --delete /etc/freeswitch/sip_profiles/ freeswitch/sip_profiles/ 2>/dev/null || true # Autoload configs that may have been customized diff --git a/database/fusionpbx.sql.gz b/database/fusionpbx.sql.gz index 2d1898e..0527ce7 100644 Binary files a/database/fusionpbx.sql.gz and b/database/fusionpbx.sql.gz differ diff --git a/database/postgres_globals.sql b/database/postgres_globals.sql index fd42076..95604c7 100644 --- a/database/postgres_globals.sql +++ b/database/postgres_globals.sql @@ -2,7 +2,7 @@ -- PostgreSQL database cluster dump -- -\restrict 78AnL92lQFdwZ64KZQ6o9LoFNKTrKa37fiaf5ytmAkuTlrqof6wtBBAgnRZAVAU +\restrict Fqi0LR1GgckCG5uaN4PxUFRZ6PbrUMLEN2WFMdU2ryEIHAUNh8n2969dhH6qrgJ SET default_transaction_read_only = off; @@ -29,7 +29,7 @@ ALTER ROLE postgres WITH SUPERUSER INHERIT CREATEROLE CREATEDB LOGIN REPLICATION -\unrestrict 78AnL92lQFdwZ64KZQ6o9LoFNKTrKa37fiaf5ytmAkuTlrqof6wtBBAgnRZAVAU +\unrestrict Fqi0LR1GgckCG5uaN4PxUFRZ6PbrUMLEN2WFMdU2ryEIHAUNh8n2969dhH6qrgJ -- -- PostgreSQL database cluster dump complete diff --git a/scripts/fax-to-email.py b/scripts/fax-to-email.py new file mode 100755 index 0000000..18e764d --- /dev/null +++ b/scripts/fax-to-email.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +import sys, os, smtplib, subprocess +from email.message import EmailMessage +from datetime import datetime + +GMAIL_USER = "myronblair@gmail.com" +GMAIL_PASS = "demsvdylwweacbcx" + +def main(): + if len(sys.argv) < 4: + print("usage: fax-to-email.py ") + sys.exit(1) + + tiff_path = sys.argv[1] + to_email = sys.argv[2] + caller_id = sys.argv[3] + + if not os.path.exists(tiff_path): + print(f"tiff not found: {tiff_path}") + sys.exit(1) + + pdf_path = tiff_path.rsplit(".", 1)[0] + ".pdf" + subprocess.run(["tiff2pdf", "-o", pdf_path, tiff_path], check=True) + + msg = EmailMessage() + msg["Subject"] = f"Fax received from {caller_id} - {datetime.now().strftime('%Y-%m-%d %H:%M')}" + msg["From"] = GMAIL_USER + msg["To"] = to_email + msg.set_content(f"You received a fax from {caller_id}. See attached PDF.") + + with open(pdf_path, "rb") as f: + msg.add_attachment(f.read(), maintype="application", subtype="pdf", + filename=os.path.basename(pdf_path)) + + with smtplib.SMTP_SSL("smtp.gmail.com", 465) as s: + s.login(GMAIL_USER, GMAIL_PASS) + s.send_message(msg) + + print(f"Sent fax email to {to_email}") + +if __name__ == "__main__": + main() diff --git a/scripts/sms-inbound-consumer.py b/scripts/sms-inbound-consumer.py new file mode 100755 index 0000000..ad39214 --- /dev/null +++ b/scripts/sms-inbound-consumer.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 +import subprocess +import logging +from signalwire.relay.consumer import Consumer + +PROJECT = "16fbbcfd-1c94-4827-869c-0364f5f67488" +TOKEN = "PTfb129c5160af67841e2da19d5e9d94bcf6312a81fa43f248" +CONTEXT = "Texting for Fusion" +FUSION_DOMAIN = "fusion.orbishosting.com" +TARGET_EXT = "1001" + +logging.basicConfig(level="INFO") +log = logging.getLogger("sms-inbound") + + +class TextConsumer(Consumer): + def setup(self): + self.project = PROJECT + self.token = TOKEN + self.contexts = [CONTEXT] + + def ready(self): + log.info(f"Connected to SignalWire Relay, listening on context: {self.contexts}") + + def on_incoming_message(self, message): + from_num = message.from_number + body = message.body or "" + log.info(f"Inbound SMS from {from_num}: {body}") + deliver_to_phone(from_num, body) + + +def deliver_to_phone(from_num, body): + safe_body = body.replace('"', "'").replace("\n", " ") + chat_line = f"sip|{from_num}@{FUSION_DOMAIN}|internal/{TARGET_EXT}@{FUSION_DOMAIN}|{safe_body}" + result = subprocess.run( + ["fs_cli", "-x", f"chat {chat_line}"], + capture_output=True, text=True + ) + log.info(f"fs_cli chat delivery result: {result.stdout.strip()} {result.stderr.strip()}") + + +if __name__ == "__main__": + consumer = TextConsumer() + consumer.run() diff --git a/scripts/sms-outbound-send.py b/scripts/sms-outbound-send.py new file mode 100755 index 0000000..53d7a5b --- /dev/null +++ b/scripts/sms-outbound-send.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +import sys +import json +import urllib.request +import base64 + +PROJECT_ID = "16fbbcfd-1c94-4827-869c-0364f5f67488" +API_TOKEN = "PTfb129c5160af67841e2da19d5e9d94bcf6312a81fa43f248" +SPACE = "orbis-hosting.signalwire.com" +FROM_NUMBER = "+18177645007" + + +def send(to_number, body): + url = f"https://{SPACE}/api/messaging/messages" + payload = json.dumps({"to": to_number, "from": FROM_NUMBER, "body": body}).encode() + auth = base64.b64encode(f"{PROJECT_ID}:{API_TOKEN}".encode()).decode() + req = urllib.request.Request(url, data=payload, method="POST", headers={ + "Content-Type": "application/json", + "Authorization": f"Basic {auth}", + }) + try: + with urllib.request.urlopen(req) as resp: + print(resp.read().decode()) + except urllib.error.HTTPError as e: + print(f"HTTP {e.code}: {e.read().decode()}") + sys.exit(1) + + +def main(): + if len(sys.argv) < 3: + print("usage: sms-outbound-send.py ") + sys.exit(1) + send(sys.argv[1], sys.argv[2]) + + +if __name__ == "__main__": + main() diff --git a/systemd_custom/sms-inbound.service b/systemd_custom/sms-inbound.service new file mode 100644 index 0000000..b798391 --- /dev/null +++ b/systemd_custom/sms-inbound.service @@ -0,0 +1,13 @@ +[Unit] +Description=SignalWire SMS Inbound Consumer (deliver to ext 1001) +After=network.target freeswitch.service + +[Service] +Type=simple +ExecStart=/usr/bin/python3 /usr/local/bin/sms-inbound-consumer.py +Restart=always +RestartSec=5 +User=root + +[Install] +WantedBy=multi-user.target