#!/usr/bin/python
license="""
Copyright (C) Dwayne Zon 2009 <dwayne.zon@gmail.com>

You may 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.

zSync.py 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 zToDo.py.  If not, write to:
The Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor
Boston, MA  02110-1301, USA.
"""
version_long='0.7: <2009-May-19 6:09pm>'
version_short='0.7'

import sys,time,datetime
#from ftplib import FTP
from subprocess import Popen
import ftplib
import gtk, hildon
try:
    import osso
    nokia=True
except:
    nokia=False
import pickle, os, threading, fcntl,socket

# Application startup routine
def application_setup(text_name, sys_name, homedir='.python'):
    global program_name, logfile, root, osso_context, context_name, app, vb
    program_name=text_name
    # "context" must start with "org.maemo."
    context_name='org.maemo.'+sys_name
    osso_context=None
    app=None
    # change into data dir
    f=os.getenv('HOME') + '/' + homedir
    if not os.path.exists(f):
        os.mkdir(f)
    os.chdir(f)
    if nokia:
        # log errors to a file for post-mortem debugging w/o a console
        logfile=sys_name+'.log'
        sys.stderr=open(logfile, 'w')
        # Nokia tablet setup
        osso_context=osso.Context(context_name, version_short, False)
        app=hildon.Program()
        root=hildon.Window()
        app.add_window(root)
        root.window_in_fullscreen=False
        root.connect('key-press-event', cb_key_press)
        root.connect('window-state-event', cb_window_state_change)
        # note that this also sets the main window title in Hildon
        gtk.set_application_name(program_name)
    else:
        root=gtk.Window()
        root.resize(200, 200)
        root.set_title(program_name)

    # exit gracefully when window is closed
    root.connect('destroy', lambda wid: gtk.main_quit())
    root.connect('delete_event', lambda a1, a2: gtk.main_quit())

    # exit gracefully on shutdown
#    signal.signal(15, lambda a1: gtk.main_quit())
    vb=gtk.VBox()
    root.add(vb)
    return root, vb

def attach_menu(menu, window=None):
    if nokia:
        if window:
            window.set_menu(menu)
        else:
            root.set_menu(menu)
    else:
        # ugly as hell
        mb=gtk.MenuBar()
        i=gtk.MenuItem('Operation Menu')
        i.set_submenu(menu)
        mb.append(i)
        vb.pack_start(mb, False, False)

# create Hildonized dialog window
def dialog_window(title, modal=True):
    if nokia:
        w=hildon.Window()
        app.add_window(w)
    else:
        w=gtk.Window()
        w.resize(800, 480)
    w.set_transient_for(root)
    w.set_destroy_with_parent(True)
    if modal:
        w.set_modal(True)
    w.set_title(title)
    if nokia:
        w.window_in_fullscreen=False
        w.connect('key-press-event', cb_key_press)
        w.connect('window-state-event', cb_window_state_change)
    return w

# display logfile
class show_logfile:
    def __init__(self, *x):
        if not nokia:
            return

        # create window with scrolling text
        self.win=dialog_window('View Logs', False)
        sw=gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self.win.add(sw)
        tv=gtk.TextView()
        tv.set_wrap_mode(gtk.WRAP_WORD)
        tv.set_editable(False)
        buf=tv.get_buffer()
        end_mark=buf.create_mark('end', buf.get_end_iter(), False)
        sw.add(tv)

        # read log file and load widget
        sys.stderr.flush()
        buf.insert_at_cursor(file(logfile, 'rb').read())

        # create menu
        self.menu=gtk.Menu()
        i=gtk.MenuItem('Clear Log')
        i.connect('activate',self.clear_log)
        self.menu.append(i)
        i=gtk.MenuItem('Close')
        i.connect('activate',self.close)
        self.menu.append(i)

        self.win.set_menu(self.menu)
        self.win.show_all()
        tv.scroll_mark_onscreen(end_mark)

    def close(self, b):
        self.win.destroy()

    def clear_log(self, b):
        sys.stderr=file(logfile, 'w')
        self.win.destroy()

###################################################################################################################
### Dialog to edit parameters

class cb_setup_parms:
    def __init__(self, *x):
        self.win=dialog_window('Setup Parameters')
        vb=gtk.VBox()
        self.win.add(vb)

        # Which things to sync
        hb=gtk.HBox()
        vb.pack_start(hb, False, False,10)
        vb2=gtk.VBox()
        hb.pack_start(vb2, False, False,10)

        self.checkbox_ztodo = gtk.CheckButton('Sync Ztodo?')
        self.checkbox_ztodo.connect('toggled',self.cb_change_ztodo)
        self.checkbox_ztodo.set_active(dosync[0])
        vb2.pack_start(self.checkbox_ztodo, False, False,10)

        self.checkbox_zcal = gtk.CheckButton('Sync GPE Calendar?')
        self.checkbox_zcal.connect('toggled',self.cb_change_zcal)
        self.checkbox_zcal.set_active(dosync[1])
        vb2.pack_start(self.checkbox_zcal, False, False,10)

        self.checkbox_zexpense = gtk.CheckButton('Sync Expenses?')
        self.checkbox_zexpense.connect('toggled',self.cb_change_zexpense)
        self.checkbox_zexpense.set_active(dosync[2])
        vb2.pack_start(self.checkbox_zexpense, False, False,10)

        self.checkbox_zcontact = gtk.CheckButton('Sync Contacts?')
        self.checkbox_zcontact.connect('toggled',self.cb_change_zcontact)
        self.checkbox_zcontact.set_active(dosync[3])
        vb2.pack_start(self.checkbox_zcontact, False, False,10)

        self.checkbox_znote = gtk.CheckButton('Sync Notes?')
        self.checkbox_znote.connect('toggled',self.cb_change_znote)
        self.checkbox_znote.set_active(dosync[4])
        vb2.pack_start(self.checkbox_znote, False, False,10)

        self.checkbox_manual = gtk.CheckButton('Sync Manual?')
        self.checkbox_manual.connect('toggled',self.cb_change_manual)
        self.checkbox_manual.set_active(syncmanual)
        vb2.pack_start(self.checkbox_manual, False, False,10)

        # Port edit box
        vb2=gtk.VBox()
        hb.pack_start(vb2, False, False,10)
        hb2=gtk.HBox()
        vb2.pack_start(hb2, False, False,10)
        txt = gtk.Label('Port:')
        hb2.pack_start(txt, True, False,10)
        self.port = gtk.Entry()
        self.port.set_text(parmblock.port)
        hb2.pack_start(self.port, True, False,10)

        # Userid edit box
        hb2=gtk.HBox()
        vb2.pack_start(hb2, False, False,10)
        txt = gtk.Label('Userid:')
        hb2.pack_start(txt, True, False,10)
        self.tuserid = gtk.Entry()
        self.tuserid.set_text(parmblock.userid)
        hb2.pack_start(self.tuserid, True, False,10)

        # Password edit box
        hb2=gtk.HBox()
        vb2.pack_start(hb2, False, False,10)
        txt = gtk.Label('Password:')
        hb2.pack_start(txt, True, False,10)
        self.tpassword = gtk.Entry()
        self.tpassword.set_text(parmblock.password)
        hb2.pack_start(self.tpassword, True, False,10)

        # buttons
        btn_save=button_with_image('Save', gtk.STOCK_SAVE, self.cb_save)
        btn_ok=button_with_image('OK', gtk.STOCK_OK, self.cb_ok)
        hb=gtk.HBox()
        vb.pack_start(hb, False, False)
        hb.pack_start(btn_save, False, False,10)
        hb.pack_start(btn_ok, False, False,10)
        self.win.show_all()

    # detail dialog: cancel button
    def cb_ok(self, b):
        self.win.destroy()

    # detail dialog: OK button
    def cb_save(self, b):
        parmblock.port = self.port.get_text()
        parmblock.userid = self.tuserid.get_text()
        parmblock.password = self.tpassword.get_text()
        if parmblock.userid <> '':
            userid = parmblock.userid
        if parmblock.password <> '':
            password = parmblock.password
        parmblock.syncopt = dosync
        self.win.destroy()

    def cb_change_ztodo(self,b):
        dosync[0] = self.checkbox_ztodo.get_active()

    def cb_change_zcal(self,b):
        dosync[1] = self.checkbox_zcal.get_active()

    def cb_change_zexpense(self,b):
        dosync[2] = self.checkbox_zexpense.get_active()

    def cb_change_zcontact(self,b):
        dosync[3] = self.checkbox_zcontact.get_active()

    def cb_change_znote(self,b):
        dosync[4] = self.checkbox_znote.get_active()

    def cb_change_manual(self,b):
        syncmanual = self.checkbox_manual.get_active()
        commandfilemain.visible = syncmanual
        cftxt.visible = syncmanual

###################################################################################################################
### utility functions

# detect hardware key presses
def cb_key_press(w, event):
    if event.keyval == gtk.keysyms.F6:
        # the "full screen" hardware key
        if w.window_in_fullscreen:
            w.unfullscreen()
        else:
            w.fullscreen()

# detect when the window is toggled to full-screen
def cb_window_state_change(w, event):
    if event.new_window_state & gtk.gdk.WINDOW_STATE_FULLSCREEN:
        w.window_in_fullscreen=True
    else:
        w.window_in_fullscreen=False

# button with stock image but without stock label
def button_with_image(label, stock, fcn, *args):
    b=gtk.Button(label)
    i=gtk.Image()
    if label and nokia:
        # large button
        i.set_from_stock(stock, gtk.ICON_SIZE_DND)
    else:
        # small button
        i.set_from_stock(stock, gtk.ICON_SIZE_BUTTON)
    b.set_image(i)
    b.connect('clicked', fcn, *args)
    return b

# About dialog box
def cb_about(*x):
    d=gtk.AboutDialog()
    d.set_name(program_name)
    d.set_version(version_short)
    d.set_comments('Sync with PC in support of zPIMS')
    d.set_authors(['Dwayne Zon <dwayne.zon@gmail.com'])
    d.set_license(license)
    d.set_website('http://ztodo.garage.maemo.org/')
    d.connect('response', lambda d, r: d.destroy())
    d.run()

############################################################################################################
class ftpsync(threading.Thread):

# Display messages on GUI and in log
    def dispmsg(self,msg,err=-1):
        gtk.gdk.threads_enter()
        statusbox.set_text(msg)
        if err == -1:
            statusframe.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse('silver'))
        elif err == 0:
            statusframe.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse('light green'))
        elif err == 1:
            statusframe.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse('yellow'))
        elif err == 2:
            statusframe.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse('red'))
        elif err == 3:
            statusframe.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse('cyan'))
        gtk.gdk.threads_leave()
        print >> sys.stderr,msg

#  Toggle the display of the cancel button
    def toggle_cancelbutton(self,on=False):
        gtk.gdk.threads_enter()
        if on:
            cancel_btn.show()
        else:
            cancel_btn.hide()
        gtk.gdk.threads_leave()

#  Make sync button pressable
    def restore_buttons(self):
        gtk.gdk.threads_enter()
        sync_btn.set_sensitive(True)
        gtk.gdk.threads_leave()

# Process the command file
    def run(self):
#        X=raw_input('test')
        waserrors = False
        global cancel_wait
        try:
#        if True:
            print >> sys.stderr,'Connecting to "'+parmblock.address+'":',parmblock.port
            remotezsync = ftplib.FTP()
#            print 't=',socket.getdefaulttimeout()
#            remotezsync.timeout = 3600
            remotezsync.connect(parmblock.address.rstrip().split(' ')[0],parmblock.port)
            remotezsync.login(userid,password)
    # Open command file and cycle through commands
            if syncmanual:
			    try:
				    cmdfile = open (commandfile,'r')
			    except:
				    self.dispmsg('Could not open command file',2)
				    self.restore_buttons()
				    return
            else:
                cmdfile = ['']
                for (i,j) in zip(dosync,synccmds):
                    if i:
    #                    print j
                        cmdfile = cmdfile + j
    #            print cmdfile
            errorflag = False
            for command in cmdfile:
                self.dispmsg('Processing: ' + command.rstrip(),0)
                if errorflag:
                    self.dispmsg( 'Skipping to next checkpoint',2)
                cmdoptions = command.rstrip().split(' ')
    # CHECKPOINT - If error, all commands will be ignored until the next checkpoint
                if cmdoptions[0] == 'CHECKPOINT':
                    if errorflag:
                        self.dispmsg('Error flag reset',0)
                    errorflag = False
    # PUT <filename> <source directory> <program-to-create-file>  - send the file name to the remote computer
                elif (not errorflag) and cmdoptions[0] == 'PUT':
                    # rename file to .tmp
                    try:
                        if len(cmdoptions) > 3:
                            cancel_wait = False
                            self.toggle_cancelbutton(True)
                            try:
                                os.remove(cmdoptions[2] + cmdoptions[1])
                            except:
                                pass
                            print >> sys.stderr,''.join(c + ' ' for c in cmdoptions[3:])
                            self.dispmsg('Running program '+''.join(c + ' ' for c in cmdoptions[3:]),1)
                            p = os.popen(''.join(c + ' ' for c in cmdoptions[3:]))
                            self.dispmsg('Waiting for file ' + cmdoptions[2] + cmdoptions[1],1)
                            while (not cancel_wait) and (not os.path.exists(cmdoptions[2] + cmdoptions[1])):
    #                            print cmdoptions[2] + cmdoptions[1]
                                time.sleep(3)

                            self.toggle_cancelbutton(False)
                            if cancel_wait:
                                self.dispmsg('Wait cancelled',2)
                                errorflag = True
                                waserrors = True
                        fstore = open(cmdoptions[2] + cmdoptions[1])
                        fcntl.flock(fstore,fcntl.LOCK_EX | fcntl.LOCK_NB)
                        os.rename(cmdoptions[2] + cmdoptions[1],cmdoptions[2] + cmdoptions[1] + '.tmp')
                        fcntl.flock(fstore,fcntl.LOCK_UN | fcntl.LOCK_NB)
                        fstore.close
    # if fails, set errorflag = True and don't do the rest
    # after success, rename the file back
                        infile = open(cmdoptions[2] + cmdoptions[1] + '.tmp',"rb")
                        try:
                            remotezsync.storbinary("STOR " + cmdoptions[1],infile)

                            os.rename(cmdoptions[2] + cmdoptions[1] + '.tmp',cmdoptions[2] + cmdoptions[1])
                        except Exception, e:
                            print >> sys.stderr,'Error putting file: ',e
                            errorflag = True
                            waserrors = True
                        else:
                            self.dispmsg('Successful upload',0)
                            infile.close()
                    except ftplib.all_errors, e:
                        self.dispmsg('Failed to prep file for send. In use?',2)
                        print >> sys.stderr,e
                        errorflag = True
                        waserrors = True

    # GET <filename> <target filename> <program-to-post-process-file> - get the filename from the remote computer and put on the local computer
                elif (not errorflag) and cmdoptions[0] == 'GET':
                    try:
                        outfile = open(cmdoptions[2] + '.tmp',"wb")
                    except:
                        self.dispmsg('Unable to create ' + cmdoptions[2] + ' for GET',2)
                        errorflag = True
                        waserrors = True
                        break
                    try:
                        self.dispmsg('Waiting for file from host',1)
                        cancel_wait = False
                        self.toggle_cancelbutton(True)
                        remotezsync.delete(cmdoptions[1])
                        while (not cancel_wait) and (remotezsync.size(cmdoptions[1]) == 0):
                            print remotezsync.size(cmdoptions[1]),':', datetime.datetime.now(),
                            time.sleep(3)
                        self.toggle_cancelbutton(False)
                        if cancel_wait:
                            self.dispmsg('Wait cancelled',2)
                            errorflag = True
                            waserrors = True
                        remotezsync.retrbinary("RETR " + cmdoptions[1],outfile.write)
                    except Exception, e :    #ftplib.all_errors
                        self.dispmsg("Error in downloading the remote file.",2)
                        print >> sys.stderr,e
                        errorflag = True
                        outfile.close()
                        waserrors = True
                        break
                    else:
                        self.dispmsg("Successful download",0)
                        outfile.close()
                        if os.path.getsize(cmdoptions[2] + '.tmp') > 0:
                            try:
                                os.rename(cmdoptions[2] + '.tmp',cmdoptions[2])
                                if len(cmdoptions) > 3:
                                    cancel_wait = False
                                    self.toggle_cancelbutton(True)
                                    print >> sys.stderr,''.join(c + ' ' for c in cmdoptions[3:])
                                    self.dispmsg('Running program '+''.join(c + ' ' for c in cmdoptions[3:]),1)
                                    p = Popen(cmdoptions[3:])
                                    while (not cancel_wait) and (p.poll() == None):
                                        time.sleep(3)
                                    self.toggle_cancelbutton(False)
                                    if cancel_wait:
                                        self.dispmsg('Wait cancelled',2)
                                        errorflag = True
                                        waserrors = True
                            except ftplib.all_errors, e:
                                self.dispmsg('Rename of temp file failed. In use?',3)
                                print >> sys.stderr,e
                                errorflag = True
                                waserrors = True
                        else:
                            self.dispmsg('File downloaded was empty. Skipping to next checkpoint',2)
                            errorflag = True
                            waserrors = True
    # RUN <fully qualified program name>
                elif (not errorflag) and cmdoptions[0] == 'RUN':
                    os.system(cmdoptions[1])
            remotezsync.close()
            if syncmanual:
                cmdfile.close()
            if waserrors:
                color = 2
                comptype = 'with errors'
            else:
                comptype = ''
                color = 3
            self.dispmsg('Command file processing completed '+comptype,color)
            self.restore_buttons()
        except ftplib.all_errors, e :
            self.dispmsg( 'Connection failed',2)
            print >> sys.stderr,e
            self.restore_buttons()
#            return

# Cancel waiting
def cb_cancel(b):
    global cancel_wait
    cancel_wait = True

# Do the sync
def cb_sync(b):
# Open FTP connection
# Text changed in the IPPrompt combobox
    global ftpthread
    sync_btn.set_sensitive(False)
    parmblock.commandfile = commandfilemain.get_text()
    parmblock.addressentry = addressprompt.get_active()
    parmblock.address = addressprompt.get_active_text()
    if parmblock.addressentry < 0 :
        addresses.insert(0,[parmblock.address])
        print 'select <0'
        parmblock.addressentry = 0
    for i in addresses:
        print i[0]

    if len(addresses) > 5:
        addresses.remove(addresses.get_iter(5))
    ftpthread = ftpsync()
    ftpthread.start()
#    sync_btn.set_sensitive(True)
#    print 'ended'

# Define the saved parameters
class parmblock_model:
    address = ''
    addressentry = None
    port='5962'
    userid=''
    password=''
    syncopt=[True,True,True,True,True]

################################################################################################################
# Main code starts here
root, vb=application_setup('zSync', 'zSync','.zSync')
print >> sys.stderr,version_long
ftpthread = None
synccmds = [['# This is for zTodo','PUT zToDo.db /home/user/.zToDo/','GET zTodonew.db /home/user/.zToDo/zToDo.db','CHECKPOINT'],
  		    ['# This is for zCalSync','PUT zcaldump.db /home/user/.gpe/ /usr/bin/zCalSync -stage1','GET zcalsyncnew.db /home/user/.gpe/zcalsync.db /usr/bin/zCalSync -stage2','CHECKPOINT'],
 		    ['# This is for the Expense application','PUT expense.db /home/user/.bramblesoft/expense/','GET expensenew.db /home/user/.bramblesoft/expense/expense.db','CHECKPOINT'],
		    ['# This is for zContactSync','PUT zcontactsdump.db /home/user/.gpe/ /usr/bin/zContactSync -stage1','GET zcontactsyncnew.db /home/user/.gpe/zcontactsync.db /usr/bin/zContactSync -stage2','CHECKPOINT'],
		    ['# This is for zNoteSync','PUT mnotes.db /home/user/.mPIM/','GET mnotesnew.db /home/user/.mPIM/mnotes.db','CHECKPOINT']]
syncmanual = False
commandfile = ''
# Load the saved parms
addresses = gtk.ListStore(str)
try:
    parmfile = file("zSync.dat","rb")
    parmblock = pickle.load(parmfile)
    saveaddrs=pickle.load(parmfile)
#    print "loading",saveaddrs
    for i in saveaddrs:
        addresses.append([i])
#	parmblock.syncopt = pickle.load(parmfile)
    parmfile.close
except:
    parmblock = parmblock_model()
for i in addresses:
    print 'addr',i[0]
print parmblock.addressentry
if parmblock.userid == '':
    userid='zSync'
else:
    userid = parmblock.userid
if parmblock.password == '':
    password='zSync1956'
else:
    password = parmblock.password
dosync = parmblock.syncopt
# Create the GUI
hb=gtk.HBox()
vb.pack_start(hb, False, False)

# Create menu
menu=gtk.Menu()
i=gtk.MenuItem('Setup Parms')
i.connect('activate',cb_setup_parms)
menu.append(i)
i=gtk.MenuItem('View Log')
i.connect('activate',show_logfile)
menu.append(i)
i=gtk.MenuItem('About')
i.connect('activate',cb_about)
menu.append(i)
i=gtk.MenuItem('Close')
i.connect('activate',lambda x: gtk.main_quit())
menu.append(i)
attach_menu(menu)
# commandfile creates a menu item the same as the detail screen for ztodo - note
#	Also, create menu items in this dialog that inserts templates at the cursor for "ztodo", "zcal", "expense"
#  button to save
# - setup parms: command filename, port number, userid, password - save this in the dat file
#
# Title
txt = gtk.Label('zSync - Sync files/apps with PC')
hb.pack_start(txt, True, False)
# Address combo entry box
hb=gtk.HBox()
vb.pack_start(hb, False, False)
addressprompt = gtk.ComboBoxEntry(addresses,0)
cell = gtk.CellRendererText()
addressprompt.pack_start(cell,True)
if parmblock.addressentry != None:
    addressprompt.set_active(parmblock.addressentry)
#addressprompt.add_attribute(cell,'text',0)
hb.pack_start(addressprompt, True, True)
# "Sync" button
hb=gtk.HBox()
vb.pack_start(hb, False, False)
sync_btn=button_with_image('Sync', gtk.STOCK_REFRESH, cb_sync)
hb.pack_start(sync_btn, True, False)
# Statusbox
hb=gtk.HBox()
vb.pack_start(hb, False, False)
statusframe1 = gtk.Frame()
statusframe = gtk.EventBox()
statusbox = gtk.Label()
statusbox.set_line_wrap(True)
statusframe.add(statusbox)
statusframe1.add(statusframe)
hb.pack_start(statusframe1, True, True)
#statusframe.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse('green'))

# Instructions
hb=gtk.HBox()
vb.pack_start(hb, False, False,10)
txt = gtk.Label('Enter IP address / URL of PC to sync with\nCancel from PC side if necessary')
hb.pack_start(txt, True, False)
# File edit box
hb=gtk.HBox()
vb.pack_start(hb, False, False,2)
cftxt = gtk.Label('Command File:')
hb.pack_start(cftxt, False, False,0)
commandfilemain = gtk.Entry()
commandfilemain.set_text(commandfile)
hb.pack_start(commandfilemain, False, False)
# "Cancel" button
hb=gtk.HBox()
vb.pack_start(hb, False, False)
cancel_btn=button_with_image('Cancel Wait', gtk.STOCK_CANCEL, cb_cancel)
hb.pack_start(cancel_btn, True, False)

root.show_all()
cancel_btn.hide()
commandfilemain.hide()
cftxt.hide()
#root.connect('key-press-event', cb_key_press2)

try:
    gtk.gdk.threads_init()
    gtk.main()
except:
    pass   
print parmblock.addressentry

if ftpthread == None or (not ftpthread.isAlive()):  
    parmfile = open("zSync.dat","wb")
    pickle.dump(parmblock,parmfile)
    saveaddrs=[]
    for i in addresses:
        saveaddrs.append((i[0]))
    pickle.dump(saveaddrs, parmfile)
#    pickle.dump(parmblock.syncopt,parmfile)
    parmfile.close
print >> sys.stderr,'All done'

