def proc_spot_mode(inmode): # valid modes modes = ["am", "cw", "data", "dv", "fm", "psk", "rtty", "ssb", "other"] valid = False mode = inmode.replace('\n', '') # check mode is valid string for validmode in range(len(modes)): if mode == modes[validmode]: valid = True break # mode is invalid, set it to other if valid == False: tstr = 'mode not valid ' + mode + ' using other instead' print(tstr) smslog.log(tstr) mode = 'other' return mode
def proc_spot_SOTA_summit(tsummit): # only want 1st 2 chars for SOTA summit = tsummit[0:2] # if no - in the original then add one if tsummit[2:3] != '-': summit += '-' summit += tsummit[2:] else: summit = tsummit # check summit is right length if len(summit) != 6: tstr = 'SOTA summit len not 6 ' + summit + ' ' + tsummit smslog.log(tstr) print(tstr) return None return summit
def proc_spot_freq(freq): # check we have a . or a : or a , in the string dotpos = freq.find('.') colpos = freq.find(':') commapos = freq.find(',') if dotpos == -1 and colpos == -1 and commapos == -1: tstr = 'no . or : or , in freq ' + freq smslog.log(tstr) print(tstr) return None if colpos != -1: dotpos = colpos freq = freq.replace(':', '.') tstr = 'replaced : with .' smslog.log(tstr) print(tstr) if commapos != -1: dotpos = commapos freq = freq.replace(',', '.') tstr = 'replaced , with .' smslog.log(tstr) print(tstr) # check digits before . if freq[0:dotpos].isdigit() == False: tstr = 'before . is not digit ' + freq print(tstr) smslog.log(tstr) return None #check digits after . if freq[dotpos + 1:].isdigit() == False: tstr = 'after . is not digit ' + freq print(tstr) smslog.log(tstr) return None # if here freq looks ok return freq
def postwotaspot(param, spot, nowota): wotaparam = {} wotaparam['posted_by'] = 'mm0fmf' summit = param['summit'].split('-') if summit[0].find('LDW') != -1: wotaparam['summit'] = summit[1] else: wotaparam['summit'] = str(int(summit[1]) + 214) wotaparam['call'] = param['actCallsign'] wotaparam['freqmode'] = param['freq'] + '+' + param['mode'] wotaparam['comment'] = param['comments'] # dont post if the nopost flag is set if nowota == True: partial_spotdata = urllib.parse.urlencode(wotaparam) print('**NOT** Posting a spot with: ') print(partial_spotdata) smslog.log(partial_spotdata) smslog.log('WOTA: posting disabled with nowota') retval = 303 return retval if spot == True: spotdata = urllib.parse.urlencode(wotaparam) print('Posting a spot with: ') print(spotdata) smslog.log(spotdata) retval = 200 try: smslog.log('WOTA: connect') if wota_connect() == False: tstr = "Cannot connect to wota.org.uk:80\n" print(tstr) smslog.log('WOTA: ' + tstr) retval = 404 return retval smslog.log('WOTA: login') if wota_login("mm0fmf", "earlgrey100") == False: tstr = "Cannot login to wota.org.uk:80\n" print(tstr) smslog.log('WOTA: ' + tstr) retval = 404 return retval #print "wotaconn.request..." # wotaconn.request("POST", "/index.php?page=mm_home/mm_sendspot.html", spotdata, wotahttpheaders) wotaconn.request("POST", "/index.php?page=mm_home/mm_sendspotnoaprs.html", spotdata, wotahttpheaders) #print "wotaconn.getresponse..." r1 = wotaconn.getresponse() #print "wotaconn.close..." wotaconn.close() #print "done" #print r1.status, r1.reason if r1.status == 200: #smslog.log( 'WOTA: '+str(r1.status) + ' is good') smslog.log('WOTA: {0:d} is good'.format(r1.status)) return 200 except IOError: print('HTTP IOError exception with www.wota.org.uk:80\n') smslog.log('WOTA: IOError, spot deleted') # not a spot, it's an alert and we support them yet else: print('Alerting with: ' + 'NOT YET') return retval
def postspot(param, nopost, api, spottingcall): spotdata = spotlite2api2(param) # dont post if the nopost flag is set if nopost == True: print('**NOT** Posting a spot with: ') print(spotdata) smslog.log(json.dumps(spotdata)) smslog.log('SPOTLITE: posting disabled with nospot') thing = {} thing['statusCode'] = 0 posted_spots[random.randint(1, 9999999)] = spotdata print("delete spot backtrace dictionary has " + str(len(posted_spots)) + " entries") print(posted_spots) return True, thing print('Posting a spot with: ') print(spotdata) smslog.log(json.dumps(spotdata)) msg = "\nclient=sms&user="******"\n" smslog.log(msg) status, reply = api.postspot(spotdata, spottingcall) if status == False: msg = "api2 call failed" print(msg) smslog.log(msg + "\n") return status, reply posted_spots[reply['id']] = spotdata print("delete spot backtrace dictionary has " + str(len(posted_spots)) + " entries") msg = "api2 liked the spot" print(msg) smslog.log(msg + "\n") return status, reply
def deletespot(param, nopost, api, spottingcall): spotdata = spotlite2api2(param) foundkey = False # dont post if the nopost flag is set if nopost == True: print('**NOT** Deleting a spot with: ') for key, value in posted_spots.items(): oldspot = dict(value) if oldspot == spotdata: del posted_spots[key] print("delete spot backtrace dictionary has " + str(len(posted_spots)) + " entries") message = ''.join("Deleted spot: " + str(key)) print(message) print(spotdata) smslog.log(message) smslog.log(json.dumps(spotdata)) foundkey = True break if foundkey == False: message = "No matching spot found" print(message) smslog.log(message + "\n") thing = {} thing['statusCode'] = 0 return True, thing print('deleting a spot with: ') for key, value in posted_spots.items(): oldspot = dict(value) if oldspot == spotdata: foundkey = True status, reply = api.deletespot(key) if status == False: print("api2 call failed") smslog.log("api2 call failed") return status, reply if reply['statusCode'] == 0: print("api2 liked the delete") smslog.log("api2 liked the delete") del posted_spots[key] print("delete spot backtrace dictionary has " + str(len(posted_spots)) + " entries") message = ''.join("Deleted spot: " + str(key)) print(message) print(spotdata) smslog.log(message) smslog.log(json.dumps(spotdata)) return status, reply else: print("api2 did not like the delete") smslog.log("api2 did not like the delete") return status, reply if foundkey == False: message = "No matching spot found" print(message) smslog.log(message + "\n") return False, None
def posthumpspot(param, spot, nopost): summitReference = "" summitReference = param['assoc'] summitReference = summitReference + '/' summitReference = summitReference + param['summit'] summitReference = summitReference.upper() spotparams = {'submitSpotButton': 'Submit spot'} spotparams['activationCallsign'] = param['actCallsign'] spotparams['summitReference'] = summitReference spotparams['frequency'] = param['freq'] spotparams['mode'] = param['mode'] spotparams['comments'] = param['comments'] encspotparams = urllib.parse.urlencode(spotparams) httpheaders = { "Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain", "User-Agent": "humps-spotter-mm0fmf/0.1" } if nopost == True: print('**NOT** Posting a hump spot with: ') print(encspotparams) smslog.log(encspotparams) smslog.log('HUMPS: posting disabled with nohump') retval = 303 return retval retval = 200 try: conn = http.client.HTTPConnection("www.summitswatch.org.uk") conn.request("GET", "/sb/login.php") r1 = conn.getresponse() #print r1.status, r1.reason if r1.status != 200: return 200 headers = r1.getheaders() for header in headers: if header[0] == 'set-cookie': cookie = header[1].split(';') #print cookie[0] httpheaders['Cookie'] = cookie[0] body = r1.read() #print loginparams #print httpheaders loginparams = { 'submitted': 'TRUE', 'submit': 'Login', } loginparams['email'] = '*****@*****.**' loginparams['pass'] = '******' encparams = urllib.parse.urlencode(loginparams) conn.request("POST", "/sb/login.php", encparams, httpheaders) r1 = conn.getresponse() body = r1.read() if r1.status != 302: conn.close() return 200 print('posting a hump spot with:') print(encspotparams) smslog.log(encspotparams) conn.request("POST", "/sb/submitSpot.php", encspotparams, httpheaders) r1 = conn.getresponse() body = r1.read() #print r1.status, r1.reason #smslog.log( 'HUMPS: '+str(r1.status) ) smslog.log('HUMPS: {0:d}'.format(r1.status)) if r1.status == 302: conn.close() return 303 except IOError: print('HTTP exception with www.summitswatch.org.uk:80\n') smslog.log('HUMPS: IOError, spot deleted') return 200
def postspotlite(param, spot, nopost, spotter): # dont post if the nopost flag is set if nopost == True: headers = { "Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain" } partial_spotdata = urllib.parse.urlencode(param) print('**NOT** Posting a spot with: ') print(partial_spotdata) smslog.log(partial_spotdata) smslog.log('SPOTLITE: posting disabled with nospot') retval = 303 return retval if spot == True: headers = { "Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain" } partial_spotdata = urllib.parse.urlencode(param) print('Posting a spot with: ') print(partial_spotdata) smslog.log(partial_spotdata) if spotter == 'VK': #'SMS_AUS': param['callsign'] = 'SMS_AUS' param['password'] = '******' elif spotter == 'GB': #'SMS': param['callsign'] = 'SMS' param['password'] = '******' elif spotter == 'SAT': #'Iridium': param['callsign'] = 'Iridium' param['password'] = '******' elif spotter == 'NA': #'SMS_NA': param['callsign'] = 'SMS_NA' param['password'] = '******' elif spotter == 'OE': #'SMS_OE': param['callsign'] = 'SMS_OE' param['password'] = '******' param['submit'] = 'SPOT!' spotdata = urllib.parse.urlencode(param) retval = 200 try: # conn = http.client.HTTPConnection("www.sota.org.uk:80") conn = http.client.HTTPConnection("old.sota.org.uk:80") conn.request("POST", "/Spotlite/postSpot", spotdata, headers) response = conn.getresponse() data = response.read() conn.close() #smslog.log( 'SPOTLITE: '+str(response.status) + '\n' + data) smslog.log('SPOTLITE: {0:d}\n{1}'.format(response.status, data.decode('utf-8'))) retval = response.status except IOError: # print('HTTP IOError exception with www.sota.org.uk:80\n') print('HTTP IOError exception with old.sota.org.uk:80\n') smslog.log('SPOTLITE: IOError, spot deleted') # not a spot, it's an alert and we support them yet else: print('Alerting with: ' + 'NOT YET') return retval
def uk_localise(callsign, assoc): assocs = ['GM', 'GW', 'GI', 'GD', 'G'] region = ['M', 'W', 'I', 'D', 'E'] clubregion = ['S', 'C', 'N', 'T', 'X'] bclub = False bgcall = False b2call = False # IL call? if callsign[0:1] == '2': b2call = True # G or M call? elif callsign[0:1] == 'G' or callsign[0:1] == 'M': bgcall = True else: # this is not a UK callsign return callsign for clubsecondary in clubregion: if clubsecondary == callsign[1:2]: bclub = True print('Club call') clubindex = clubregion.index(clubsecondary) break # check if uk call in uk region for tassoc in assocs: if tassoc == assoc: # we are in a localisable region index = assocs.index(tassoc) # copy 1st char localised = callsign[0:1] if bclub == True: #print 'uk club callsign in ',tassoc # club call, 2nd char is clubregion localised += clubregion[index] # club call always has a secondary locator # so rest of call starts at 2: not 1: localised += callsign[2:] else: # england has no secondary locator if index == 4: # IL call? if b2call == True: #print 'uk IL callsign in ',tassoc # but england does have secondary if IL call localised += region[index] # IL call always has a secondary locator # so rest of call starts at 2: localised += callsign[2:] else: #print 'uk callsign in ',tassoc # english call in england if callsign[1:2].isdigit() == True: # just copy whats left localised += callsign[1:] else: # uk regional, number starts at 2: localised += callsign[2:] else: # in a region with secondary localised += region[index] # english call in england if callsign[1:2].isdigit() == True: # just copy whats left localised += callsign[1:] else: # uk regional, number starts at 2: localised += callsign[2:] break else: #print 'uk callsign but not in ',tassoc localised = callsign smslog.log('callsign: ' + callsign + ' assoc: ' + assoc + ' localised: ' + localised) return localised
def parse_SOTA_spot(message, spottercall, isAPI2, spotsource): message.strip() pepperspot = message.find('-DS09a)') if pepperspot != -1: pepperspot = pepperspot * -1 message = message[1:-pepperspot] pepperspot = message.find('-DS1f)') if pepperspot != -1: pepperspot = pepperspot * -1 message = message[1:-pepperspot] if spottercall == 'MM0FMF': pepperspot = message.find('via DroidSpot') if pepperspot != -1: pepperspot = pepperspot * -1 message = message[0:-pepperspot] print('DroidSpot removed:\n' + message) pepperspot = message.find('#DroidSpot') if pepperspot != -1: pepperspot = pepperspot * -1 message = message[0:-pepperspot] print('DroidSpot removed:\n' + message) fields = message.split(' ') # user may have entered multiple spaces, use list comprehension to remove any # null entries in the list of keywords after we split on space fields = [i for i in fields if i != ''] # create dict with all bad entries spot = allbadspot() # check we have at least 6 fields of data # well we should have 6 fields but we dont need a comment field # so we accept 5 if len(fields) < NUM_SOTA_FIELDS - 1: #tstr = 'Bad format: only '+str(len(fields))+' fields in message' tstr = 'Bad format: only {0:d} fields in message'.format(len(fields)) smslog.log(tstr) spot['actCallsign'] = spottercall smslog.badspot(spot, 'data') print(tstr) return None # create some vars (because we are a C programmer at heart) callsign = '' assoc = '' summit = '' freq = '' mode = '' comment = '' isfullcall = False status = False # cleanup call, add /p etc. callsign, isfullcall, eraseme = proc_spot_callsign( fields[sota_CALL].upper(), spottercall) # extract association assoc = fields[sota_ASSOC].upper() if isfullcall == False: # uk regionalise the callsign callsign = uk_localise(callsign, assoc) # fill in dict with parsed data spot['actCallsign'] = callsign spot['assoc'] = assoc # extract summit and check is SOTA format summit = proc_spot_SOTA_summit(fields[sota_REF].upper()) if summit == None: # log it for status smslog.badspot(spot, 'summit') return False, None, False # fill in dict with parsed data spot['summit'] = summit # extract freq freq = proc_spot_freq(fields[sota_FREQ].upper()) # if freq is bogus, fail now if freq == None: smslog.badspot(spot, 'freq') return False, None, False # fill in dict with parsed data spot['freq'] = freq # extract mode and cleanup mode = proc_spot_mode(fields[sota_MODE].lower()) # build comment if isAPI2 == True: comment = proc_spot_api2comment(spottercall, fields, sota_COMMENT, spotsource) else: comment = proc_spot_comment(spottercall, fields, sota_COMMENT) # finally assemble all components into a spot string # spot = {} # spot[ 'actCallsign' ] = callsign # spot[ 'assoc' ] = assoc # spot[ 'summit' ] = summit # spot[ 'freq' ] = freq spot['mode'] = mode spot['comments'] = comment return True, spot, eraseme
def processloop(sender, msg, nospot, spotsource, sotapi2): #isAPI2 = False isAPI2 = True callsign, features = usercheck.find(sender) if len(msg) == 0: print('Bad format, no data!') smslog.log('Bad message format, no data') return fstr = 'SOTA' if callsign != '': # yes, the user is registered print('Found: ', callsign) if features & 1: fstr += '+Hump' if features & 2: fstr += '+WOTA' print('Features:', fstr) print('Message: ', msg) else: index1 = msg.find('dlor.me/') index2 = msg.find('inr.ch') index3 = msg.find('garmin.com') # not Delorme Inreach if index1 == -1 and index2 == -1 and index3 == -1: # unknown sender smslog.log('Unknown sender: ' + sender) # skip the processing return # we have a Delorme Inreach message, find the user delorme = 1 if index1 != -1: delorme = index1 if index2 != -1: delorme = index2 if index3 != -1: delorme = index3 # we have a Delorme Inreach message, find the user delormemsg = msg[delorme:] if delormemsg.find(' - ') == -1: # delorme message looks buggered smslog.log('Delorme InReach message looks corrupt\n') smslog.log(msg) # skip further processing return delormefields = delormemsg.split(' - ') sender = delormefields[1].strip() callsign, features = usercheck.find(sender) if callsign == '': # unknown delorme user smslog.log('Unknown Delorme InReach sender: ' + sender) # skip further processing return else: # trim Delorme trash off our spot message msg = msg[:delorme] # check extra features support if features & 1: fstr += '+Hump' if features & 2: fstr += '+WOTA' print('(Delorme) Found: ' + callsign) print('(Delorme) Features:', fstr) print('(Delorme) Message: ', msg) # overide default spotsource as all Delorme message are from Iridium spotsource = 'Iridium' # by now we have a valid SMS or Delorm user identified formatvalid = False print("processing message: ") status, httpspot, eraseme = parsemsg.parse_SOTA_spot( msg, callsign, isAPI2, spotsource) # check we got some data if status == False: # log bum data and do next smslog.log('Invalid message: ' + msg) # data seems good else: # handle spots if isAPI2 == False and eraseme == False: # post spot, log results httpresp = http_sota.postspotlite(httpspot, True, nospot, spotsource) # log badness if spot failed if httpresp == 200: smslog.log('Spotlite does not like the message') else: if eraseme == True: # post spot using API2 status, httpresp = api_sota.deletespot(httpspot, nospot, sotapi2, callsign) else: # post spot using API2 status, httpresp = api_sota.postspot(httpspot, nospot, sotapi2, callsign) # log badness if spot failed if status == False: smslog.log('Posting/deleting the spot failed, api fail') else: smslog.log('api2 likes the message') return