kopia lustrzana https://github.com/craigerl/digipi
334 wiersze
11 KiB
Python
Executable File
334 wiersze
11 KiB
Python
Executable File
#!/usr/bin/python
|
|
# m k s y s o p . p y
|
|
# $Revision: 165 $
|
|
# $Author: eckertb $
|
|
# $Id: mksysop.py 165 2014-06-05 11:28:26Z eckertb $
|
|
#
|
|
# Description:
|
|
# RMS Gateway - generate sysop XML file to maintain
|
|
# the sysop record in the winlink system
|
|
#
|
|
# RMS Gateway
|
|
#
|
|
# Copyright (c) 2004-2013 Hans-J. Barthen - DL5DI
|
|
# Copyright (c) 2008-2013 Brian R. Eckert - W3SG
|
|
#
|
|
# Questions or problems regarding this program can be emailed
|
|
# to linux-rmsgw@w3sg.org
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
#
|
|
#
|
|
|
|
import os
|
|
import sys
|
|
import re
|
|
import requests
|
|
import json
|
|
import platform
|
|
from xml.etree import ElementTree
|
|
from optparse import OptionParser
|
|
from distutils.version import LooseVersion
|
|
|
|
#################################
|
|
# BEGIN CONFIGURATION SECTION
|
|
#################################
|
|
|
|
gateway_config = '/etc/rmsgw/gateway.conf'
|
|
service_config_xml = '/etc/rmsgw/winlinkservice.xml'
|
|
channel_config_xml = '/etc/rmsgw/channels.xml'
|
|
version_info = '/etc/rmsgw/.version_info'
|
|
sysop_template_xml = '/etc/rmsgw/sysop-template.xml'
|
|
sysop_config_xml = '/etc/rmsgw/sysop.xml'
|
|
|
|
new_sysop_config_xml = 'new-sysop.xml'
|
|
|
|
py_version_require='2.7.9'
|
|
|
|
#################################
|
|
# END CONFIGURATION SECTION
|
|
#################################
|
|
|
|
### Local Functions #############
|
|
|
|
def NotFoundHelp():
|
|
print '*' * 75
|
|
print 'If you need to create your initial sysop record,'
|
|
print 'copy', sysop_template_xml, 'to', sysop_config_xml
|
|
print 'and enter the appropriate text within each of the'
|
|
print 'sysop element tags.'
|
|
print '*' * 75
|
|
|
|
#################################
|
|
|
|
cmdlineparser = OptionParser()
|
|
cmdlineparser.add_option("-d", "--debug",
|
|
action="store_true", dest="DEBUG", default=False,
|
|
help="turn on debug output")
|
|
cmdlineparser.add_option("-c", "--callsign",
|
|
action="store", metavar="CALLSIGN",
|
|
dest="callsign", default=None,
|
|
help="use a specific callsign")
|
|
(options, args) = cmdlineparser.parse_args()
|
|
|
|
#
|
|
# dictionaries for config info
|
|
#
|
|
rms_chans = {}
|
|
gw_config = {}
|
|
ws_config = {}
|
|
svc_calls = {}
|
|
version = {}
|
|
param_roots = {}
|
|
|
|
#
|
|
# Check running as root
|
|
#
|
|
if os.geteuid() != 0:
|
|
print("Must be root, exiting ...")
|
|
sys.exit(1)
|
|
|
|
#
|
|
# check python version
|
|
#
|
|
python_version=platform.python_version()
|
|
|
|
# This does not work with release candidates (Python 2.7.15rc1)
|
|
# if StrictVersion(python_version) >= StrictVersion(py_version_require):
|
|
# if parse_version(python_version) >= parse_version(py_version_require):
|
|
|
|
if LooseVersion(python_version) >= LooseVersion(py_version_require):
|
|
if options.DEBUG: print('Python Version Check: ' + str(python_version) + ' OK')
|
|
else:
|
|
print('Need more current Python version than: ' + str(python_version) + ' require version: ' + str(py_version_require) + ' or newer')
|
|
print('Exiting ...')
|
|
sys.exit(1)
|
|
|
|
#
|
|
# load gateway config
|
|
#
|
|
with open(gateway_config) as gwfile:
|
|
for line in gwfile:
|
|
if not line.strip().startswith('#'):
|
|
name, val = line.partition("=")[::2]
|
|
gw_config[name.strip()] = val.strip()
|
|
gwfile.close()
|
|
|
|
if options.DEBUG: print('Gateway config =', gw_config)
|
|
|
|
#
|
|
# load version info
|
|
#
|
|
with open(version_info) as versionfile:
|
|
for line in versionfile:
|
|
if not line.strip().startswith('#'):
|
|
name, val = line.partition("=")[::2]
|
|
version[name.strip()] = val.strip()
|
|
versionfile.close()
|
|
|
|
if options.DEBUG: print('version_program = {}'.format(version['PROGRAM']))
|
|
|
|
#
|
|
# load service config from XML
|
|
#
|
|
winlink_service = ElementTree.parse(service_config_xml)
|
|
winlink_config = winlink_service.getroot()
|
|
|
|
for svc_config in winlink_config.iter('config'):
|
|
# basic configuration data
|
|
ws_config['WebServiceAccessCode'] = svc_config.find('WebServiceAccessCode').text
|
|
ws_config['svchost'] = svc_config.find('svchost').text
|
|
ws_config['svcport'] = svc_config.find('svcport').text
|
|
ws_config['namespace'] = svc_config.find('namespace').text
|
|
|
|
# for the service operations, the tags are the operations,
|
|
# element text is the service call detail
|
|
for svc_ops in svc_config.findall('svcops'):
|
|
for svc_call in svc_ops:
|
|
svc_calls[svc_call.tag] = svc_call.text
|
|
param_roots[svc_call.tag] = svc_call.attrib['paramRoot']
|
|
|
|
#
|
|
# load channel config from XML - need password
|
|
#
|
|
|
|
document = ElementTree.parse(channel_config_xml)
|
|
rmschannels = document.getroot()
|
|
|
|
ns = '{http://www.namespace.org}'
|
|
for channel in rmschannels.findall("%schannel" % (ns)):
|
|
# if options.DEBUG: print('channel xml = {}'.format(ElementTree.tostring(channel)))
|
|
|
|
callsign = channel.find("%scallsign" % (ns)).text
|
|
rms_chans['callsign'] = callsign
|
|
|
|
password = channel.find("%spassword" % (ns)).text
|
|
rms_chans['password'] = password
|
|
|
|
if options.DEBUG: print('ws_config =', ws_config)
|
|
if options.DEBUG: print('svc_calls =', svc_calls)
|
|
if options.DEBUG: print('param_roots =', param_roots)
|
|
|
|
#
|
|
# need a callsign to try to get things setup
|
|
#
|
|
# if there is existing sysop info stored in
|
|
# the winlink system, we'll grab that and create
|
|
# the initial local XML file of values so that
|
|
# it can be easily maintained and updated going
|
|
# forward
|
|
#
|
|
if options.callsign == None: # no callsign given on cmd line?
|
|
#
|
|
# first check for gateway callsign and extract
|
|
# the basecall
|
|
#
|
|
if 'GWCALL' in gw_config:
|
|
options.callsign = gw_config['GWCALL'].split('-', 1)[0] # first item of list
|
|
else:
|
|
# ask for callsign if none given on command line
|
|
# and none in the gateway config
|
|
options.callsign = raw_input('Enter gateway callsign (without SSID): ')
|
|
|
|
options.callsign = options.callsign.upper()
|
|
|
|
if options.DEBUG: print('callsign =', options.callsign)
|
|
|
|
#
|
|
# prepare and make webservice call
|
|
#
|
|
headers = {'Content-Type': 'application/xml'}
|
|
|
|
# Old winlink services url format
|
|
# svc_url = 'http://' + ws_config['svchost'] + ':' + ws_config['svcport'] + svc_calls['sysopget']
|
|
#svc_url = 'https://' + ws_config['svchost'] + svc_calls['sysop2get'] + '?' + 'Callsign=' + format(options.callsign) + '&Program=' + format(version['PROGRAM']) + '&Password=' + format(rms_chans['password']) + '&Key=' + format(ws_config['WebServiceAccessCode'] + '&format=json')
|
|
svc_url = 'https://' + ws_config['svchost'] + svc_calls['sysop2get'] + '?' + 'Callsign=' + format(options.callsign) + '&Program=' + format(version['PROGRAM']) + '&Password=' + format(rms_chans['password']) + '&Key=' + format(ws_config['WebServiceAccessCode'] + '&format=json')
|
|
|
|
if options.DEBUG: print 'svc_url =', svc_url
|
|
|
|
#
|
|
# prepare xml parameters for call
|
|
#
|
|
sysop_get = ElementTree.Element(param_roots['sysop2get'])
|
|
sysop_get.set('xmlns:i', 'http://www.w3.org/2001/XMLSchema-instance')
|
|
sysop_get.set('xmlns', ws_config['namespace'])
|
|
|
|
child = ElementTree.SubElement(sysop_get, 'Key')
|
|
child.text = ws_config['WebServiceAccessCode']
|
|
|
|
child = ElementTree.SubElement(sysop_get, 'Callsign')
|
|
child.text = options.callsign
|
|
|
|
if options.DEBUG: print('sysop_get XML =', ElementTree.tostring(sysop_get))
|
|
|
|
# Post the request
|
|
try:
|
|
response = requests.post(svc_url, data=ElementTree.tostring(sysop_get), headers=headers)
|
|
except requests.ConnectionError as e:
|
|
print("Error: Internet connection failure:")
|
|
print('svc_url = ', svc_url)
|
|
print(e)
|
|
sys.exit(1)
|
|
|
|
if options.DEBUG: print 'Response =', response.content
|
|
|
|
# we'll load the returned xml into this dictionary
|
|
return_data = {}
|
|
|
|
json_data = response.json()
|
|
if options.DEBUG: print((json.dumps(json_data, indent=2)))
|
|
json_dict = json.loads(response.text)
|
|
|
|
# print the return code of this request, should be 200 which is "OK"
|
|
if options.DEBUG: print("Request status code:" + str(response.status_code))
|
|
|
|
#
|
|
# Verify request status code"
|
|
#
|
|
if response.ok:
|
|
if options.DEBUG: print("Debug: Good Request status code")
|
|
else:
|
|
print('*** Get for', options.callsign, 'failed, ErrorCode =', str(response.status_code))
|
|
print('*** Error code: ' + json_dict['ResponseStatus']['ErrorCode'])
|
|
print('*** Error message: ' + json_dict['ResponseStatus']['Message'])
|
|
# sys.exit(1)
|
|
|
|
#
|
|
# check for errors coming back
|
|
#
|
|
if json_dict['ResponseStatus']:
|
|
print('ResponseStatus not NULL: ', json_dict['ResponseStatus'])
|
|
sys.exit(1)
|
|
else:
|
|
if options.DEBUG: print(('ResponseStatus is NULL: ', json_dict['ResponseStatus']))
|
|
|
|
|
|
#
|
|
# build xml element tree from json response while
|
|
#
|
|
|
|
#
|
|
# check that we got something useful back
|
|
#
|
|
returned_callsign=json_dict['Sysop']['Callsign']
|
|
|
|
if not returned_callsign or not returned_callsign.strip():
|
|
print('*** No record found for', options.callsign)
|
|
sys.exit(2)
|
|
|
|
#
|
|
# load the sysop XML doc (this is an unpopulated template
|
|
# for our purposes here)
|
|
#
|
|
if not os.path.isfile(sysop_template_xml):
|
|
print("File: " + sysop_template_xml + " does not exist")
|
|
sys.exit(2)
|
|
|
|
document = ElementTree.parse(sysop_template_xml)
|
|
sysops = document.getroot()
|
|
|
|
#
|
|
# update the XML document with the values returned from
|
|
# our webservice call...
|
|
#
|
|
for sysop in sysops.findall('sysop'):
|
|
sysop.find('Callsign').text = returned_callsign
|
|
sysop.find('Password').text = rms_chans['password']
|
|
sysop.find('GridSquare').text = json_dict['Sysop']['GridSquare']
|
|
sysop.find('SysopName').text = json_dict['Sysop']['SysopName']
|
|
sysop.find('StreetAddress1').text = json_dict['Sysop']['StreetAddress1']
|
|
sysop.find('StreetAddress2').text = json_dict['Sysop']['StreetAddress2']
|
|
sysop.find('City').text = json_dict['Sysop']['City']
|
|
sysop.find('State').text = json_dict['Sysop']['State']
|
|
sysop.find('Country').text = json_dict['Sysop']['Country']
|
|
sysop.find('PostalCode').text = json_dict['Sysop']['PostalCode']
|
|
sysop.find('Email').text = json_dict['Sysop']['Email']
|
|
sysop.find('Phones').text = json_dict['Sysop']['Phones']
|
|
sysop.find('Website').text = json_dict['Sysop']['Website']
|
|
sysop.find('Comments').text = json_dict['Sysop']['Comments']
|
|
|
|
#
|
|
# ... and write the updated document to a new XML file
|
|
# for the sysop to inspect and move into place
|
|
# as appropriate
|
|
document.write(new_sysop_config_xml)
|
|
|
|
print 'New sysop XML data written to', new_sysop_config_xml
|
|
print 'Please inspect the results and copy to', sysop_config_xml
|
|
print 'if it is correct.'
|
|
|
|
sys.exit(0)
|
|
|