commit 876d8d17dc34f3b9c542b459aea24718a459a4d9 Author: Wonko the Sane Date: Sat Jul 10 14:17:24 2021 +0100 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..20b8ddc --- /dev/null +++ b/.gitignore @@ -0,0 +1,216 @@ + +# Created by https://www.toptal.com/developers/gitignore/api/python,emacs,git +# Edit at https://www.toptal.com/developers/gitignore?templates=python,emacs,git + +### Emacs ### +# -*- mode: gitignore; -*- +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* + +# Org-mode +.org-id-locations +*_archive + +# flymake-mode +*_flymake.* + +# eshell files +/eshell/history +/eshell/lastdir + +# elpa packages +/elpa/ + +# reftex files +*.rel + +# AUCTeX auto folder +/auto/ + +# cask packages +.cask/ +dist/ + +# Flycheck +flycheck_*.el + +# server auth directory +/server/ + +# projectiles files +.projectile + +# directory configuration +.dir-locals.el + +# network security +/network-security.data + + +### Git ### +# Created by git for backups. To disable backups in Git: +# $ git config --global mergetool.keepBackup false +*.orig + +# Created by git when using merge tools for conflicts +*.BACKUP.* +*.BASE.* +*.LOCAL.* +*.REMOTE.* +*_BACKUP_*.txt +*_BASE_*.txt +*_LOCAL_*.txt +*_REMOTE_*.txt + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# End of https://www.toptal.com/developers/gitignore/api/python,emacs,git + +# pyenv bits +.python-version + +# things truck adds for WingIDE +# which he has forgotten and will add later. diff --git a/README.md b/README.md new file mode 100644 index 0000000..b64e969 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +The new and improved python3 version is here! +Because as we all know, python2 is the work of the devil, a major contributor to global warming +and is probably responsible for the death of Jesus. + +Installing. + +Find a nice place to put the file 'sipproxy', preferrably in a directory of its own. +cd to that directory in a terminal/console/xterm and invoke the program by typing ./sipproxy +It is purposely verbose, and will display a running commentary on what is happening. +During this first run, the config file will be created as conf/config.conf and the phone book +will be created as conf/addressbook.conf; (Both of these files require editing, and a great +deal of effort has been put into using the right number words to enable the user to understand +what is required, without competing with 'War & Peace'). + + + diff --git a/sipproxy b/sipproxy new file mode 100755 index 0000000..be19efc --- /dev/null +++ b/sipproxy @@ -0,0 +1,612 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +#import sys first so that if we bale in the following try we can still exit clean. +import sys + +try: + # twisted imports + from twisted.internet.protocol import DatagramProtocol + from twisted.internet import reactor + + # system imports + import codecs + import os + import re + import signal + import socket + import syslog + import time +except ImportError: + print("Some modules missing: requires Twisted among others.\n") + sys.exit(1) + +################################################################## +os.chdir(os.path.dirname(__file__)) +BaseDir = os.getcwd() +CRLF = "\r\n" +confdir = "conf" +conffile = "config.conf" +config = "/" + confdir + "/" + conffile +phonebookfile = BaseDir + "/" + confdir + "/addressbook.conf" +ITSP = "127.0.0.1" +################################################################## + +def ReadConfig(): + print("Read config") + try: + with codecs.open(BaseDir + config, 'r', encoding='utf-8') as configfile: + for line in configfile: + preconf(line) + except: + print("Error reading " + BaseDir + config + "\nAborting") + + +def CreateConfig(): + print("Not found.\n") + print("Checking that " + BaseDir + "/" + confdir + " exists") + if (os.path.isdir(BaseDir + "/" + confdir) == False): + print("No. Attempting to create " + BaseDir + "/" + confdir) + try: + os.mkdir(BaseDir + "/" + confdir) + print("Success\n") + except OSError as e: + print("Can\'t create " + BaseDir + "/" + confdir) + print(e) + sys.exit(1) + except IOError as e: + print("Can\'t create " + BaseDir + "/" + confdir) + print(e) + sys.exit(1) + + else: + print("Yes.") + print("Attempting to write configuration file " + BaseDir + config) + try: + fh = codecs.open(BaseDir + config, 'w', encoding='utf-8') + fh.write('\n') + except IOError as e: + print("Error: can\'t write file - " + BaseDir + config) + print(e) + sys.exit(1) + except OSError as e: + print("Error: can\'t write file - " + BaseDir + config) + print(e) + sys.exit(1) + else: + fh.close() + with codecs.open(BaseDir + config, 'w', encoding='utf-8') as configfile: + configfile.write("# This software was written as a shim for a Grandstream Budget One VOIP telephone\r") + configfile.write(" operating on an ipv4 lan, to add a phone book and get around the UDP NAT problem.\r") + configfile.write(" consequently it does not require a stun server or other black magic to operate.\r") + configfile.write(" It will probably work with other VOIP telephones\n") + configfile.write("# Prerequisites.\r") + configfile.write(" A VOIP telephone\r") + configfile.write(" A computer on which to run, that has either direct access to the Internet, or has\r") + configfile.write(" the following 3 UDP ports portforwarded from something that does.\r") + configfile.write(" 5060, 11110, and 11111\n") + configfile.write("# The important settings in your VOIP telephone are :- \n") + configfile.write(" IP address:\r") + configfile.write(" SIP Server:\r") + configfile.write(" Outbound Proxy:\r") + configfile.write(" local RTP port:\r") + configfile.write("# These must match up with the settings below or it just won\'t work \n") + configfile.write("# In this configuration file, there are no defaults,\r") + configfile.write("# lines beginning with white space are comments\r") + configfile.write(" Anything after a # is a comment\n") + configfile.write(" The configuration lines must begin in column 1\r") + configfile.write(" so each of the following lines needs a value.\n\n") + configfile.write("LocalPhoneIP = 192.168.0.42 # ip address of the VOIP telephone\n") + configfile.write("LocalPhonePort = 5004 # local RTP port: in the telephone's setup menu\n") + configfile.write("ThisBoxIP = 192.168.0.69 # the Internet connected box I am running on\r") + configfile.write(" this is also the Outbound Proxy: in your telephone's setup.\n") + configfile.write("PublicIP = 127.0.0.1 # Where the sip provider will send your incoming calls\n") + configfile.write("ITSP = sip.sipdiscount.com # (Internet Telephone Service Provider)\r") + configfile.write(" this the same as SIP Server: in your telephone\'s setup.\n") + configfile.write("UserID = bob_smith # SIP User ID: in your telephone\'s setup. This is used to \r") + configfile.write(" prevent random idiots making your phone ring whilst unsuccessfully\r") + configfile.write(" trying to steal your bandwidth/services.\n") + configfile.write("logfile = /var/log/phone.log # needs root to write to /var/log so use a file you have actual\r") + configfile.write(" permission to write to.\n") + configfile.write(" \n") + configfile.write(" \n") + print("Config file " + BaseDir + config + " successfully written.") + print("Additionally, " + BaseDir + config + " will require editing before you can continue.") + +def preconf(line): + global LocalPhoneIP + global LocalPhonePort + global ThisBoxIP + global PublicIP + global ITSP + global UserID + global logfile + + if(line[:12] == u"LocalPhoneIP"): + LocalPhoneIP = line.split("=")[1].strip() + LocalPhoneIP = LocalPhoneIP.split("#")[0].strip() + print("LocalPhoneIP = " + LocalPhoneIP) + + if(line[:14] == u"LocalPhonePort"): + LocalPhonePort = line.split("=")[1].strip() + LocalPhonePort = LocalPhonePort.split("#")[0].strip() + print("LocalPhonePort = " + LocalPhonePort) + + if(line[:9] == u"ThisBoxIP"): + ThisBoxIP = line.split("=")[1].strip() + ThisBoxIP = ThisBoxIP.split("#")[0].strip() + print("ThisBoxIP = " + ThisBoxIP) + + if(line[:8] == u"PublicIP"): + PublicIP = line.split("=")[1].strip() + PublicIP = PublicIP.split("#")[0].strip() + print("PublicIP = " + PublicIP) + + if(line[:4] == u"ITSP"): + ITSP = line.split("=")[1].strip() + ITSP = ITSP.split("#")[0].strip() + print("ITSP = " + ITSP) + + if(line[:6] == u"UserID"): + UserID = line.split("=")[1].strip() + UserID = UserID.split("#")[0].strip() + print("UserID = " + UserID) + + if(line[:7] == u"logfile"): + logfile = line.split("=")[1].strip() + logfile = logfile.split("#")[0].strip() + print("logfile = " + logfile) + +def isip(addr): + try: + socket.inet_aton(addr) + return True + except socket.error: + return False + +################################################################## +#variable +BookList = [] +Destination = "127.0.0.1" +Remote_Audio_IP = "127.0.0.1" +Remote_Audio_Port = "61110" +Local_Audio_IP = "127.0.0.1" +Local_Audio_Port = "61110" +register_regex = 'CSeq: (.+?) REGISTER' +inviteSD_regex = 'INVITE sip:(.+?)@sipdiscount.com SIP/2' +register_pattern=re.compile(register_regex, flags=re.IGNORECASE) +inviteSD_pattern=re.compile(inviteSD_regex, flags=re.IGNORECASE) +################################################################## +class Sip(DatagramProtocol): + def datagramReceived(self, data, addr): + global Destination + try: + data = data.decode() + except UnicodeDecodeError as e: + print("random shite detected from " + addr[0]) + print(e) + return + + Time = time.strftime("%Y-%m-%d %H:%M:%S") + reg = re.findall(register_pattern,data) + if reg: + Destination = ITSP # Registration always with ITSP + print(Time, "From:", addr[0]) + print(data[:12]) + else: + try: + syslog.syslog("From " + addr[0]) + syslog.syslog(data) + print(Time, "From:", addr[0]) + print(data) + except TypeError: + syslog.syslog("TypeError") + print(Time, "TypeError:") + + tdata = Proxy(data, addr) + + if (addr[0] == LocalPhoneIP): + reg = re.findall(register_pattern,tdata) + if reg: + Destination = ITSP # Registration always with ITSP + self.transport.write(tdata.encode(), (Destination, 5060)) + print(tdata[:12]) + else: + syslog.syslog("To " + Destination) + syslog.syslog(tdata) + print(Time, "To:", Destination) + self.transport.write(tdata.encode(), (Destination, 5060)) + print(tdata) + else: + if (addr[0] != LocalPhoneIP): + Logit(Time + " From ip: " + addr[0] + " " + data) + if (UserID in data): + Destination = addr[0] + reg = re.findall(register_pattern,tdata) + if reg: + self.transport.write(tdata.encode(), (LocalPhoneIP, 5060)) + print(tdata[:12]) + else: + syslog.syslog("To " + LocalPhoneIP) + syslog.syslog(tdata) + print(Time, "To:", LocalPhoneIP) + self.transport.write(tdata.encode(), (LocalPhoneIP, 5060)) + print(tdata) + + else: + Logit(Time + " From ip: " + addr[0] + " " + tdata) + +################################################################## + +def Proxy(data, addr): + if (addr[0] == LocalPhoneIP): + tdata = FromLocal(data, addr) + else: + tdata = FromRemote(data, addr) + if ("m=audio" in tdata): + return(tdata.strip() + CRLF) + else: + return(tdata.strip() + CRLF + CRLF) + +################################################################## + +def FromRemote(data, addr): + global Remote_Audio_IP # spurious, probably unneeded + + data = data.replace(PublicIP, LocalPhoneIP) + data = data.replace(addr[0], ThisBoxIP) + data = Remote_SDP_Edit(data) + return data + +################################################################## + +def FromLocal(data, addr): + global Destination + data = FoneBook(data) +# Too many bugs, needs thinking about. +# reg = re.findall(register_pattern,data) +# if reg: +# Destination = ITSP +# print("Destination is " + Destination) +# data = data.replace(addr[0], PublicIP) +# data = Local_SDP_Edit(data) +# return data +# +# sd = re.findall(inviteSD_pattern,data) +# if sd: +# Destination = ITSP +# print("Destination is " + Destination) +# else: +# if ("INVITE sip:" in data): +# begin = data.find("@") +# begin = begin + 1 +# nigeb = data.find(" ", begin) +# Destination = data[begin:nigeb] +# Destination = Destination.split(':')[0] +# print("Destination is " + Destination) +# +# if isip(Destination) == False: +# Destination = socket.gethostbyname(Destination) +# +# print("Destination is " + Destination) + data = data.replace(addr[0], PublicIP) + data = Local_SDP_Edit(data) +# print(data) + return data + +################################################################## + +class OutRTP(DatagramProtocol): + def datagramReceived(self, data, addr): + global Remote_Audio_IP + global Remote_Audio_Port + if (addr[0] == LocalPhoneIP): + dst = ((Remote_Audio_IP, int(Remote_Audio_Port))) + else: + dst = ((LocalPhoneIP, int(LocalPhonePort))) + self.transport.write(data, dst) + +################################################################## + +class OutRTCP(DatagramProtocol): + def datagramReceived(self, data, addr): + global Remote_Audio_IP + global Remote_Audio_Port + if (addr[0] == LocalPhoneIP): + dst = ((Remote_Audio_IP, int(Remote_Audio_Port) + 1)) + else: + dst = ((LocalPhoneIP, (int(LocalPhonePort) + 1))) + self.transport.write(data, dst) + +################################################################## + +def FoneBook(data): + for line in BookList: + if (line.split("=")[0] in data): + data = data.replace(line.split("=")[0],line.split("=")[1]) + return data + +################################################################## + +def Local_SDP_Edit(data): #fiddle with data from localphone + global Local_Audio_IP + global Local_Audio_Port + if ("m=audio" in data): + PortA = data.split("m=audio ")[1] + Local_Audio_Port = PortA.split()[0] + IPA = data.split("c=IN IP4 ")[1] + Local_Audio_IP = IPA.split()[0] + data = data.replace("m=audio " + Local_Audio_Port, "m=audio 11110") + data = data.replace("IN IP4 " + Local_Audio_IP, "IN IP4 " + PublicIP) + First = data.split("Content-Length: ")[0] + "Content-Length: " + Second = data.split(CRLF + CRLF)[1] + ilength = len(Second) + return First + str(ilength) + CRLF + CRLF + Second + else: + return data + +################################################################## + +def Remote_SDP_Edit(data): #fiddle with data from remotephone + global Remote_Audio_IP + global Remote_Audio_Port + if ("m=audio" in data): + PortA = data.split("m=audio ")[1] + Remote_Audio_Port = PortA.split()[0] + IPA = data.split("c=IN IP4 ")[1] + Remote_Audio_IP= IPA.split()[0] + data = data.replace("m=audio " + Remote_Audio_Port, "m=audio 11110") + data = data.replace("IN IP4 " + Remote_Audio_IP, "IN IP4 " + ThisBoxIP) + First = data.split("Content-Length: ")[0] + "Content-Length: " + Second = data.split(CRLF + CRLF)[1] + ilength = len(Second) + return First + str(ilength) + CRLF + CRLF + Second + else: + return data + +################################################################## + +def signal_handler(sig, frame): + print + print("signal", sig) + Time = time.strftime("%Y-%m-%d %H:%M:%S") + print(Time, "Shutting down") + reactor.stop() + print('reactor stopped') + syslog.syslog("SIGINT - Shutting Down!") + os._exit(0) + syslog.syslog("Not Visible in syslog.") + quit() + + +################################################################## +def MkFoneBook(): + Blurb001 = "# This fonebook is crude, the error checking is minimal, so if you screw it up, then it wont work.\n" + Blurb002 = "# However, if you delete the screwed up copy, the basic file will be recreated by SipProxy.\n\n" + Blurb003 = "# Lines beginning with # are ignored, as are lines consisting solely of whitespace and blank lines.\n#\n" + Blurb004 = "#Replace=With\n" + + Blurb005 = "#01* Geographic area codes.\n" + Blurb006 = "INVITE sip:01=INVITE sip:00441\n" + Blurb007 = "ACK sip:01=ACK sip:00441\n" + Blurb008 = "BYE sip:01=BYE sip:00441\n" + Blurb009 = "CANCEL sip:01=CANCEL sip:00441\n\n" + + Blurb010 = "#02* Geographic area codes (introduced in 2000).\n" + Blurb011 = "INVITE sip:02=INVITE sip:00442\n" + Blurb012 = "ACK sip:02=ACK sip:00442\n" + Blurb013 = "BYE sip:02=BYE sip:00442\n" + Blurb014 = "CANCEL sip:02=CANCEL sip:00442\n\n" + + Blurb015 = "#03* Nationwide non-geographic code, charged to caller at geographic area code rates (introduced 2007).\n" + Blurb016 = "INVITE sip:03=INVITE sip:00443\n" + Blurb017 = "ACK sip:03=ACK sip:00443\n" + Blurb018 = "BYE sip:03=BYE sip:00443\n" + Blurb019 = "CANCEL sip:03=CANCEL sip:00443\n\n" + + Blurb020 = "#05* Corporate numbering and VoIP services\n" + Blurb021 = "INVITE sip:05=INVITE sip:00445\n" + Blurb022 = "ACK sip:05=ACK sip:00445\n" + Blurb023 = "BYE sip:05=BYE sip:00445\n" + Blurb024 = "CANCEL sip:05=CANCEL sip:00445\n\n" + + Blurb025 = "#07* Mostly for mobile phones\n" + Blurb026 = "INVITE sip:07=INVITE sip:00447\n" + Blurb027 = "ACK sip:07=ACK sip:00447\n" + Blurb028 = "BYE sip:07=BYE sip:00447\n" + Blurb029 = "CANCEL sip:07=CANCEL sip:00447\n\n" + + Blurb030 = "#08* Freephone (toll free) on 080, and Special Services (formerly known as local and national rate) on 084 and 087.\n" + Blurb031 = "INVITE sip:08=INVITE sip:00448\n" + Blurb032 = "ACK sip:08=ACK sip:00448\n" + Blurb033 = "BYE sip:08=BYE sip:00448\n" + Blurb034 = "CANCEL sip:08=CANCEL sip:00448\n\n" + + Blurb035 = "#The following numbers are for Scunthorpe (01724) local numbers.\n" + Blurb036 = "INVITE sip:2=INVITE sip:004417242\n" + Blurb037 = "ACK sip:2=ACK sip:004417242\n" + Blurb038 = "BYE sip:2=BYE sip:004417242\n" + Blurb039 = "CANCEL sip:2=CANCEL sip:004417242\n\n" + + Blurb040 = "INVITE sip:3=INVITE sip:004417243\n" + Blurb041 = "ACK sip:3=ACK sip:004417243\n" + Blurb042 = "BYE sip:3=BYE sip:004417243\n" + Blurb043 = "CANCEL sip:3=CANCEL sip:004417243\n\n" + + Blurb044 = "INVITE sip:7=INVITE sip:004417247\n" + Blurb045 = "ACK sip:7=ACK sip:004417247\n" + Blurb046 = "BYE sip:7=BYE sip:004417247\n" + Blurb047 = "CANCEL sip:7=CANCEL sip:004417247\n\n" + + Blurb048 = "INVITE sip:8=INVITE sip:004417248\n" + Blurb049 = "ACK sip:8=ACK sip:004417248\n" + Blurb050 = "BYE sip:8=BYE sip:004417248\n" + Blurb051 = "CANCEL sip:8=CANCEL sip:004417248\n\n" + + Blurb052 = "# Here can be placed upto 100, 3 digit, speed dial shortcuts, from 100 to 199.\n" + Blurb053 = "# Each entry is a pair of lines, firstly the #speed dial number and description.\n" + Blurb054 = "# Secondly the 'Replace=With' for the preceeding line.\n\n" + + Blurb0541 = "# As far as the telephone is concerned, all traffic goes to sipdiscount.com\n" + Blurb0542 = "# so if we want it go elsewhere we need to check the destination after the phonebook\n" + Blurb0543 = "# has fiddled with it and set the destination accordingly.\n\n" + + Blurb055 = "#100 Example speed dial 1\n" + Blurb056 = "INVITE sip:100@sip.sipdiscount.com=INVITE sip:00441724280280@sip.sipdiscount.com\n" + Blurb057 = "ACK sip:100@sip.sipdiscount.com=ACK sip:00441724280280@sip.sipdiscount.com\n" + Blurb058 = "BYE sip:100@sip.sipdiscount.com=BYE sip:00441724280280@sip.sipdiscount.com\n" + Blurb059 = "CANCEL sip:100@sip.sipdiscount.com=CANCEL sip:00441724280280@sip.sipdiscount.com\n\n" + + Blurb060 = "#101 Example speed dial 2\n" + Blurb061 = "INVITE sip:101@sip.sipdiscount.com=INVITE sip:00441724855555@sip.sipdiscount.com\n" + Blurb062 = "ACK sip:101@sip.sipdiscount.com=ACK sip:00441724855555@sip.sipdiscount.com\n" + Blurb063 = "BYE sip:101@sip.sipdiscount.com=BYE sip:00441724855555@sip.sipdiscount.com\n" + Blurb064 = "CANCEL sip:101@sip.sipdiscount.com=CANCEL sip:00441724855555@sip.sipdiscount.com\n" + + try: + fh = codecs.open(phonebookfile, 'w', encoding='utf-8') + fh.write(Blurb001) + fh.write(Blurb002) + fh.write(Blurb003) + fh.write(Blurb004) + fh.write(Blurb005) + fh.write(Blurb006) + fh.write(Blurb007) + fh.write(Blurb008) + fh.write(Blurb009) + fh.write(Blurb010) + fh.write(Blurb011) + fh.write(Blurb012) + fh.write(Blurb013) + fh.write(Blurb014) + fh.write(Blurb015) + fh.write(Blurb016) + fh.write(Blurb017) + fh.write(Blurb018) + fh.write(Blurb019) + fh.write(Blurb020) + fh.write(Blurb021) + fh.write(Blurb022) + fh.write(Blurb023) + fh.write(Blurb024) + fh.write(Blurb025) + fh.write(Blurb026) + fh.write(Blurb027) + fh.write(Blurb028) + fh.write(Blurb029) + fh.write(Blurb030) + fh.write(Blurb031) + fh.write(Blurb032) + fh.write(Blurb033) + fh.write(Blurb034) + fh.write(Blurb035) + fh.write(Blurb036) + fh.write(Blurb037) + fh.write(Blurb038) + fh.write(Blurb039) + fh.write(Blurb040) + fh.write(Blurb041) + fh.write(Blurb042) + fh.write(Blurb043) + fh.write(Blurb044) + fh.write(Blurb045) + fh.write(Blurb046) + fh.write(Blurb047) + fh.write(Blurb048) + fh.write(Blurb049) + fh.write(Blurb050) + fh.write(Blurb051) + fh.write(Blurb052) + fh.write(Blurb053) + fh.write(Blurb054) + fh.write(Blurb0541) + fh.write(Blurb0542) + fh.write(Blurb0543) + fh.write(Blurb055) + fh.write(Blurb056) + fh.write(Blurb057) + fh.write(Blurb058) + fh.write(Blurb059) + fh.write(Blurb060) + fh.write(Blurb061) + fh.write(Blurb062) + fh.write(Blurb063) + fh.write(Blurb064) + except IOError: + pass + else: + print("Phone book written") + print("The phone book will need to be edited to create your speed dial") + print("shortcuts and to map your local exchange. This is not absolutely") + print("necessary immediately, and sipproxy will still function regardless.") + fh.close() +################################################################## +def Logit(Blurb): + try: + fh = codecs.open(logfile, 'a', encoding='utf-8') + Blurb = Blurb.replace("\n","\\n") + Blurb = Blurb.replace("\r","\\r") + fh.write(Blurb) + fh.write("\n") + except IOError: + pass + else: + fh.close() + +################################################################## + +def ReadFoneBook(): + global BookList + try: + with codecs.open(phonebookfile, 'r', encoding='utf-8') as config: + for line in config: + if line[:1] != "#" and line.strip() != "": + BookList.append(line.strip()) + + except IOError: + pass + +################################################################## +print("\n\n\n\n\n\n") +print(" ____ ____") +print(" / ___) _ ____ | _ \\") +print("( (___ (_)| _ \| |_) )_ __ ___ __ ____ __") +print(" \__ \| || |_) | __/| '__/ _ \\\ \/ /\ \/ /") +print(" ___) | || __/| | | | ( (_) )> < \ / ") +print("(_____/|_||_| |_| |_| \___//_/\_\ /_/ ") +print("\n\n\n\n\n\n") +print("The all new and improved sipproxy running under Python " + (sys.version)) +print("Initialising " + __file__) +print("Looking for " + BaseDir + config) +if os.path.isfile(BaseDir + config): + result = ReadConfig() +else: + result = CreateConfig() + if os.path.isfile(phonebookfile): + print("Phone book already exists, not overwriting") + sys.exit(0) + else: + result = MkFoneBook() + sys.exit(0) + +if isip(ITSP) == False: + Destination = socket.gethostbyname(ITSP) + ITSP = Destination + print("ITSP = " + Destination) +else: + Destination = ITSP + +if os.path.isfile(phonebookfile): + result = ReadFoneBook() +else: + result = MkFoneBook() + +signal.signal(signal.SIGINT, signal_handler) +Time = time.strftime("%Y-%m-%d %H:%M:%S") +print(Time, "Everything started up") +Logit(Time + "Started up OK") +syslog.syslog("Everything started up") +reactor.listenUDP(5060, Sip()) +reactor.listenUDP(11110, OutRTP()) +reactor.listenUDP(11111, OutRTCP()) +reactor.run() +