2015-10-12 00:23:37 +00:00
#!/usr/bin/env python3
2013-03-24 20:11:03 +00:00
2017-03-20 13:06:01 +00:00
# Copyright (C) 2013-2017 Christian Thomas Jacobs.
2013-03-24 20:11:03 +00:00
# This file is part of PyQSO.
# PyQSO 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 3 of the License, or
# (at your option) any later version.
#
# PyQSO 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 PyQSO. If not, see <http://www.gnu.org/licenses/>.
import logging
2017-02-07 14:17:14 +00:00
try :
import http . client as http_client
except ImportError :
import httplib as http_client
2013-07-13 19:23:53 +00:00
from xml . dom import minidom
2017-07-06 22:09:56 +00:00
try :
from urllib . parse import quote
except ImportError :
from urllib import quote
2013-03-24 20:11:03 +00:00
2017-07-07 11:21:41 +00:00
from pyqso . auxiliary_dialogs import error
2013-08-03 19:11:00 +00:00
2016-01-27 16:23:09 +00:00
2017-02-21 14:54:04 +00:00
class CallsignLookupQRZ :
2016-01-27 16:23:09 +00:00
""" Use qrz.com to lookup details about a particular callsign. """
def __init__ ( self , parent ) :
""" Initialise a new callsign lookup handler.
: arg parent : The parent Gtk dialog .
"""
self . parent = parent
self . connection = None
self . session_key = None
return
def connect ( self , username , password ) :
""" Initiate a session with the qrz.com server. Hopefully this will provide a session key.
: arg str username : The username of the qrz . com user account .
: arg str password : The password of the qrz . com user account .
: returns : True if a successful connection was made to the server , and False otherwise .
: rtype : bool
"""
logging . debug ( " Connecting to the qrz.com server... " )
2017-07-06 22:09:56 +00:00
2017-07-06 22:14:28 +00:00
# Connect to the server.
2016-01-27 16:23:09 +00:00
try :
2017-07-06 20:05:36 +00:00
self . connection = http_client . HTTPConnection ( " xmldata.qrz.com " )
2017-07-07 11:21:41 +00:00
request = " /xml/current/?username= %s ;password= %s ;agent=pyqso " % ( username , quote ( password ) ) # Percent-escape the password in case there are reserved characters present.
2017-07-06 20:05:36 +00:00
self . connection . request ( " GET " , request )
2016-01-27 16:23:09 +00:00
response = self . connection . getresponse ( )
2017-07-07 11:21:41 +00:00
except Exception as e :
logging . exception ( e )
2016-01-27 16:23:09 +00:00
error ( parent = self . parent , message = " Could not connect to the qrz.com server. Check connection to the internets? " )
return False
2017-07-06 22:14:28 +00:00
# Get the session key.
2016-01-27 16:23:09 +00:00
xml_data = minidom . parseString ( response . read ( ) )
2017-07-06 20:23:27 +00:00
session_node = xml_data . getElementsByTagName ( " Session " ) [ 0 ] # There should only be one Session element.
2017-07-06 20:05:36 +00:00
session_key_node = session_node . getElementsByTagName ( " Key " )
2017-07-07 11:21:41 +00:00
if ( session_key_node ) :
2016-01-27 16:23:09 +00:00
self . session_key = session_key_node [ 0 ] . firstChild . nodeValue
2017-07-07 11:21:41 +00:00
logging . debug ( " Successfully connected to the qrz.com server. Session key is: %s . " % self . session_key )
2016-01-27 16:23:09 +00:00
connected = True
else :
connected = False
2017-07-06 20:23:27 +00:00
# If there are any errors or warnings, print them out.
2017-07-06 20:05:36 +00:00
session_error_node = session_node . getElementsByTagName ( " Error " )
2017-07-07 11:21:41 +00:00
if ( session_error_node ) :
2016-01-27 16:23:09 +00:00
session_error = session_error_node [ 0 ] . firstChild . nodeValue
2017-07-07 11:21:41 +00:00
error ( parent = self . parent , message = " qrz.com session error: %s " % session_error )
2016-01-27 16:23:09 +00:00
return connected
def lookup ( self , full_callsign , ignore_prefix_suffix = True ) :
""" Parse the XML tree that is returned from the qrz.com XML server to obtain the NAME, ADDRESS, STATE, COUNTRY, DXCC, CQZ, ITUZ, and IOTA field data (if present).
: arg str full_callsign : The callsign to look up ( without any prefix / suffix stripping ) .
: arg bool ignore_prefix_suffix : True if callsign prefixes / suffixes should be removed prior to querying the server , False otherwise .
: returns : The data in a dictionary called fields_and_data .
: rtype : dict
"""
2017-07-06 20:23:27 +00:00
logging . debug ( " Looking up callsign. The full callsign (with a prefix and/or suffix) is %s . " % full_callsign )
2016-01-27 16:23:09 +00:00
# Remove any prefix or suffix from the callsign before performing the lookup.
if ( ignore_prefix_suffix ) :
callsign = strip ( full_callsign )
else :
callsign = full_callsign
# Commence lookup.
fields_and_data = { " NAME " : " " , " ADDRESS " : " " , " STATE " : " " , " COUNTRY " : " " , " DXCC " : " " , " CQZ " : " " , " ITUZ " : " " , " IOTA " : " " }
if ( self . session_key ) :
2017-07-06 20:05:36 +00:00
request = " /xml/current/?s= %s ;callsign= %s " % ( self . session_key , callsign )
self . connection . request ( " GET " , request )
2016-01-27 16:23:09 +00:00
response = self . connection . getresponse ( )
xml_data = minidom . parseString ( response . read ( ) )
2017-07-06 20:05:36 +00:00
callsign_node = xml_data . getElementsByTagName ( " Callsign " )
2017-07-07 11:21:41 +00:00
if ( callsign_node ) :
2017-07-06 20:23:27 +00:00
callsign_node = callsign_node [ 0 ] # There should only be a maximum of one Callsign element.
2016-01-27 16:23:09 +00:00
2017-07-06 20:05:36 +00:00
callsign_fname_node = callsign_node . getElementsByTagName ( " fname " )
callsign_name_node = callsign_node . getElementsByTagName ( " name " )
2017-07-07 11:21:41 +00:00
if ( callsign_fname_node ) :
2016-01-27 16:23:09 +00:00
fields_and_data [ " NAME " ] = callsign_fname_node [ 0 ] . firstChild . nodeValue
2017-07-07 11:21:41 +00:00
if ( callsign_name_node ) : # Add the surname, if present.
2016-01-27 16:23:09 +00:00
fields_and_data [ " NAME " ] = fields_and_data [ " NAME " ] + " " + callsign_name_node [ 0 ] . firstChild . nodeValue
2017-07-06 20:05:36 +00:00
callsign_addr1_node = callsign_node . getElementsByTagName ( " addr1 " )
callsign_addr2_node = callsign_node . getElementsByTagName ( " addr2 " )
2017-07-07 11:21:41 +00:00
if ( callsign_addr1_node ) :
2016-01-27 16:23:09 +00:00
fields_and_data [ " ADDRESS " ] = callsign_addr1_node [ 0 ] . firstChild . nodeValue
2017-07-07 11:21:41 +00:00
if ( callsign_addr2_node ) : # Add the second line of the address, if present.
fields_and_data [ " ADDRESS " ] = ( fields_and_data [ " ADDRESS " ] + " , " if callsign_addr1_node else " " ) + callsign_addr2_node [ 0 ] . firstChild . nodeValue
2016-01-27 16:23:09 +00:00
2017-07-06 20:05:36 +00:00
callsign_state_node = callsign_node . getElementsByTagName ( " state " )
2017-07-07 11:21:41 +00:00
if ( callsign_state_node ) :
2016-01-27 16:23:09 +00:00
fields_and_data [ " STATE " ] = callsign_state_node [ 0 ] . firstChild . nodeValue
2017-07-06 20:05:36 +00:00
callsign_country_node = callsign_node . getElementsByTagName ( " country " )
2017-07-07 11:21:41 +00:00
if ( callsign_country_node ) :
2016-01-27 16:23:09 +00:00
fields_and_data [ " COUNTRY " ] = callsign_country_node [ 0 ] . firstChild . nodeValue
2017-07-06 20:05:36 +00:00
callsign_ccode_node = callsign_node . getElementsByTagName ( " ccode " )
2017-07-07 11:21:41 +00:00
if ( callsign_ccode_node ) :
2016-01-27 16:23:09 +00:00
fields_and_data [ " DXCC " ] = callsign_ccode_node [ 0 ] . firstChild . nodeValue
2017-07-06 20:05:36 +00:00
callsign_cqzone_node = callsign_node . getElementsByTagName ( " cqzone " )
2017-07-07 11:21:41 +00:00
if ( callsign_cqzone_node ) :
2016-01-27 16:23:09 +00:00
fields_and_data [ " CQZ " ] = callsign_cqzone_node [ 0 ] . firstChild . nodeValue
2017-07-06 20:05:36 +00:00
callsign_ituzone_node = callsign_node . getElementsByTagName ( " ituzone " )
2017-07-07 11:21:41 +00:00
if ( callsign_ituzone_node ) :
2016-01-27 16:23:09 +00:00
fields_and_data [ " ITUZ " ] = callsign_ituzone_node [ 0 ] . firstChild . nodeValue
2017-07-06 20:05:36 +00:00
callsign_iota_node = callsign_node . getElementsByTagName ( " iota " )
2017-07-07 11:21:41 +00:00
if ( callsign_iota_node ) :
2016-01-27 16:23:09 +00:00
fields_and_data [ " IOTA " ] = callsign_iota_node [ 0 ] . firstChild . nodeValue
else :
2017-07-06 20:23:27 +00:00
# If there is no Callsign element, then print out the error message in the Session element.
2017-07-06 20:05:36 +00:00
session_node = xml_data . getElementsByTagName ( " Session " )
2017-07-07 11:21:41 +00:00
if ( session_node ) :
2017-07-06 20:05:36 +00:00
session_error_node = session_node [ 0 ] . getElementsByTagName ( " Error " )
2017-07-07 11:21:41 +00:00
if ( session_error_node ) :
2016-01-27 16:23:09 +00:00
session_error = session_error_node [ 0 ] . firstChild . nodeValue
error ( parent = self . parent , message = session_error )
2017-07-06 20:23:27 +00:00
# Return empty strings for the field data.
2016-01-27 16:23:09 +00:00
logging . debug ( " Callsign lookup complete. Returning data... " )
return fields_and_data
2013-03-24 20:11:03 +00:00
2015-04-28 22:04:03 +00:00
2017-02-21 14:54:04 +00:00
class CallsignLookupHamQTH :
2016-01-27 16:23:09 +00:00
""" Use hamqth.com to lookup details about a particular callsign. """
def __init__ ( self , parent ) :
self . parent = parent
self . connection = None
self . session_id = None
return
def connect ( self , username , password ) :
""" Initiate a session with the hamqth.com server. Hopefully this will provide a session key.
: arg str username : The username of the hamqth . com user account .
: arg str password : The password of the hamqth . com user account .
: returns : True if a successful connection was made to the server , and False otherwise .
: rtype : bool
"""
logging . debug ( " Connecting to the hamqth.com server... " )
2017-07-06 22:09:56 +00:00
2017-07-06 22:14:28 +00:00
# Connect to the server.
2016-01-27 16:23:09 +00:00
try :
2017-07-06 20:05:36 +00:00
self . connection = http_client . HTTPSConnection ( " www.hamqth.com " )
2017-07-07 11:21:41 +00:00
request = " /xml.php?u= %s &p= %s " % ( username , quote ( password ) ) # Percent-escape the password in case there are reserved characters present.
2017-07-06 20:05:36 +00:00
self . connection . request ( " GET " , request )
2016-01-27 16:23:09 +00:00
response = self . connection . getresponse ( )
2017-07-07 11:21:41 +00:00
except Exception as e :
logging . exception ( e )
2016-01-27 16:23:09 +00:00
error ( parent = self . parent , message = " Could not connect to the hamqth.com server. Check connection to the internets? " )
return False
2017-07-06 22:14:28 +00:00
# Get the session ID.
2016-01-27 16:23:09 +00:00
xml_data = minidom . parseString ( response . read ( ) )
2017-07-06 20:23:27 +00:00
session_node = xml_data . getElementsByTagName ( " session " ) [ 0 ] # There should only be one Session element.
2017-07-06 20:05:36 +00:00
session_id_node = session_node . getElementsByTagName ( " session_id " )
2017-07-07 11:21:41 +00:00
if ( session_id_node ) :
2016-01-27 16:23:09 +00:00
self . session_id = session_id_node [ 0 ] . firstChild . nodeValue
2017-07-07 11:21:41 +00:00
logging . debug ( " Successfully connected to the hamqth.com server. Session ID is: %s . " % self . session_id )
2016-01-27 16:23:09 +00:00
connected = True
else :
connected = False
2017-07-06 20:23:27 +00:00
# If there are any errors or warnings, print them out.
2017-07-06 20:05:36 +00:00
session_error_node = session_node . getElementsByTagName ( " error " )
2017-07-07 11:21:41 +00:00
if ( session_error_node ) :
2016-01-27 16:23:09 +00:00
session_error = session_error_node [ 0 ] . firstChild . nodeValue
2017-07-07 11:21:41 +00:00
error ( parent = self . parent , message = " hamqth.com session error: %s " % session_error )
2016-01-27 16:23:09 +00:00
return connected
def lookup ( self , full_callsign , ignore_prefix_suffix = True ) :
""" Parse the XML tree that is returned from the hamqth.com XML server to obtain the NAME, ADDRESS, STATE, COUNTRY, DXCC, CQZ, ITUZ, and IOTA field data (if present),
: arg str full_callsign : The callsign to look up ( without any prefix / suffix stripping ) .
: arg bool ignore_prefix_suffix : True if callsign prefixes / suffixes should be removed prior to querying the server , False otherwise .
: returns : The data in a dictionary called fields_and_data .
: rtype : dict
"""
2017-07-06 20:23:27 +00:00
logging . debug ( " Looking up callsign. The full callsign (with a prefix and/or suffix) is %s . " % full_callsign )
2016-01-27 16:23:09 +00:00
# Remove any prefix or suffix from the callsign before performing the lookup.
if ( ignore_prefix_suffix ) :
callsign = strip ( full_callsign )
else :
callsign = full_callsign
# Commence lookup.
fields_and_data = { " NAME " : " " , " ADDRESS " : " " , " STATE " : " " , " COUNTRY " : " " , " DXCC " : " " , " CQZ " : " " , " ITUZ " : " " , " IOTA " : " " }
if ( self . session_id ) :
2017-07-06 20:05:36 +00:00
request = " /xml.php?id= %s &callsign= %s &prg=pyqso " % ( self . session_id , callsign )
self . connection . request ( " GET " , request )
2016-01-27 16:23:09 +00:00
response = self . connection . getresponse ( )
xml_data = minidom . parseString ( response . read ( ) )
2017-07-06 20:05:36 +00:00
search_node = xml_data . getElementsByTagName ( " search " )
2017-07-07 11:21:41 +00:00
if ( search_node ) :
2017-07-06 20:23:27 +00:00
search_node = search_node [ 0 ] # There should only be a maximum of one Callsign element.
2016-01-27 16:23:09 +00:00
2017-07-06 20:05:36 +00:00
search_name_node = search_node . getElementsByTagName ( " nick " )
2017-07-07 11:21:41 +00:00
if ( search_name_node ) :
2016-01-27 16:23:09 +00:00
fields_and_data [ " NAME " ] = search_name_node [ 0 ] . firstChild . nodeValue
2017-07-06 20:05:36 +00:00
search_addr1_node = search_node . getElementsByTagName ( " adr_street1 " )
search_addr2_node = search_node . getElementsByTagName ( " adr_street2 " )
2017-07-07 11:21:41 +00:00
if ( search_addr1_node ) :
2016-01-27 16:23:09 +00:00
fields_and_data [ " ADDRESS " ] = search_addr1_node [ 0 ] . firstChild . nodeValue
2017-07-07 11:21:41 +00:00
if ( search_addr2_node ) : # Add the second line of the address, if present.
fields_and_data [ " ADDRESS " ] = ( fields_and_data [ " ADDRESS " ] + " , " if search_addr1_node else " " ) + search_addr2_node [ 0 ] . firstChild . nodeValue
2016-01-27 16:23:09 +00:00
2017-07-06 20:05:36 +00:00
search_state_node = search_node . getElementsByTagName ( " us_state " )
2017-07-07 11:21:41 +00:00
if ( search_state_node ) :
2016-01-27 16:23:09 +00:00
fields_and_data [ " STATE " ] = search_state_node [ 0 ] . firstChild . nodeValue
2017-07-06 20:05:36 +00:00
search_country_node = search_node . getElementsByTagName ( " country " )
2017-07-07 11:21:41 +00:00
if ( search_country_node ) :
2016-01-27 16:23:09 +00:00
fields_and_data [ " COUNTRY " ] = search_country_node [ 0 ] . firstChild . nodeValue
2017-07-06 20:05:36 +00:00
search_cqzone_node = search_node . getElementsByTagName ( " cq " )
2017-07-07 11:21:41 +00:00
if ( search_cqzone_node ) :
2016-01-27 16:23:09 +00:00
fields_and_data [ " CQZ " ] = search_cqzone_node [ 0 ] . firstChild . nodeValue
2017-07-06 20:05:36 +00:00
search_ituzone_node = search_node . getElementsByTagName ( " itu " )
2017-07-07 11:21:41 +00:00
if ( search_ituzone_node ) :
2016-01-27 16:23:09 +00:00
fields_and_data [ " ITUZ " ] = search_ituzone_node [ 0 ] . firstChild . nodeValue
2017-07-06 20:23:27 +00:00
search_iota_node = search_node . getElementsByTagName ( " iota " )
2017-07-07 11:21:41 +00:00
if ( search_iota_node ) :
2016-01-27 16:23:09 +00:00
fields_and_data [ " IOTA " ] = search_iota_node [ 0 ] . firstChild . nodeValue
else :
2017-07-06 20:23:27 +00:00
# If there is no Callsign element, then print out the error message in the Session element.
2017-07-06 20:05:36 +00:00
session_node = xml_data . getElementsByTagName ( " session " )
2017-07-07 11:21:41 +00:00
if ( session_node ) :
2017-07-06 20:05:36 +00:00
session_error_node = session_node [ 0 ] . getElementsByTagName ( " error " )
2017-07-07 11:21:41 +00:00
if ( session_error_node ) :
2016-01-27 16:23:09 +00:00
session_error = session_error_node [ 0 ] . firstChild . nodeValue
error ( parent = self . parent , message = session_error )
2017-07-06 20:23:27 +00:00
# Return empty strings for the field data.
2017-07-07 11:21:41 +00:00
2016-01-27 16:23:09 +00:00
logging . debug ( " Callsign lookup complete. Returning data... " )
return fields_and_data
2015-04-28 22:04:03 +00:00
def strip ( full_callsign ) :
2016-01-27 16:23:09 +00:00
""" Remove any prefixes or suffixes from a callsign.
: arg str full_callsign : The callsign to be considered for prefix / suffix removal .
: returns : The callsign with prefixes / suffixes removed .
: rtype : str
"""
components = full_callsign . split ( " / " ) # We assume that prefixes or suffixes come before/after a forward slash character "/".
suffixes = [ " P " , " M " , " A " , " PM " , " MM " , " AM " , " QRP " ]
try :
if ( len ( components ) == 3 ) :
# We have both a prefix and a suffix.
2014-05-13 15:27:31 +00:00
callsign = components [ 1 ]
2016-01-27 16:23:09 +00:00
elif ( len ( components ) == 2 ) :
if ( components [ 1 ] . upper ( ) in suffixes or components [ 1 ] . lower ( ) in suffixes ) :
# If the last part of the full_callsign is a valid suffix, then use the part before that.
callsign = components [ 0 ]
2017-07-06 20:23:27 +00:00
logging . debug ( " Suffix %s found. Callsign to lookup is %s . " % ( components [ 1 ] , callsign ) )
2016-01-27 16:23:09 +00:00
else :
# We have a prefix, so take the part after the first "/".
callsign = components [ 1 ]
2017-07-06 20:23:27 +00:00
logging . debug ( " Prefix %s found. Callsign to lookup is %s . " % ( components [ 0 ] , callsign ) )
2016-01-27 16:23:09 +00:00
elif ( len ( components ) == 1 ) :
# We have neither a prefix nor a suffix, so use the full_callsign.
callsign = full_callsign
2017-07-06 20:23:27 +00:00
logging . debug ( " No prefix or suffix found. Callsign to lookup is %s . " % callsign )
2016-01-27 16:23:09 +00:00
else :
raise ValueError
except ValueError :
callsign = full_callsign
return callsign