Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJack Zielke <kg4gjy@takeovertheworld.org>2009-05-26 05:15:52 (GMT)
committer Jack Zielke <kg4gjy@takeovertheworld.org>2009-05-26 05:15:52 (GMT)
commit9d5629af4687c6c8d08ccdb961c21573b74b82a6 (patch)
tree5470cb2568e355e778ba4d9917fdc1cec11eecc4
parent22fed72ecf4d7d2d37003bc998227783c4051775 (diff)
version 4 - no journal, no message queue, gui update
-rw-r--r--NEWS1
-rw-r--r--activity/activity.info2
-rwxr-xr-xaprs.py428
3 files changed, 290 insertions, 141 deletions
diff --git a/NEWS b/NEWS
index 3d71ce4..c64a9df 100644
--- a/NEWS
+++ b/NEWS
@@ -2,3 +2,4 @@ September 14 2008 - version 0 started
September 20 2008 - version 1 - no journal, no messaging
September 22 2008 - version 2 - no journal, can not send messages, gui update
September 25 2008 - version 3 - no journal, can not send messages, gui update
+September 28 2008 - version 4 - no journal, no message queue, gui update
diff --git a/activity/activity.info b/activity/activity.info
index 413fc49..7c99a2c 100644
--- a/activity/activity.info
+++ b/activity/activity.info
@@ -1,6 +1,6 @@
[Activity]
name = APRS-XO
-activity_version= 3
+activity_version= 4
service_name = org.laptop.APRSXO
icon = activity-aprs-xo
exec = sugar-activity aprs.APRSActivity
diff --git a/aprs.py b/aprs.py
index 37749fc..f60ad04 100755
--- a/aprs.py
+++ b/aprs.py
@@ -1,3 +1,4 @@
+# -*- coding: UTF-8 -*-
# Copyright (C) 2008, Jack Zielke <jack@linuxcoffee.com>
# Copyright (C) 2008, One Laptop Per Child
#
@@ -38,6 +39,7 @@ PORT = 14580
RECV_BUFFER = 4096
MAXLINES = 50
+MAXRETRIES = 15
bundle = ActivityBundle(activity.get_bundle_path())
VERSION = bundle.get_activity_version()
@@ -46,19 +48,19 @@ del bundle
class APRSActivity(activity.Activity):
def __init__(self, handle):
activity.Activity.__init__(self, handle)
-# self.set_title(_('APRS-XO Activity'))
- self.set_title("APRS-XO Activity")
-
-# self.connect("destroy", self.onDestroy)
+ self.set_title(_('APRS-XO Activity'))
self.sock = None
self.location = "home"
self.site = None
self.sent_acks = {}
+ self.recv_acks = {}
self.timers = []
+ self.bulletins = ["AIR", "DGPS", "QST", "TEL", "ALL", "DRILL", "QTH", "TEST", "AP", "DX", "RTCM", "TLM", "BEACON", "ID", "SKY", "WX", "CQ", "JAVA", "SPACE", "ZIP", "GPS", "MAIL", "SPC", "DF", "MICE", "SYM", "BLN", "NWS", "NTS"]
self.validating = False
self.help = True
self.messagebox = False
+ self.sequence = random.randrange(0, 7000)
titlefont = pango.FontDescription('Sans bold 8')
mediumfont = pango.FontDescription('Sans 6.5')
@@ -81,8 +83,8 @@ class APRSActivity(activity.Activity):
leftwin = gtk.VBox(False, 10)
# Top 'about' box
- aboutbox = gtk.VBox(False, 8)
- aboutbox.set_border_width(8)
+ aboutbox = gtk.VBox(False, 11)
+ aboutbox.set_border_width(10)
topaboutbox = gtk.VBox(False, 0)
@@ -92,22 +94,22 @@ class APRSActivity(activity.Activity):
titlelabel.modify_font(titlefont)
titlebox.pack_start(titlelabel, False, False, 0)
titlelabel.show()
- aboutlabel1 = gtk.Label("This amateur radio program will update your position")
+ aboutlabel1 = gtk.Label("This amateur radio program will update your")
aboutlabel1.set_alignment(0, 0.8)
- aboutlabel1.modify_font(mediumfont)
+# aboutlabel1.modify_font(mediumfont)
titlebox.pack_start(aboutlabel1, False, False, 0)
aboutlabel1.show()
topaboutbox.pack_start(titlebox, False, False, 0)
titlebox.show()
- aboutlabel2 = gtk.Label("& status on all of the global APRS web pages once every 10 minutes.")
+ aboutlabel2 = gtk.Label("positon & status on all of the global APRS web pages once\nevery 10 minutes.")
aboutlabel2.set_alignment(0, 0)
- aboutlabel2.modify_font(mediumfont)
+# aboutlabel2.modify_font(mediumfont)
topaboutbox.pack_start(aboutlabel2, False, False, 0)
aboutlabel2.show()
aboutbox.pack_start(topaboutbox, False, False, 0)
topaboutbox.show()
- sitebox = gtk.HBox(False, 8)
+ sitebox = gtk.HBox(False, 10)
sitelabel = gtk.Label("Select an APRS site:")
sitelabel.set_alignment(0, 0.4)
sitebox.pack_start(sitelabel, False, False, 0)
@@ -134,18 +136,17 @@ class APRSActivity(activity.Activity):
aboutbox.pack_start(sitebox, False, False, 0)
sitebox.show()
- infobox = gtk.VBox(False, 4)
- # more info radio box?
+# infobox = gtk.VBox(False, 4)
-# infolabel = gtk.Label("With a ham license you can communicate worldwide with wireless and radio.\nWithout a ham license you can only communicate with other XO's on the\nInternet.")
- infolabel = gtk.Label("With a ham license you can communicate worldwide with wireless and radio.")
- infolabel.set_alignment(0, 0)
- infolabel.modify_font(smallfont)
- infobox.pack_start(infolabel, False, False, 0)
- infolabel.show()
+## infolabel = gtk.Label("With a ham license you can communicate worldwide with wireless and radio.\nWithout a ham license you can only communicate with other XO's on the\nInternet.")
+# infolabel = gtk.Label("With a ham license you can communicate worldwide with wireless and radio.")
+# infolabel.set_alignment(0, 0)
+# infolabel.modify_font(smallfont)
+# infobox.pack_start(infolabel, False, False, 0)
+# infolabel.show()
- aboutbox.pack_start(infobox, False, False, 0)
- infobox.show()
+# aboutbox.pack_start(infobox, False, False, 0)
+# infobox.show()
leftwin.pack_start(aboutbox, False, False, 0)
aboutbox.show()
@@ -156,7 +157,7 @@ class APRSActivity(activity.Activity):
# identifiers box
identbox = gtk.VBox(False, 4)
- identbox.set_border_width(8)
+ identbox.set_border_width(10)
identlabel = gtk.Label("Identifiers")
identlabel.set_alignment(0, 0)
@@ -183,11 +184,11 @@ class APRSActivity(activity.Activity):
bottomidentbox.pack_start(passlabel1, False, False, 0)
passlabel1.show()
-# bottomrightidentbox = gtk.VBox(False, 0)
-
self.passtext = gtk.Entry()
self.passtext.set_max_length(5)
self.passtext.set_width_chars(5)
+ self.passtext.set_invisible_char("x")
+ self.passtext.set_visibility(False)
bottomidentbox.pack_start(self.passtext, False, False, 0)
self.passtext.show()
@@ -195,14 +196,11 @@ class APRSActivity(activity.Activity):
bottomidentbox.show()
passlabel2 = gtk.Label("optional")
- passlabel2.set_alignment(0.68, 0)
+ passlabel2.set_alignment(0.74, 0)
passlabel2.modify_font(smallfont)
identbox.pack_start(passlabel2, False, False, 0)
passlabel2.show()
- # bottomidentbox.pack_start(bottomrightidentbox, False, False, 0)
- # bottomrightidentbox.show()
-
leftwin.pack_start(identbox, False, False, 0)
identbox.show()
@@ -211,15 +209,12 @@ class APRSActivity(activity.Activity):
separator.show()
# station box
- stationbox = gtk.VBox(False, 8)
- stationbox.set_border_width(8)
-
-# topstationbox = gtk.HBox(False, 8)
+ stationbox = gtk.VBox(False, 11)
+ stationbox.set_border_width(10)
stationlabel = gtk.Label("Station Comment")
stationlabel.set_alignment(0, 0)
stationlabel.modify_font(titlefont)
-# topstationbox.pack_start(stationlabel, False, False, 0)
stationbox.pack_start(stationlabel, False, False, 0)
stationlabel.show()
@@ -231,16 +226,12 @@ class APRSActivity(activity.Activity):
self.stationtext.set_width_chars(43)
self.stationtext.set_text("%s's XO at home." % firstName)
self.stationtext.connect("changed", self.disable_beacon)
-# topstationbox.pack_start(self.stationtext, False, False, 0)
stationtextbox.pack_start(self.stationtext, False, False, 0)
self.stationtext.show()
stationbox.pack_start(stationtextbox, False, False, 0)
stationtextbox.show()
-# stationbox.pack_start(topstationbox, False, False, 0)
-# topstationbox.show()
-
- stationhelp = gtk.Label("Optional description of current position, status, or destination.\nEnter up to 43 characters, most important first since some\ndisplays can only see the first 20 or 28.")
+ stationhelp = gtk.Label("Optional description of current position, status,\nor destination. Enter up to 43 characters, most\nimportant first since some displays can only see\nthe first 20 or 28.")
stationhelp.set_alignment(0, 0)
# stationhelp.modify_font(mediumfont)
stationbox.pack_start(stationhelp, False, False, 0)
@@ -254,8 +245,8 @@ class APRSActivity(activity.Activity):
separator.show()
# position box
- positbox = gtk.VBox(False, 8)
- positbox.set_border_width(8)
+ positbox = gtk.VBox(False, 11)
+ positbox.set_border_width(10)
toppositbox = gtk.HBox(False, 0)
@@ -387,9 +378,9 @@ class APRSActivity(activity.Activity):
positbox.pack_start(toppositbox, False, False, 0)
toppositbox.show()
- positlabel2 = gtk.Label("If you do not know your LAT/LONG then your zip code will be used to\nplace you on the map.")
+ positlabel2 = gtk.Label("If you do not know your LAT/LONG then your zip code will\nbe used to place you on the map.")
positlabel2.set_alignment(0, 0)
- positlabel2.modify_font(mediumfont)
+# positlabel2.modify_font(mediumfont)
positbox.pack_start(positlabel2, False, False, 0)
positlabel2.show()
@@ -401,10 +392,10 @@ class APRSActivity(activity.Activity):
separator.show()
# defined here so clear and connect buttons have access
- statusview = gtk.TextView()
- self.statusbuffer = statusview.get_buffer()
- messageview = gtk.TextView()
- self.messagebuffer = messageview.get_buffer()
+ self.statusview = gtk.TextView()
+ self.statusbuffer = self.statusview.get_buffer()
+ self.messageview = gtk.TextView()
+ self.messagebuffer = self.messageview.get_buffer()
connectbutton = gtk.Button()
connectbutton.set_label("Connect")
@@ -436,18 +427,18 @@ class APRSActivity(activity.Activity):
rightwin.pack_start(rightwintopbox, False, False, 0)
rightwintopbox.show()
- messageview.set_editable(False)
- messageview.set_cursor_visible(True)
- messageview.set_wrap_mode(gtk.WRAP_CHAR)
- messageview.set_justification(gtk.JUSTIFY_LEFT)
- messageview.modify_font(smallfont)
+ self.messageview.set_editable(False)
+ self.messageview.set_cursor_visible(True)
+ self.messageview.set_wrap_mode(gtk.WRAP_CHAR)
+ self.messageview.set_justification(gtk.JUSTIFY_LEFT)
+ self.messageview.modify_font(smallfont)
- self.messagebuffer.set_text("Welcome to APRS-XO.\n\nThis program sends your position information to a server\nthat will then display your location on a webpage. This\nprogram requires an active Internet connection to work.\n\nSelect an APRS Site\nSelecting a button will copy the URI to the clipboard.\n\nIndentifiers\nEnter your callsign and optionally an aprsd password\n\nStation Comment\nData in the Station Comment field will appear after your\nlocation information on the website.")
+ self.messagebuffer.set_text("Welcome to APRS-XO.\n\nThis program sends your position information to a server that will\nthen display your location on a webpage. This program requires an\nactive Internet connection to work.\n\nSelect an APRS Site\nSelecting a button will copy the URI to the clipboard.\n\nIndentifiers\nEnter your callsign and optionally an aprsd password.\n\nStation Comment\nData in the Station Comment field will appear after your location\ninformation on the website.")
self.messagewindow = gtk.ScrolledWindow()
self.messagewindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
- self.messagewindow.add_with_viewport(messageview)
- messageview.show()
+ self.messagewindow.add_with_viewport(self.messageview)
+ self.messageview.show()
rightwin.pack_start(self.messagewindow, True, True, 0)
self.messagewindow.show()
@@ -467,8 +458,9 @@ class APRSActivity(activity.Activity):
self.messagecombo.show()
self.messagetext = gtk.Entry()
+ # TODO should this be lower with acks?
self.messagetext.set_max_length(67)
- self.messagetext.set_width_chars(28)
+ self.messagetext.set_width_chars(32)
self.messagetext.modify_font(smallfont)
self.messagetext.connect("activate", self.send_message, self.messagetext)
messagebox.pack_start(self.messagetext, False, False, 0)
@@ -483,18 +475,18 @@ class APRSActivity(activity.Activity):
rightwin.pack_start(messagebox, False, False, 0)
messagebox.show()
- statusview.set_editable(False)
- statusview.set_cursor_visible(True)
- statusview.set_wrap_mode(gtk.WRAP_CHAR)
- statusview.set_justification(gtk.JUSTIFY_LEFT)
- statusview.modify_font(smallfont)
+ self.statusview.set_editable(False)
+ self.statusview.set_cursor_visible(True)
+ self.statusview.set_wrap_mode(gtk.WRAP_CHAR)
+ self.statusview.set_justification(gtk.JUSTIFY_LEFT)
+ self.statusview.modify_font(smallfont)
- self.statusbuffer.set_text("Position\nEnter your lat/lon. You may leave the decimal minutes (mm)\nblank for position ambiguity. If you do not know your lat/lon,\nenter your 5 digit zip code instead.\n\nBeacon\nWhen selected, sends location data every 10 minutes. The\nbeacon will automatically stop when you edit personal\ninformation. Must be manually reselected after edit\ncompletion.\n\nThis message will self destruct when you press Connect\n\nAPRS Copyright (c) Bob Bruninga WB4APR\n\n")
+ self.statusbuffer.set_text("Position\nEnter your lat/long. You may leave the decimal minutes (mm)\nblank for position ambiguity. If you do not know your lat/long,\nenter your 5 digit zip code instead.\n\nBeacon\nWhen selected, sends location data every 10 minutes. The\nbeacon will automatically stop when you edit personal\ninformation. Must be manually reselected after edit completion.\n\nThis message will self destruct when you press Connect.\n\nAPRS Copyright (c) Bob Bruninga WB4APR\n\n")
self.statuswindow = gtk.ScrolledWindow()
self.statuswindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
- self.statuswindow.add_with_viewport(statusview)
- statusview.show()
+ self.statuswindow.add_with_viewport(self.statusview)
+ self.statusview.show()
rightwin.pack_start(self.statuswindow, True, True, 0)
self.statuswindow.show()
@@ -502,7 +494,7 @@ class APRSActivity(activity.Activity):
self.rawtext = gtk.Entry()
self.rawtext.set_max_length(128)
- self.rawtext.set_width_chars(39)
+ self.rawtext.set_width_chars(43)
self.rawtext.modify_font(smallfont)
self.rawtext.connect("activate", self.raw_send)
self.rawbox.pack_start(self.rawtext, False, False, 0)
@@ -515,8 +507,6 @@ class APRSActivity(activity.Activity):
rawbutton.show()
rightwin.pack_start(self.rawbox, False, False, 0)
- # only show if aprsd says you are verified
- # changed to always available
self.rawbox.show()
win.pack_start(rightwin, False, False, 0)
@@ -534,13 +524,12 @@ class APRSActivity(activity.Activity):
self.lonMMtext.set_text("6")
self.lonmmtext.set_text("93")
self.loncombo.set_active(0)
-# self.nametext.set_text("Jack")
-# self.locbutton.set_active(0)
- self.stationtext.set_text("")
+# self.stationtext.set_text("")
self.ziptext.set_text("")
self.beaconbutton.set_active(True)
win.show()
+ self.calltext.grab_focus()
def clear_status(self, button=None):
# self.statusbuffer.delete(self.statusbuffer.get_start_iter(), self.statusbuffer.get_end_iter())
@@ -555,7 +544,6 @@ class APRSActivity(activity.Activity):
if (self.help):
self.clear_status()
-# self.clear_message()
self.messagebuffer.set_text("Message Window")
self.messagebox = True
self.help = False
@@ -647,13 +635,14 @@ class APRSActivity(activity.Activity):
self.status_write("Server closed connection.\n")
return False
else:
-# self.status_write(recv_data)
- # find uri's
+ # find uri's http or else www
webaddy = recv_data.lower().find("http")
if (webaddy != -1):
recv_data = ("%s\n%s" % (recv_data[:webaddy], recv_data[webaddy:]))
-
- # for now just cut the line at the first ":" unless it looks like a comment
+ else:
+ webaddy = recv_data.lower().find("www")
+ if (webaddy != -1):
+ recv_data = ("%s\n%s" % (recv_data[:webaddy], recv_data[webaddy:]))
if (recv_data[0] == "#"):
self.status_write("%s\n\n" % recv_data)
else:
@@ -665,9 +654,7 @@ class APRSActivity(activity.Activity):
self.status_write("%s\n" % recv_data[cuthere+1:])
else:
self.status_write("%s\n\n" % recv_data[cuthere+1:])
-
self.msg_check(recv_data)
-
return True
def send_beacon(self):
@@ -701,13 +688,18 @@ class APRSActivity(activity.Activity):
if (statuslines > MAXLINES):
deletehere = self.statusbuffer.get_iter_at_line(statuslines - MAXLINES)
self.statusbuffer.delete(self.statusbuffer.get_start_iter(), deletehere)
- adjustment = self.statuswindow.get_vadjustment()
- adjustment.set_value(adjustment.upper)
+ if (not self.statusview.is_focus()):
+ adjustment = self.statuswindow.get_vadjustment()
+ adjustment.set_value(adjustment.upper)
def message_write(self, text):
+ if (self.messagebox):
+ self.clear_message()
+ self.messagebox = False
self.messagebuffer.insert(self.messagebuffer.get_end_iter(), text)
- adjustment = self.messagewindow.get_vadjustment()
- adjustment.set_value(adjustment.upper)
+ if (not self.messageview.is_focus()):
+ adjustment = self.messagewindow.get_vadjustment()
+ adjustment.set_value(adjustment.upper)
def set_location(self, widget, data=None):
self.location = data
@@ -754,8 +746,8 @@ class APRSActivity(activity.Activity):
self.status_write("[ERROR] %s\n" % msg[1])
self.validating = False
return False
- A = random.randrange(0,9)
- O = random.randrange(0,9)
+ A = random.randrange(0, 9)
+ O = random.randrange(0, 9)
if (self.calltext.get_text() == ""):
self.calltext.set_text("X%s-%d%d" % (self.ziptext.get_text(), A, O))
try:
@@ -799,7 +791,7 @@ class APRSActivity(activity.Activity):
stop_here = True
if (stop_here):
- self.status_write("Latitude and Longitude must be complete.\nFor position ambiguity omit decimal Minutes (mm).\nIf you do not know your lat/lon, leave the letters\n(DD, MM, etc) and provide your zip code.\n")
+ self.status_write("Latitude and Longitude must be complete.\nFor position ambiguity omit decimal Minutes (mm).\nIf you do not know your lat/long, leave the letters\n(DD, MM, etc) and provide your zip code.\n")
self.validating = False
return False
@@ -854,75 +846,121 @@ class APRSActivity(activity.Activity):
self.beaconbutton.set_active(beaconchecked)
self.validating = False
-# def onDestroy(self, junk=None ):
-# if (self.sock != None):
-# self.disconnect()
-
def close( self ):
self.hide()
if (self.sock != None):
self.disconnect()
activity.Activity.close( self )
-# def write_file(self, filename):
+ def write_file_broken(self, filename):
# does not appear to run
# from self.save() returns:
# TypeError: object of type 'dbus.Int32' has no len()
-# self.metadata['mime_type'] = 'text/plain'
-
-# self.metadata['callsign'] = self.calltext.get_text()
-# self.metadata['password'] = self.passtext.get_text()
-# self.metadata['latDD'] = self.latDDtext.get_text()
-# self.metadata['latMM'] = self.latMMtext.get_text()
-# self.metadata['latmm'] = self.latmmtext.get_text()
-# self.metadata['lat'] = self.latcombo.get_active()
-# self.metadata['lonDDD'] = self.lonDDDtext.get_text()
-# self.metadata['lonMM'] = self.lonMMtext.get_text()
-# self.metadata['lonmm'] = self.lonmmtext.get_text()
-# self.metadata['lon'] = self.loncombo.get_active()
-## self.metadata['nick_name'] = self.nametext.get_text()
-## self.metadata['location'] = self.location
-# self.metadata['stationtext'] = self.stationtext.get_text()
-## self.metadata['zip'] = self.ziptext.get_text()
-# self.metadata['beacon'] = self.beaconbutton.get_active()
-# # should save list of callsigns used in outgoing messages
-
-# def read_file(self, filename):
-# # does not appear to run
-# self.calltext.set_text(self.metadata.get('callsign', ""))
-# self.passtext.set_text(self.metadata.get('password', ""))
-# self.latDDtext.set_text(self.metadata.get('latDD', "00"))
-# self.latMMtext.set_text(self.metadata.get('latMM', "00"))
-# self.latmmtext.set_text(self.metadata.get('latmm', "00"))
-## self.latcombo.set_active(self.metadata.get('lat', ""))
-# self.lonDDDtext.set_text(self.metadata.get('lonDDD', "000"))
-# self.lonMMtext.set_text(self.metadata.get('lonMM', "00"))
-# self.lonmmtext.set_text(self.metadata.get('lonmm', "00"))
-## self.loncombo.set_active(self.metadata.get('lon', ""))
-## self.nametext.set_text(self.metadata.get('nick_name', "Joe"))
-## self.locbutton.set_active(self.metadata.get('location', ""))
-# self.stationtext.set_text(self.metadata.get('stationtext', "test text"))
-# self.ziptext.set_text(self.metadata.get('zip', ""))
-## self.beaconbutton.set_active(self.metadata.get('beacon', ""))
+ self.metadata['mime_type'] = 'text/plain'
+
+ self.metadata['callsign'] = self.calltext.get_text()
+ self.metadata['password'] = self.passtext.get_text()
+ self.metadata['latDD'] = self.latDDtext.get_text()
+ self.metadata['latMM'] = self.latMMtext.get_text()
+ self.metadata['latmm'] = self.latmmtext.get_text()
+ self.metadata['lat'] = self.latcombo.get_active()
+ self.metadata['lonDDD'] = self.lonDDDtext.get_text()
+ self.metadata['lonMM'] = self.lonMMtext.get_text()
+ self.metadata['lonmm'] = self.lonmmtext.get_text()
+ self.metadata['lon'] = self.loncombo.get_active()
+# self.metadata['nick_name'] = self.nametext.get_text()
+# self.metadata['location'] = self.location
+ self.metadata['stationtext'] = self.stationtext.get_text()
+# self.metadata['zip'] = self.ziptext.get_text()
+ self.metadata['beacon'] = self.beaconbutton.get_active()
+ # should save list of callsigns used in outgoing messages
+
+ def read_file_broken(self, filename):
+ # does not appear to run
+ self.calltext.set_text(self.metadata.get('callsign', ""))
+ self.passtext.set_text(self.metadata.get('password', ""))
+ self.latDDtext.set_text(self.metadata.get('latDD', "00"))
+ self.latMMtext.set_text(self.metadata.get('latMM', "00"))
+ self.latmmtext.set_text(self.metadata.get('latmm', "00"))
+# self.latcombo.set_active(self.metadata.get('lat', ""))
+ self.lonDDDtext.set_text(self.metadata.get('lonDDD', "000"))
+ self.lonMMtext.set_text(self.metadata.get('lonMM', "00"))
+ self.lonmmtext.set_text(self.metadata.get('lonmm', "00"))
+# self.loncombo.set_active(self.metadata.get('lon', ""))
+# self.nametext.set_text(self.metadata.get('nick_name', "Joe"))
+# self.locbutton.set_active(self.metadata.get('location', ""))
+ self.stationtext.set_text(self.metadata.get('stationtext', "test text"))
+ self.ziptext.set_text(self.metadata.get('zip', ""))
+# self.beaconbutton.set_active(self.metadata.get('beacon', ""))
def msg_check(self, data):
+ # a better message decoder
+ firstcheck = data.find("::")
+ secondcheck = data[firstcheck+11:firstcheck+12]
+ thirdcheck = data.find("{")
+ if (firstcheck != -1 and secondcheck == ":"):
+ tocall = data[firstcheck+2:firstcheck+11].upper()
+ strippedtocall = tocall.strip()
+ fromcall = data[:data.find(">")].upper()
+ isbulletin = self.bulletin_check(strippedtocall)
+ if (isbulletin):
+ message = data[firstcheck+12:-1]
+ # TODO add BLN, etc to tocall dropdown list?
+# self.add_callsign(fromcall, False)
+ # for now, display them every time
+ self.message_write("%s %s.%s> %s\n" % (time.strftime("%m/%d %H:%M", time.localtime()), fromcall, strippedtocall, message))
+ else:
+ if (strippedtocall == self.calltext.get_text()):
+ self.add_callsign(fromcall, False)
+ if (thirdcheck != -1):
+ sequence_end = data.find("}")
+ if (sequence_end == -1):
+ sequence = data[thirdcheck+1:-1]
+ else:
+ sequence = data[thirdcheck+1:sequence_end]
+ replyack = data[sequence_end+1:-1]
+ if (replyack[0:3] == "ack"):
+ self.recv_acks["%s-%s" % (fromcall, replyack[3:])] = 1
+ message = data[firstcheck+12:thirdcheck]
+ ackmessage = ":%s:ack%s" % (fromcall, sequence)
+ self.send_data(ackmessage)
+ id = "%s-%s" % (fromcall, sequence)
+ if (id in self.sent_acks):
+ self.timers.append(gobject.timeout_add(30 * 1000, self.send_ack, ackmessage))
+ self.timers.append(gobject.timeout_add(60 * 1000, self.send_ack, ackmessage))
+ self.timers.append(gobject.timeout_add(120 * 1000, self.send_ack, ackmessage))
+ else:
+ self.message_write("%s %s> %s\n" % (time.strftime("%m/%d %H:%M", time.localtime()), fromcall, message))
+ self.sent_acks[id] = time.time() # to help a cleanup thread later
+ self.sent_acks[fromcall] = sequence # to help with reply acks later
+ else:
+ message = data[firstcheck+12:-1]
+ if (message[0:3] == "ack"):
+ self.recv_acks["%s-%s" % (fromcall, message[3:])] = 1
+ else:
+ self.message_write("%s %s> %s\n" % (time.strftime("%m/%d %H:%M", time.localtime()), fromcall, message))
+
+ def msg_check_old(self, data):
# a quick "does it look like a message?" check
# this check will only find messages that require acks
firstcheck = data.find("::")
secondcheck = data.find("{")
+ # FIX this will ignore BLN, ALL, QST, CQ, etc with { in message
+ # FIXME actually a BLN with a { freezes the status window..
if (firstcheck != -1 and secondcheck != -1):
# great, it looks kinda like a message, is it to me?
- tocall = data[firstcheck+2:firstcheck+11]
- strippedtocall = tocall.strip().upper()
+ tocall = data[firstcheck+2:firstcheck+11].upper()
+ strippedtocall = tocall.strip()
if (strippedtocall == self.calltext.get_text()):
sequence_end = data.find("}")
if (sequence_end == -1):
sequence = data[secondcheck+1:-1]
else:
sequence = data[secondcheck+1:sequence_end]
- fromcall = data[:data.find(">")]
+ fromcall = data[:data.find(">")].upper()
message = data[firstcheck+12:secondcheck]
+ self.add_callsign(fromcall, False)
ackmessage = ":%s:ack%s" % (fromcall, sequence)
self.send_data(ackmessage)
id = "%s-%s" % (fromcall, sequence)
@@ -931,26 +969,29 @@ class APRSActivity(activity.Activity):
self.timers.append(gobject.timeout_add(60 * 1000, self.send_ack, ackmessage))
self.timers.append(gobject.timeout_add(120 * 1000, self.send_ack, ackmessage))
else:
- if (self.messagebox):
- self.clear_message()
- self.messagebox = False
- self.message_write("%s> %s\n" % (fromcall, message))
+ self.message_write("%s %s> %s\n" % (time.strftime("%m/%d %H:%M", time.localtime()), fromcall, message))
self.sent_acks[id] = time.time() # to help a cleanup thread later
self.sent_acks[fromcall] = sequence # to help with reply acks later
else:
# is it a message that does not get acked?
if (firstcheck != -1):
- tocall = data[firstcheck+2:firstcheck+11]
- strippedtocall = tocall.strip().upper()
+ tocall = data[firstcheck+2:firstcheck+11].upper()
+ strippedtocall = tocall.strip()
+ fromcall = data[:data.find(">")].upper()
+ message = data[firstcheck+12:-1]
if (strippedtocall == "ALL" or strippedtocall == "QST" or strippedtocall == "CQ" or strippedtocall[:3] == "BLN" or strippedtocall[:3] == "NWS"):
- fromcall = data[:data.find(">")]
- message = data[firstcheck+12:-1]
# for now, display them every time
- if (self.messagebox):
- self.clear_message()
- self.messagebox = False
- self.message_write("%s:%s> %s\n" % (fromcall, strippedtocall, message))
+ self.message_write("%s %s:%s> %s\n" % (time.strftime("%m/%d %H:%M", time.localtime()), fromcall, strippedtocall, message))
+ else:
+ # is it an ack (to me)?
+ if (strippedtocall == self.calltext.get_text()):
+ if (message[0:3] == "ack"):
+ # record the message as acked to stop repeating it
+ self.recv_acks["%s-%s" % (fromcall, message[3:])] = 1
+ else:
+ # no ack and addressed to me.
+ self.message_write("%s %s> %s\n" % (time.strftime("%m/%d %H:%M", time.localtime()), fromcall, message))
def disable_beacon(self, widget, data=None):
if (self.sock != None):
@@ -973,9 +1014,85 @@ class APRSActivity(activity.Activity):
return True
def send_message(self, widget, data=None):
- self.message_write("This version of APRS-XO can not send messages.\n")
+ tocall = self.messagedest.get_text().upper()
+ message = self.messagetext.get_text()
+
+ isbulletin = self.bulletin_check(tocall)
+
+ # check for illegal characters before clearing message
+ if (isbulletin):
+ if (message.find("|") != -1 or message.find("~") != -1):
+ self.message_write("Bulletins can not contain the following characters: | ~")
+ return False
+ else:
+ if (message.find("|") != -1 or message.find("~") != -1 or message.find("{") != -1):
+ self.message_write("Messages can not contain the following characters: | ~ {")
+ return False
+
self.messagetext.set_text("")
+ # add callsign to list if just entered
+ if (self.messagecombo.get_active() == -1):
+ self.add_callsign(tocall, True)
+
+ # get a sequence number
+ if (isbulletin):
+ # don't waste a number on a bulletin
+ sequence = ""
+ else:
+ sequence = "%s" % self.b90()
+
+ # TODO
+ # check to see if there is an unack-ed message to same callsign
+ # too many to the same call? give an error instead
+ # too many in general? give an error instead
+ # print message + QUEUED add to the queue...
+ # cancel message option - menu popup
+
+ # TODO save location for repeat/ack counter, queued and cancelled locations too
+ # put the message in the message window
+# self.message_write("%s %s> %s\n" % (time.strftime("%m/%d %H:%M", time.localtime()), self.calltext.get_text(), message))
+ self.message_write("%s To:%s> %s\n" % (time.strftime("%m/%d %H:%M", time.localtime()), tocall, message))
+
+ # send the message
+ if (isbulletin):
+ self.send_data(":%s:%s" % (tocall.ljust(9), message))
+ # TODO what are the correct timings for bulletins?
+ gobject.timeout_add(600 * 1000, self.msg_timer, tocall, message, "", 2, 600)
+ else:
+ replyack = self.replyack(tocall)
+ self.send_data(":%s:%s{%s}%s" % (tocall.ljust(9), message, sequence, replyack))
+ self.recv_acks["%s-%s" % (tocall, sequence)] = 0
+ gobject.timeout_add(7 * 1000, self.msg_timer, tocall, message, sequence, 2, 7)
+
+ def b90(self):
+ if (self.sequence > 8099):
+ self.sequence = 0
+ first = ((self.sequence / 90) % 90) + 33
+ second = (self.sequence % 90) + 33
+ output = "%c%c" % (first, second)
+ self.sequence += 1
+ return output
+
+ def msg_timer(self, tocall, message, sequence, count, delay):
+ if (self.recv_acks["%s-%s" % (tocall, sequence)] == 1):
+ return False
+ else:
+ replyack = self.replyack(tocall)
+ self.send_data(":%s:%s{%s}%s" % (tocall.ljust(9), message, sequence, replyack))
+
+ # start the next timer
+ count += 1
+ if (count > MAXRETRIES):
+ return False
+ delay *= 2
+ if (delay > 600):
+ delay = 600
+ gobject.timeout_add(delay * 1000, self.msg_timer, tocall, message, sequence, count, delay)
+
+ # and stop this timer
+ return False
+
def clipboard(self):
clipboard = gtk.clipboard_get()
target = [("text/uri-list", 0, 0)]
@@ -986,3 +1103,34 @@ class APRSActivity(activity.Activity):
def clipboard_clear(self, clipboard, data):
pass
+
+ def add_callsign(self, callsign, activate):
+ model = self.messagecombo.get_model()
+ notfound = True
+ iter = model.get_iter_first()
+ while iter:
+ currentcall = model.get(iter, 0)[0]
+ if (currentcall == callsign):
+ notfound = False
+ break
+ iter = model.iter_next(iter)
+ if (notfound):
+ self.messagecombo.prepend_text(callsign)
+ if (activate):
+ self.messagecombo.set_active(0)
+
+ def bulletin_check(self, callsign):
+ for currentcall in self.bulletins:
+ length = len(currentcall)
+ if (currentcall == callsign[0:length]):
+ return True
+ return False
+
+ def replyack(self, tocall):
+ replyack = ""
+ if (tocall in self.sent_acks):
+ id = "%s-%s" % (tocall, self.sent_acks[tocall])
+ if (time.time() - self.sent_acks[id] < 5400):
+ # less than 90 minutes ago
+ replyack = "ack%s" % self.sent_acks[tocall]
+ return replyack