OSDN Git Service

Merge branch 'master' of http://git.code.sf.net/p/nevernote/code into develop
[neighbornote/NeighborNote.git] / src / cx / fbn / nevernote / threads / SyncRunner.java
index 81243a3..15b993c 100644 (file)
-/*\r
- * This file is part of NixNote \r
- * Copyright 2009 Randy Baumgarte\r
- * \r
- * This file may be licensed under the terms of of the\r
- * GNU General Public License Version 2 (the ``GPL'').\r
- *\r
- * Software distributed under the License is distributed\r
- * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
- * express or implied. See the GPL for the specific language\r
- * governing rights and limitations.\r
- *\r
- * You should have received a copy of the GPL along with this\r
- * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
- * or write to the Free Software Foundation, Inc.,\r
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
- *\r
-*/\r
-package cx.fbn.nevernote.threads;\r
-\r
-import java.io.BufferedOutputStream;\r
-import java.io.File;\r
-import java.io.FileOutputStream;\r
-import java.io.IOException;\r
-import java.io.InputStream;\r
-import java.io.UnsupportedEncodingException;\r
-import java.net.UnknownHostException;\r
-import java.util.ArrayList;\r
-import java.util.Calendar;\r
-import java.util.Date;\r
-import java.util.GregorianCalendar;\r
-import java.util.HashMap;\r
-import java.util.List;\r
-import java.util.TreeSet;\r
-import java.util.concurrent.LinkedBlockingQueue;\r
-\r
-import org.apache.http.HttpEntity;\r
-import org.apache.http.HttpResponse;\r
-import org.apache.http.NameValuePair;\r
-import org.apache.http.client.ClientProtocolException;\r
-import org.apache.http.client.HttpClient;\r
-import org.apache.http.client.entity.UrlEncodedFormEntity;\r
-import org.apache.http.client.methods.HttpPost;\r
-import org.apache.http.impl.client.DefaultHttpClient;\r
-import org.apache.http.message.BasicNameValuePair;\r
-import org.apache.http.protocol.HTTP;\r
-import org.apache.thrift.TException;\r
-import org.apache.thrift.protocol.TBinaryProtocol;\r
-import org.apache.thrift.transport.THttpClient;\r
-import org.apache.thrift.transport.TTransportException;\r
-\r
-import com.evernote.edam.error.EDAMNotFoundException;\r
-import com.evernote.edam.error.EDAMSystemException;\r
-import com.evernote.edam.error.EDAMUserException;\r
-import com.evernote.edam.notestore.NoteStore;\r
-import com.evernote.edam.notestore.NoteStore.Client;\r
-import com.evernote.edam.notestore.SyncChunk;\r
-import com.evernote.edam.notestore.SyncState;\r
-import com.evernote.edam.type.Data;\r
-import com.evernote.edam.type.LinkedNotebook;\r
-import com.evernote.edam.type.Note;\r
-import com.evernote.edam.type.Notebook;\r
-import com.evernote.edam.type.Resource;\r
-import com.evernote.edam.type.SavedSearch;\r
-import com.evernote.edam.type.SharedNotebook;\r
-import com.evernote.edam.type.Tag;\r
-import com.evernote.edam.type.User;\r
-import com.evernote.edam.userstore.AuthenticationResult;\r
-import com.evernote.edam.userstore.UserStore;\r
-import com.trolltech.qt.core.QByteArray;\r
-import com.trolltech.qt.core.QFile;\r
-import com.trolltech.qt.core.QIODevice.OpenModeFlag;\r
-import com.trolltech.qt.core.QObject;\r
-import com.trolltech.qt.core.QTextCodec;\r
-import com.trolltech.qt.gui.QMessageBox;\r
-\r
-import cx.fbn.nevernote.signals.NoteIndexSignal;\r
-import cx.fbn.nevernote.signals.NoteResourceSignal;\r
-import cx.fbn.nevernote.signals.NoteSignal;\r
-import cx.fbn.nevernote.signals.NotebookSignal;\r
-import cx.fbn.nevernote.signals.SavedSearchSignal;\r
-import cx.fbn.nevernote.signals.StatusSignal;\r
-import cx.fbn.nevernote.signals.SyncSignal;\r
-import cx.fbn.nevernote.signals.TagSignal;\r
-import cx.fbn.nevernote.sql.DatabaseConnection;\r
-import cx.fbn.nevernote.sql.DeletedItemRecord;\r
-import cx.fbn.nevernote.utilities.ApplicationLogger;\r
-\r
-public class SyncRunner extends QObject implements Runnable {\r
-       \r
-       private final ApplicationLogger logger;\r
-               private DatabaseConnection              conn;\r
-               private boolean                                 idle;\r
-               public boolean                                  error;\r
-               public volatile List<String>    errorSharedNotebooks;\r
-               public volatile HashMap<String,String>  errorSharedNotebooksIgnored;\r
-               public volatile boolean                 isConnected;\r
-               public volatile boolean                 keepRunning;\r
-               public volatile String                  authToken;\r
-               private long                                    evernoteUpdateCount;\r
-               private final String userAgent = "NixNote/" + System.getProperty("os.name")\r
-                                                               +"/"+System.getProperty("java.vendor") + "/"\r
-                                                               + System.getProperty("java.version") +";";\r
-               \r
-               public volatile NoteStore.Client                localNoteStore;\r
-               private UserStore.Client                                userStore;\r
-               \r
-               public volatile StatusSignal                    status;\r
-               public volatile TagSignal                               tagSignal;\r
-               public volatile NotebookSignal                  notebookSignal;\r
-               public volatile NoteIndexSignal                 noteIndexSignal;\r
-               public volatile NoteSignal                              noteSignal;\r
-               public volatile SavedSearchSignal               searchSignal;\r
-               public volatile NoteResourceSignal              resourceSignal;\r
-               public volatile SyncSignal                              syncSignal;\r
-               public volatile boolean                                 authRefreshNeeded;\r
-               public volatile boolean                                 syncNeeded;\r
-               public volatile boolean                                 disableUploads;\r
-               public volatile boolean                                 syncDeletedContent;\r
-               private volatile List<String>                   dirtyNoteGuids;\r
-               \r
-           public volatile String username = ""; \r
-           public volatile String password = ""; \r
-               public volatile String userStoreUrl;\r
-//         private final static String consumerKey = "baumgarte"; \r
-//         private final static String consumerSecret = "eb8b5740e17cb55f";\r
-           public String noteStoreUrlBase;\r
-           private THttpClient userStoreTrans;\r
-           private TBinaryProtocol userStoreProt;\r
-           //private AuthenticationResult authResult;\r
-           private AuthenticationResult linkedAuthResult;\r
-           private User user; \r
-//         private long authTimeRemaining;\r
-           public long authRefreshTime;\r
-           public long failedRefreshes = 0;\r
-           public  THttpClient noteStoreTrans;\r
-           public TBinaryProtocol noteStoreProt;\r
-           public String noteStoreUrl;\r
-           public long sequenceDate;\r
-           public int updateSequenceNumber;\r
-           private boolean refreshNeeded;\r
-           private volatile LinkedBlockingQueue<String> workQueue;\r
-               private static int MAX_QUEUED_WAITING = 1000;\r
-               String dbuid;\r
-               String dburl;\r
-               String indexUrl;\r
-               String resourceUrl;\r
-               String dbpswd;\r
-               String dbcpswd;\r
-               private final TreeSet<String> ignoreTags;\r
-               private final TreeSet<String> ignoreNotebooks;\r
-               private final TreeSet<String> ignoreLinkedNotebooks;\r
-               private HashMap<String,String> badTagSync;\r
-       \r
-               \r
-               \r
-       public SyncRunner(String logname, String u, String i, String r, String uid, String pswd, String cpswd) {\r
-               logger = new ApplicationLogger(logname);\r
-               \r
-               noteSignal = new NoteSignal();\r
-               status = new StatusSignal();\r
-               tagSignal = new TagSignal();\r
-               notebookSignal = new NotebookSignal();\r
-               noteIndexSignal = new NoteIndexSignal();\r
-               noteSignal = new NoteSignal();\r
-               searchSignal = new SavedSearchSignal();\r
-               syncSignal = new SyncSignal();\r
-               resourceSignal = new NoteResourceSignal();\r
-               resourceUrl = r;\r
-               indexUrl = i;\r
-               dbuid = uid;\r
-               dburl = u;\r
-               dbpswd = pswd;\r
-               dbcpswd = cpswd;\r
-//             this.setAutoDelete(false);\r
-               \r
-               isConnected = false;\r
-               syncNeeded = false;\r
-               authRefreshNeeded = false;\r
-               keepRunning = true;\r
-               idle = true;\r
-               disableUploads = false;\r
-               ignoreTags = new TreeSet<String>();\r
-               ignoreNotebooks = new TreeSet<String>();\r
-               ignoreLinkedNotebooks = new TreeSet<String>();\r
-               \r
-//             setAutoDelete(false);\r
-               workQueue=new LinkedBlockingQueue<String>(MAX_QUEUED_WAITING);\r
-       }\r
-       @Override\r
-       public void run() {\r
-               errorSharedNotebooks = new ArrayList<String>();\r
-               errorSharedNotebooksIgnored = new HashMap<String,String>();\r
-               try {\r
-                       logger.log(logger.EXTREME, "Starting thread");\r
-                       conn = new DatabaseConnection(logger, dburl, indexUrl, resourceUrl, dbuid, dbpswd, dbcpswd, 200);\r
-                       while(keepRunning) {\r
-                               logger.log(logger.EXTREME, "Blocking until work is found");\r
-                               String work = workQueue.take();\r
-                               logger.log(logger.LOW, "Dirty Notes Before Sync: " +new Integer(conn.getNoteTable().getDirtyCount()).toString());\r
-                               logger.log(logger.EXTREME, "Work found: " +work);\r
-                               if (work.equalsIgnoreCase("stop")) {\r
-                                       idle=false;\r
-                                       return;\r
-                               }\r
-                               conn.getNoteTable().dumpDirtyNotes();  // Debugging statement\r
-                               idle=false;\r
-                               error=false;\r
-                               if (syncNeeded) {\r
-                                       logger.log(logger.EXTREME, "SyncNeeded is true");\r
-                                       refreshNeeded=false;\r
-                                       sequenceDate = conn.getSyncTable().getLastSequenceDate();\r
-                                       updateSequenceNumber = conn.getSyncTable().getUpdateSequenceNumber();\r
-                                       try {\r
-                                               logger.log(logger.EXTREME, "Beginning sync");\r
-                                               evernoteSync(localNoteStore);\r
-                                               logger.log(logger.EXTREME, "Sync finished");\r
-                                       } catch (UnknownHostException e) {\r
-                                               status.message.emit(e.getMessage());\r
-                                       }\r
-                               }\r
-                               idle=true;\r
-                               logger.log(logger.EXTREME, "Signaling refresh finished.  refreshNeeded=" +refreshNeeded);\r
-                               syncSignal.finished.emit(refreshNeeded);\r
-                               if (error) {\r
-                                       syncSignal.errorDisconnect.emit();\r
-                                       status.message.emit(tr("Error synchronizing - see log for details."));\r
-                               }\r
-                               logger.log(logger.LOW, "Dirty Notes After Sync: " +new Integer(conn.getNoteTable().getDirtyCount()).toString());\r
-                               conn.getNoteTable().dumpDirtyNotes();\r
-                               logger.log(logger.LOW, "---");\r
-                       }\r
-               }       \r
-               catch (InterruptedException e1) {\r
-                       e1.printStackTrace();\r
-               }\r
-               conn.dbShutdown();\r
-       }\r
-\r
-       \r
-       public DatabaseConnection getConnection() {\r
-               return conn;\r
-       }\r
-\r
-       public boolean isIdle() {\r
-               return idle;\r
-       }\r
-\r
-\r
-       public void setConnected(boolean c) {\r
-               isConnected = c;\r
-       }\r
-       public void setKeepRunning(boolean r) {\r
-               logger.log(logger.EXTREME, "Setting keepRunning=" +r);\r
-               keepRunning = r;\r
-       }\r
-       public void setNoteStore(NoteStore.Client c) {\r
-               logger.log(logger.EXTREME, "Setting NoteStore in sync thread");\r
-               localNoteStore = c;\r
-       }\r
-       public void setUserStore(UserStore.Client c) {\r
-               logger.log(logger.EXTREME, "Setting UserStore in sync thread");\r
-               userStore = c;\r
-       }\r
-\r
-       public void setEvernoteUpdateCount(long s) {\r
-               logger.log(logger.EXTREME, "Setting Update Count in sync thread");\r
-               evernoteUpdateCount = s;\r
-       }\r
-       \r
-       //***************************************************************\r
-    //***************************************************************\r
-    //** These functions deal with Evernote communications\r
-    //***************************************************************\r
-    //***************************************************************\r
-       // Synchronize changes with Evernote\r
-       @SuppressWarnings("unused")\r
-       private void evernoteSync(Client noteStore) throws java.net.UnknownHostException {\r
-               logger.log(logger.HIGH, "Entering SyncRunner.evernoteSync");\r
-               \r
-               // Rebuild list of tags & notebooks to ignore\r
-               ignoreNotebooks.clear();\r
-               List<String> ignore = conn.getSyncTable().getIgnoreRecords("NOTEBOOK");\r
-               for (int i=0; i<ignore.size(); i++) \r
-                       ignoreNotebooks.add(ignore.get(i));\r
-               \r
-               ignore.clear();\r
-               ignore = conn.getSyncTable().getIgnoreRecords("LINKEDNOTEBOOK");\r
-               for (int i=0; i<ignore.size(); i++) \r
-                       ignoreLinkedNotebooks.add(ignore.get(i));\r
-               \r
-               ignoreTags.clear();\r
-               ignore = conn.getSyncTable().getIgnoreRecords("TAG");\r
-               for (int i=0; i<ignore.size(); i++) \r
-                       ignoreTags.add(ignore.get(i));\r
-\r
-               // Make sure we are connected & should keep running\r
-               if (isConnected && keepRunning) {\r
-                       error = false;\r
-                       logger.log(logger.EXTREME, "Synchronizing with Evernote");\r
-                       status.message.emit(tr("Synchronizing with Evernote"));\r
-                       \r
-                       // Get user information\r
-                       try {\r
-                               logger.log(logger.EXTREME, "getting user from userstore");\r
-                               User user = userStore.getUser(authToken);\r
-                               logger.log(logger.EXTREME, "Saving user information");\r
-                               syncSignal.saveUserInformation.emit(user);\r
-                       } catch (EDAMUserException e1) {\r
-                               e1.printStackTrace();\r
-                               status.message.emit(tr("User exception getting user account information.  Aborting sync and disconnecting"));\r
-                               syncSignal.errorDisconnect.emit();\r
-                               error = true;\r
-                               enDisconnect();\r
-                               return;\r
-                       } catch (EDAMSystemException e1) {\r
-                               e1.printStackTrace();\r
-                               status.message.emit(tr("System error user account information.  Aborting sync and disconnecting!"));\r
-                               syncSignal.errorDisconnect.emit();\r
-                               error = true;\r
-                               enDisconnect();\r
-                               return;\r
-                       } catch (TException e1) {\r
-                               e1.printStackTrace();\r
-                               syncSignal.errorDisconnect.emit();\r
-                               error = true;\r
-                               status.message.emit(tr("Transaction error getting user account information.  Aborting sync and disconnecting!"));\r
-                               enDisconnect();\r
-                               return;\r
-                       }\r
-                       \r
-                       // Get sync state\r
-                       SyncState syncState = null;\r
-                       try {   \r
-                               logger.log(logger.EXTREME, "Getting sync state");\r
-                               syncState = noteStore.getSyncState(authToken);  \r
-                               syncSignal.saveUploadAmount.emit(syncState.getUploaded());\r
-                               syncSignal.saveEvernoteUpdateCount.emit(syncState.getUpdateCount());\r
-                               evernoteUpdateCount = syncState.getUpdateCount();\r
-                       } catch (EDAMUserException e) {\r
-                               e.printStackTrace();\r
-                               status.message.emit(tr("Error getting sync state! Aborting sync and disconnecting!"));\r
-                               syncSignal.errorDisconnect.emit();\r
-                               enDisconnect();\r
-                               return;\r
-                       } catch (EDAMSystemException e) {\r
-                               e.printStackTrace();\r
-                               status.message.emit(tr("Error getting sync state! Aborting sync and disconnecting!"));\r
-                               syncSignal.errorDisconnect.emit();\r
-                               enDisconnect();\r
-                               return;\r
-                       } catch (TException e) {\r
-                               e.printStackTrace();\r
-                               status.message.emit(tr("Error getting sync state! Aborting sync and disconnecting!"));\r
-                               syncSignal.errorDisconnect.emit();\r
-                               enDisconnect();\r
-                               return;\r
-                       }\r
-                       \r
-                       if (syncState == null) {\r
-                               logger.log(logger.EXTREME, "Sync State is null");\r
-                               status.message.emit(tr("Syncronization Error!"));\r
-                               return;\r
-                       }\r
-\r
-                       // Determine what to do. \r
-                       // If we need to do a full sync.\r
-                       logger.log(logger.LOW, "Full Sequence Before: " +syncState.getFullSyncBefore());\r
-                       logger.log(logger.LOW, "Last Sequence Date: " +sequenceDate);\r
-                       logger.log(logger.LOW, "Var Last Sequence Number: " +updateSequenceNumber);\r
-                       logger.log(logger.LOW, "DB Last Sequence Number: " + conn.getSyncTable().getUpdateSequenceNumber());\r
-                       if (syncState.getFullSyncBefore() > sequenceDate) {\r
-                               logger.log(logger.EXTREME, "Full sequence date has expired");\r
-                               sequenceDate = 0;\r
-                               conn.getSyncTable().setLastSequenceDate(0);\r
-                               updateSequenceNumber = 0;\r
-                               conn.getSyncTable().setUpdateSequenceNumber(0);\r
-                       }\r
-                       // Check for "special" sync instructions\r
-                       String syncLinked = conn.getSyncTable().getRecord("FullLinkedNotebookSync");\r
-                       String syncShared = conn.getSyncTable().getRecord("FullSharedNotebookSync");\r
-                       String syncNotebooks = conn.getSyncTable().getRecord("FullNotebookSync");\r
-                       String syncInkNoteImages = conn.getSyncTable().getRecord("FullInkNoteImageSync");\r
-                       if (syncLinked != null) {\r
-                               downloadAllLinkedNotebooks(localNoteStore);\r
-                       }\r
-                       if (syncShared != null) {\r
-                               downloadAllSharedNotebooks(localNoteStore);\r
-                       }\r
-                       if (syncNotebooks != null) {\r
-                               downloadAllNotebooks(localNoteStore);\r
-                       }\r
-                       \r
-                       if (syncInkNoteImages != null) {\r
-                               List<String> guids = conn.getNoteTable().noteResourceTable.findInkNotes();\r
-                               for (int i=0; i<guids.size(); i++) {\r
-                                       downloadInkNoteImage(guids.get(i), authToken);\r
-                               }\r
-                               conn.getSyncTable().deleteRecord("FullInkNoteImageSync");\r
-                       }\r
-                       \r
-                       // If there are remote changes\r
-                       logger.log(logger.LOW, "Update Count: " +syncState.getUpdateCount());\r
-                       logger.log(logger.LOW, "Last Update Count: " +updateSequenceNumber);\r
-                       \r
-                       if (syncState.getUpdateCount() > updateSequenceNumber) {\r
-                               logger.log(logger.EXTREME, "Refresh needed is true");\r
-                               refreshNeeded = true;\r
-                               logger.log(logger.EXTREME, "Downloading changes");\r
-                               syncRemoteToLocal(localNoteStore);\r
-                       }\r
-                       \r
-                       //*****************************************\r
-                       //* Sync linked/shared notebooks \r
-                       //*****************************************\r
-                       syncLinkedNotebooks();\r
-                       //conn.getNoteTable().getDirty();\r
-                       //disableUploads = true;   /// DELETE THIS LINE!!!!\r
-                       if (!disableUploads) {\r
-                               logger.log(logger.EXTREME, "Uploading changes");\r
-                               // Synchronize remote changes\r
-                               if (!error)\r
-                                       syncExpunged(localNoteStore);\r
-                               if (!error)\r
-                                       syncLocalTags(localNoteStore);\r
-                               if (!error)\r
-                                       syncLocalNotebooks(localNoteStore);\r
-                               if (!error)\r
-                                       syncLocalLinkedNotebooks(localNoteStore);\r
-                               if (!error) \r
-                                       syncDeletedNotes(localNoteStore);\r
-                               if (!error)\r
-                                       syncLocalNotes();\r
-                               if (!error)\r
-                                       syncLocalSavedSearches(localNoteStore);\r
-                       }\r
-                       \r
-                       status.message.emit(tr("Cleaning up"));\r
-                       List<String> notes = conn.getNoteTable().expungeIgnoreSynchronizedNotes(conn.getSyncTable().getIgnoreRecords("NOTEBOOK"), \r
-                                       conn.getSyncTable().getIgnoreRecords("TAG"), conn.getSyncTable().getIgnoreRecords("LINKEDNOTEBOOK"));\r
-                       if (notes.size() > 0)\r
-                               syncSignal.refreshLists.emit();\r
-                       \r
-                       //*****************************************\r
-                       //* End of synchronization\r
-                       //*****************************************\r
-                       if (refreshNeeded)\r
-                               syncSignal.refreshLists.emit();\r
-                       \r
-                       if (!error) {\r
-                               logger.log(logger.LOW, "Sync completed.  Errors=" +error);\r
-                               if (!disableUploads) \r
-                                       status.message.emit(tr("Synchronizing complete"));\r
-                               else\r
-                                       status.message.emit(tr("Download syncronization complete.  Uploads have been disabled."));\r
-                               \r
-                               logger.log(logger.EXTREME, "Saving sync time");\r
-                               if (syncState.getCurrentTime() > sequenceDate)\r
-                                       sequenceDate = syncState.getCurrentTime();\r
-                               if (syncState.getUpdateCount() > updateSequenceNumber)\r
-                                       updateSequenceNumber = syncState.getUpdateCount();\r
-                               conn.getSyncTable().setLastSequenceDate(sequenceDate);\r
-                               conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);\r
-                       }\r
-               }\r
-               logger.log(logger.HIGH, "Leaving SyncRunner.evernoteSync");\r
-       }\r
-       \r
-       // Sync deleted items with Evernote\r
-       private void syncExpunged(Client noteStore) {\r
-               logger.log(logger.HIGH, "Entering SyncRunner.syncExpunged");\r
-               \r
-               List<DeletedItemRecord> expunged = conn.getDeletedTable().getAllDeleted();\r
-               boolean error = false;\r
-               for (int i=0; i<expunged.size() && keepRunning; i++) {\r
-\r
-//                     if (authRefreshNeeded)\r
-//                             if (!refreshConnection())\r
-//                                     return;\r
-\r
-                       try {\r
-                               if (expunged.get(i).type.equalsIgnoreCase("TAG")) {\r
-                                       logger.log(logger.EXTREME, "Tag expunged");\r
-                                       conn.getDeletedTable().expungeDeletedItem(expunged.get(i).guid, "TAG"); \r
-                                       updateSequenceNumber = noteStore.expungeTag(authToken, expunged.get(i).guid);\r
-                                       conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);\r
-                                       conn.getSyncTable().setLastSequenceDate(sequenceDate);\r
-                                       conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);                              \r
-                               }\r
-                               if      (expunged.get(i).type.equalsIgnoreCase("NOTEBOOK")) {\r
-                                       logger.log(logger.EXTREME, "Notebook expunged");\r
-                                       conn.getDeletedTable().expungeDeletedItem(expunged.get(i).guid, "NOTEBOOK");\r
-                                       updateSequenceNumber = noteStore.expungeNotebook(authToken, expunged.get(i).guid);\r
-                                       conn.getSyncTable().setLastSequenceDate(sequenceDate);\r
-                                       conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);\r
-                               }\r
-                               if (expunged.get(i).type.equalsIgnoreCase("NOTE")) {\r
-                                       logger.log(logger.EXTREME, "Note expunged");\r
-                                       conn.getDeletedTable().expungeDeletedItem(expunged.get(i).guid, "NOTE");\r
-                                       updateSequenceNumber = noteStore.deleteNote(authToken, expunged.get(i).guid);\r
-                                       refreshNeeded = true;\r
-                                       conn.getSyncTable().setLastSequenceDate(sequenceDate);\r
-                                       conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);\r
-                               }\r
-                               if (expunged.get(i).type.equalsIgnoreCase("SAVEDSEARCH")) {\r
-                                       logger.log(logger.EXTREME, "saved search expunged");\r
-                                       conn.getDeletedTable().expungeDeletedItem(expunged.get(i).guid, "SAVEDSEARCH");\r
-                                       updateSequenceNumber = noteStore.expungeSearch(authToken, expunged.get(i).guid);\r
-                                       conn.getSyncTable().setLastSequenceDate(sequenceDate);\r
-                                       conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);\r
-                               }\r
-                       } catch (EDAMUserException e) {\r
-                               logger.log(logger.LOW, "EDAM User Excepton in syncExpunged: " +expunged.get(i).guid);   // This can happen if we try to delete a deleted note\r
-                       } catch (EDAMSystemException e) {\r
-                               logger.log(logger.LOW, "EDAM System Excepton in syncExpunged: "+expunged.get(i).guid);\r
-                               logger.log(logger.LOW, e.getStackTrace());\r
-                               error=true;\r
-                       } catch (EDAMNotFoundException e) {\r
-                               logger.log(logger.LOW, "EDAM Not Found Excepton in syncExpunged: "+expunged.get(i).guid);\r
-                       } catch (TException e) {\r
-                               logger.log(logger.LOW, "EDAM TExcepton in syncExpunged: "+expunged.get(i).guid);\r
-                               logger.log(logger.LOW, e.getStackTrace());\r
-                               error=true;\r
-                       }\r
-               }\r
-               if (!error)\r
-                       conn.getDeletedTable().expungeAllDeletedRecords();\r
-               \r
-               logger.log(logger.HIGH, "Leaving SyncRunner.syncExpunged");\r
-\r
-       }\r
-       private void syncDeletedNotes(Client noteStore) {\r
-               if (syncDeletedContent)\r
-                       return;\r
-               logger.log(logger.HIGH, "Entering SyncRunner.syncDeletedNotes");\r
-               status.message.emit(tr("Synchronizing deleted notes."));\r
-\r
-               List<Note> notes = conn.getNoteTable().getDirty();\r
-               // Sync the local notebooks with Evernote's\r
-               for (int i=0; i<notes.size() && keepRunning; i++) {\r
-                       \r
-//                     if (authRefreshNeeded)\r
-//                             if (!refreshConnection())\r
-//                                     return;\r
-                       \r
-                       Note enNote = notes.get(i);\r
-                       try {\r
-                               if (enNote.getUpdateSequenceNum() > 0 && (enNote.isActive() == false || enNote.getDeleted() > 0)) {\r
-                                       // Check that the note is valid.  \r
-                                       if (enNote.isActive() == true || enNote.getDeleted() == 0) {\r
-                                               conn.getNoteTable().deleteNote(enNote.getGuid());\r
-                                               enNote = conn.getNoteTable().getNote(enNote.getGuid(), false, false, false, false, false);\r
-                                       }\r
-                                       if (syncDeletedContent) {\r
-                                               logger.log(logger.EXTREME, "Deleted note found & synch content selected");\r
-                                               Note delNote = conn.getNoteTable().getNote(enNote.getGuid(), true, true, true, true, true);\r
-                                               delNote = getNoteContent(delNote);\r
-                                               delNote = noteStore.updateNote(authToken, delNote);\r
-                                               enNote.setUpdateSequenceNum(delNote.getUpdateSequenceNum());\r
-                                               conn.getNoteTable().updateNoteSequence(enNote.getGuid(), enNote.getUpdateSequenceNum());\r
-                                       } else {\r
-                                               logger.log(logger.EXTREME, "Deleted note found & sync content not selected");\r
-                                               int usn = noteStore.deleteNote(authToken, enNote.getGuid());\r
-                                               enNote.setUpdateSequenceNum(usn);\r
-                                               conn.getNoteTable().updateNoteSequence(enNote.getGuid(), enNote.getUpdateSequenceNum());                                                \r
-                                       }\r
-                                       logger.log(logger.EXTREME, "Resetting deleted dirty flag");\r
-                                       conn.getNoteTable().resetDirtyFlag(enNote.getGuid());\r
-                                       updateSequenceNumber = enNote.getUpdateSequenceNum();\r
-                                       logger.log(logger.EXTREME, "Saving sequence number");\r
-                                       conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);\r
-                               }                               \r
-                       } catch (EDAMUserException e) {\r
-                               logger.log(logger.LOW, "*** EDAM User Excepton syncLocalNotes "+e);\r
-                               //status.message.emit("Error sending local note: " +e.getParameter());\r
-                               //logger.log(logger.LOW, e.toString()); \r
-                               //error = true;\r
-                       } catch (EDAMSystemException e) {\r
-                               logger.log(logger.LOW, "*** EDAM System Excepton syncLocalNotes "+e);\r
-                               status.message.emit(tr("Error: ") +e);\r
-                               logger.log(logger.LOW, e.toString());           \r
-                               error = true;\r
-                       } catch (EDAMNotFoundException e) {\r
-                               logger.log(logger.LOW, "*** EDAM Not Found Excepton syncLocalNotes " +e);\r
-                               //status.message.emit("Error deleting local note: " +e +" - Continuing");\r
-                               //logger.log(logger.LOW, e.toString());         \r
-                               //error = true;\r
-                       } catch (TException e) {\r
-                               logger.log(logger.LOW, "*** EDAM TExcepton syncLocalNotes "+e);\r
-                               status.message.emit(tr("Error sending local note: ") +e);\r
-                               logger.log(logger.LOW, e.toString());   \r
-                               error = true;\r
-                       }               \r
-               }\r
-       }\r
-       // Sync notes with Evernote\r
-       private void syncLocalNotes() {\r
-               logger.log(logger.HIGH, "Entering SyncRunner.syncNotes");\r
-               logger.log(logger.LOW, "Dirty local notes found: " +new Integer(conn.getNoteTable().getDirtyCount()).toString());\r
-               status.message.emit(tr("Sending local notes."));\r
-\r
-               List<Note> notes = conn.getNoteTable().getDirty();\r
-               // Sync the local notebooks with Evernote's\r
-               for (int i=0; i<notes.size() && keepRunning; i++) {\r
-                       syncLocalNote(localNoteStore, notes.get(i), authToken);\r
-               }\r
-               logger.log(logger.HIGH, "Leaving SyncRunner.syncNotes");\r
-\r
-       }\r
-       // Sync notes with Evernote\r
-       private void syncLocalNote(Client noteStore, Note enNote, String token) {\r
-               logger.log(logger.HIGH, "Entering SyncRunner.syncNotes");\r
-               status.message.emit(tr("Sending local notes."));\r
-                       \r
-               if (enNote.isActive()) {\r
-                       try {\r
-                               if (enNote.getUpdateSequenceNum() > 0) {\r
-                                       logger.log(logger.EXTREME, "Active dirty note found - non new - " +enNote.getGuid());\r
-                                       logger.log(logger.EXTREME, "Fetching note content");\r
-                                       enNote = getNoteContent(enNote);\r
-                                       logger.log(logger.MEDIUM, "Updating note : "+ enNote.getGuid() +" <title>" +enNote.getTitle()+"</title>");\r
-                                       enNote = noteStore.updateNote(token, enNote);\r
-                               } else { \r
-                                       logger.log(logger.EXTREME, "Active dirty found - new note " +enNote.getGuid());\r
-                                       String oldGuid = enNote.getGuid();\r
-                                       logger.log(logger.MEDIUM, "Fetching note content");\r
-                                       enNote = getNoteContent(enNote);\r
-                                       logger.log(logger.MEDIUM, "Creating note : "+ enNote.getGuid() +" <title>" +enNote.getTitle()+"</title>");\r
-                                       enNote = noteStore.createNote(token, enNote);\r
-                                       logger.log(logger.MEDIUM, "New note Guid : "+ enNote.getGuid() +" <title>" +enNote.getTitle()+"</title>");\r
-                                       noteSignal.guidChanged.emit(oldGuid, enNote.getGuid());\r
-                                       conn.getNoteTable().updateNoteGuid(oldGuid, enNote.getGuid());\r
-                               }\r
-                               updateSequenceNumber = enNote.getUpdateSequenceNum();\r
-                               logger.log(logger.EXTREME, "Saving note");\r
-                               conn.getNoteTable().updateNoteSequence(enNote.getGuid(), enNote.getUpdateSequenceNum());\r
-                               List<Resource> rl = enNote.getResources();\r
-                               logger.log(logger.EXTREME, "Getting note resources");\r
-                               for (int j=0; j<enNote.getResourcesSize() && keepRunning; j++) {\r
-                                       Resource newRes = rl.get(j);\r
-                                       Data d = newRes.getData();\r
-                                       if (d!=null) {  \r
-                                               logger.log(logger.EXTREME, "Calculating resource hash");\r
-                                               String hash = byteArrayToHexString(d.getBodyHash());\r
-                                               logger.log(logger.EXTREME, "updating resources by hash");\r
-                                               String oldGuid = conn.getNoteTable().noteResourceTable.getNoteResourceGuidByHashHex(enNote.getGuid(), hash);\r
-                                               conn.getNoteTable().updateNoteResourceGuidbyHash(enNote.getGuid(), newRes.getGuid(), hash);\r
-                                               resourceSignal.resourceGuidChanged.emit(enNote.getGuid(), oldGuid, newRes.getGuid());\r
-                                       }\r
-                               }\r
-                               logger.log(logger.EXTREME, "Resetting note dirty flag");\r
-                               conn.getNoteTable().resetDirtyFlag(enNote.getGuid());\r
-                               updateSequenceNumber = enNote.getUpdateSequenceNum();\r
-                               logger.log(logger.EXTREME, "Emitting note sequence number change");\r
-                               conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);\r
-\r
-                       } catch (EDAMUserException e) {\r
-                               logger.log(logger.LOW, "*** EDAM User Excepton syncLocalNotes "+e);\r
-                               status.message.emit(tr("Error sending local note: ")     +e.getParameter());\r
-                               logger.log(logger.LOW, e.toString());   \r
-                               error = true;\r
-                       } catch (EDAMSystemException e) {\r
-                               logger.log(logger.LOW, "*** EDAM System Excepton syncLocalNotes "+e);\r
-                               status.message.emit(tr("Error: ") +e);\r
-                               logger.log(logger.LOW, e.toString());           \r
-                               error = true;\r
-                       } catch (EDAMNotFoundException e) {\r
-                               logger.log(logger.LOW, "*** EDAM Not Found Excepton syncLocalNotes " +e);\r
-                               status.message.emit(tr("Error sending local note: ") +e);\r
-                               logger.log(logger.LOW, e.toString());   \r
-                               error = true;\r
-                       } catch (TException e) {\r
-                               logger.log(logger.LOW, "*** EDAM TExcepton syncLocalNotes "+e);\r
-                               status.message.emit(tr("Error sending local note: ") +e);\r
-                               logger.log(logger.LOW, e.toString());   \r
-                               error = true;\r
-                       }\r
-               }\r
-               logger.log(logger.HIGH, "Leaving SyncRunner.syncLocalNote");\r
-\r
-       }\r
-\r
-       // Sync Notebooks with Evernote\r
-       private void syncLocalNotebooks(Client noteStore) {\r
-               logger.log(logger.HIGH, "Entering SyncRunner.syncLocalNotebooks");\r
-               \r
-               status.message.emit(tr("Sending local notebooks."));\r
-               List<Notebook> remoteList = new ArrayList<Notebook>();\r
-               try {\r
-                       logger.log(logger.EXTREME, "Getting remote notebooks to compare with local");\r
-                       remoteList = noteStore.listNotebooks(authToken);\r
-               } catch (EDAMUserException e1) {\r
-                       logger.log(logger.LOW, "*** EDAM User Excepton syncLocalNotebooks getting remote Notebook List");\r
-                       status.message.emit(tr("Error: ") +e1);\r
-                       logger.log(logger.LOW, e1.toString());          \r
-                       error = true;\r
-               } catch (EDAMSystemException e1) {\r
-                       logger.log(logger.LOW, "*** EDAM System Excepton syncLocalNotebooks getting remote Notebook List");\r
-                       status.message.emit(tr("Error: ") +e1);\r
-                       logger.log(logger.LOW, e1.toString());  \r
-                       error = true;\r
-               } catch (TException e1) {\r
-                       logger.log(logger.LOW, "*** EDAM Transaction Excepton syncLocalNotebooks getting remote Notebook List");\r
-                       status.message.emit(tr("Error: ") +e1);\r
-                       logger.log(logger.LOW, e1.toString());  \r
-                       error = true;\r
-               }\r
-               logger.log(logger.EXTREME, "Getting local dirty notebooks");\r
-               List<Notebook> notebooks = conn.getNotebookTable().getDirty();\r
-               int sequence;\r
-               // Sync the local notebooks with Evernote's\r
-               for (int i=0; i<notebooks.size() && keepRunning; i++) {\r
-                       \r
-//                     if (authRefreshNeeded)\r
-//                             if (!refreshConnection())\r
-//                                     return;\r
-                       \r
-                       Notebook enNotebook = notebooks.get(i);\r
-                       try {\r
-                               if (enNotebook.getUpdateSequenceNum() > 0) {\r
-                                       logger.log(logger.EXTREME, "Existing notebook is dirty");\r
-                                       sequence = noteStore.updateNotebook(authToken, enNotebook);\r
-                               } else {\r
-                                       logger.log(logger.EXTREME, "New dirty notebook found");\r
-                                       String oldGuid = enNotebook.getGuid();\r
-                                       boolean found = false;\r
-                                       \r
-                                       // Look for a notebook with the same name.  If one is found, we don't need \r
-                                       // to create another one\r
-                                       logger.log(logger.EXTREME, "Looking for matching notebook name");\r
-                                       for (int k=0; k<remoteList.size() && !found && keepRunning; k++) {\r
-                                               if (remoteList.get(k).getName().equalsIgnoreCase(enNotebook.getName())) {\r
-                                                       enNotebook = remoteList.get(k);\r
-                                                       logger.log(logger.EXTREME, "Matching notebook found");\r
-                                                       found = true;\r
-                                               }\r
-                                       }\r
-                                       if (!found)\r
-                                               enNotebook = noteStore.createNotebook(authToken, enNotebook);\r
-                                       \r
-                                       logger.log(logger.EXTREME, "Updating notebook in database");\r
-                                       conn.getNotebookTable().updateNotebookGuid(oldGuid, enNotebook.getGuid());\r
-                                       sequence = enNotebook.getUpdateSequenceNum();\r
-                               }\r
-                               logger.log(logger.EXTREME, "Updating notebook sequence in database");\r
-                               conn.getNotebookTable().updateNotebookSequence(enNotebook.getGuid(), sequence);\r
-                               logger.log(logger.EXTREME, "Resetting dirty flag in notebook");\r
-                               conn.getNotebookTable().resetDirtyFlag(enNotebook.getGuid());\r
-                               updateSequenceNumber = sequence;\r
-                               logger.log(logger.EXTREME, "Emitting sequence number to main thread");\r
-                               conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);\r
-                       } catch (EDAMUserException e) {\r
-                               logger.log(logger.LOW, "*** EDAM User Excepton syncLocalNotebooks");\r
-                               logger.log(logger.LOW, e.toString() + ": Stack : " +enNotebook.getStack());     \r
-                               error = true;\r
-                       } catch (EDAMSystemException e) {\r
-                               logger.log(logger.LOW, "*** EDAM System Excepton syncLocalNotebooks");\r
-                               logger.log(logger.LOW, e.toString());           \r
-                               error = true;\r
-                       } catch (EDAMNotFoundException e) {\r
-                               logger.log(logger.LOW, "*** EDAM Not Found Excepton syncLocalNotebooks");\r
-                               logger.log(logger.LOW, e.toString());           \r
-                               error = true;\r
-                       } catch (TException e) {\r
-                               logger.log(logger.LOW, "*** EDAM TExcepton syncLocalNotebooks");\r
-                               logger.log(logger.LOW, e.toString());   \r
-                               error = true;\r
-                       }               \r
-               }\r
-               logger.log(logger.HIGH, "Leaving SyncRunner.syncLocalNotebooks");\r
-\r
-       }\r
-       // Sync Tags with Evernote\r
-       private void syncLocalTags(Client noteStore) {\r
-               logger.log(logger.HIGH, "Entering SyncRunner.syncLocalTags");\r
-               List<Tag> remoteList = new ArrayList<Tag>();\r
-               status.message.emit(tr("Sending local tags."));\r
-               \r
-               try {\r
-                       logger.log(logger.EXTREME, "Getting remote tags to compare names with the local tags");\r
-                       remoteList = noteStore.listTags(authToken);\r
-               } catch (EDAMUserException e1) {\r
-                       logger.log(logger.LOW, "*** EDAM User Excepton syncLocalTags getting remote Tag List");\r
-                       status.message.emit(tr("Error: ") +e1);\r
-                       logger.log(logger.LOW, e1.toString());  \r
-                       error = true;\r
-               } catch (EDAMSystemException e1) {\r
-                       logger.log(logger.LOW, "*** EDAM System Excepton syncLocalTags getting remote Tag List");\r
-                       status.message.emit(tr("Error: ") +e1);\r
-                       logger.log(logger.LOW, e1.toString());          \r
-                       error = true;\r
-               } catch (TException e1) {\r
-                       logger.log(logger.LOW, "*** EDAM Transaction Excepton syncLocalTags getting remote Tag List");\r
-                       status.message.emit(tr("Error: ") +e1);\r
-                       logger.log(logger.LOW, e1.toString());  \r
-                       error = true;\r
-               }               \r
-               \r
-               int sequence;\r
-               \r
-               if (badTagSync == null)\r
-                       badTagSync = new HashMap<String,String>();\r
-               else\r
-                       badTagSync.clear();\r
-               \r
-               Tag enTag = findNextTag();\r
-               \r
-               // This is a hack.  Sometimes this function goes flookey and goes into a \r
-               // perpetual loop.  This causes  NeverNote to flood Evernote's servers.\r
-               // This is a safety valve to prevent unlimited loops.\r
-               int maxCount = conn.getTagTable().getDirty().size()+10;\r
-               int loopCount = 0;\r
-               \r
-               while(enTag!=null && loopCount < maxCount) {\r
-                       loopCount++;\r
-//                     if (authRefreshNeeded)\r
-//                             if (!refreshConnection())\r
-//                                     return;\r
-\r
-                       try {\r
-                               if (enTag.getUpdateSequenceNum() > 0) {\r
-                                       logger.log(logger.EXTREME, "Updating tag");\r
-                                       sequence = noteStore.updateTag(authToken, enTag);\r
-                               } else {\r
-                                       \r
-                                       // Look for a tag with the same name.  If one is found, we don't need \r
-                                       // to create another one\r
-                                       logger.log(logger.EXTREME, "New tag.  Comparing with remote names");\r
-                                       boolean found = false;\r
-                                       String oldGuid = enTag.getGuid();\r
-                                       for (int k=0; k<remoteList.size() && !found && keepRunning; k++) {\r
-                                               if (remoteList.get(k).getName().equalsIgnoreCase(enTag.getName())) {\r
-                                                       conn.getTagTable().updateTagGuid(enTag.getGuid(), remoteList.get(k).getGuid());\r
-                                                       enTag = remoteList.get(k);\r
-                                                       logger.log(logger.EXTREME, "Matching tag name found");\r
-                                                       found = true;\r
-                                               }\r
-                                       }\r
-                                       if (!found)\r
-                                               enTag = noteStore.createTag(authToken, enTag);\r
-                                       else\r
-                                               enTag.setUpdateSequenceNum(noteStore.updateTag(authToken,enTag));\r
-                                       sequence = enTag.getUpdateSequenceNum();\r
-                                       if (!oldGuid.equals(enTag.getGuid())) {\r
-                                               logger.log(logger.EXTREME, "Updating tag guid");\r
-                                               conn.getTagTable().updateTagGuid(oldGuid, enTag.getGuid());\r
-                                       }\r
-                               }\r
-                               logger.log(logger.EXTREME, "Updating tag sequence number");\r
-                               conn.getTagTable().updateTagSequence(enTag.getGuid(), sequence);\r
-                               logger.log(logger.EXTREME, "Resetting tag dirty flag");\r
-                               conn.getTagTable().resetDirtyFlag(enTag.getGuid());\r
-                               logger.log(logger.EXTREME, "Emitting sequence number to the main thread.");\r
-                               updateSequenceNumber = sequence;\r
-                               conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);\r
-                       } catch (EDAMUserException e) {\r
-                               logger.log(logger.LOW, "*** EDAM User Excepton syncLocalTags: " +enTag.getName());\r
-                               logger.log(logger.LOW, e.toString());\r
-                               badTagSync.put(enTag.getGuid(),null);\r
-                               error = true;\r
-                       } catch (EDAMSystemException e) {\r
-                               logger.log(logger.LOW, "** EDAM System Excepton syncLocalTags: " +enTag.getName());\r
-                               logger.log(logger.LOW, e.toString());   \r
-                               badTagSync.put(enTag.getGuid(),null);\r
-                               error = true;\r
-                       } catch (EDAMNotFoundException e) {\r
-                               logger.log(logger.LOW, "*** EDAM Not Found Excepton syncLocalTags: " +enTag.getName());\r
-                               logger.log(logger.LOW, e.toString());\r
-                               badTagSync.put(enTag.getGuid(),null);\r
-                               error = true;\r
-                       } catch (TException e) {\r
-                               logger.log(logger.LOW, "*** EDAM TExcepton syncLocalTags: " +enTag.getName());\r
-                               logger.log(logger.LOW, e.toString());\r
-                               badTagSync.put(enTag.getGuid(),null);\r
-                               error = true;\r
-                       }       \r
-                       \r
-                       // Find the next tag\r
-                       logger.log(logger.EXTREME, "Finding next tag");\r
-                       enTag = findNextTag();\r
-               }\r
-               logger.log(logger.HIGH, "Leaving SyncRunner.syncLocalTags");\r
-       }\r
-       private void syncLocalLinkedNotebooks(Client noteStore) {\r
-               logger.log(logger.HIGH, "Entering SyncRunner.syncLocalLinkedNotebooks");\r
-               \r
-               List<String> list = conn.getLinkedNotebookTable().getDirtyGuids();\r
-               for (int i=0; i<list.size(); i++) {\r
-                       LinkedNotebook book = conn.getLinkedNotebookTable().getNotebook(list.get(i));\r
-                       try {\r
-                               noteStore.updateLinkedNotebook(authToken, book);\r
-                       } catch (EDAMUserException e) {\r
-                               logger.log(logger.LOW, "*** EDAM User Excepton syncLocalLinkedNotebooks");\r
-                               status.message.emit(tr("Error: ") +e);\r
-                               logger.log(logger.LOW, e.toString());           \r
-                               error = true;\r
-                               e.printStackTrace();\r
-                       } catch (EDAMNotFoundException e) {\r
-                               logger.log(logger.LOW, "*** EDAM Not Found Excepton syncLocalLinkedNotebooks");\r
-                               status.message.emit(tr("Error: ") +e);\r
-                               logger.log(logger.LOW, e.toString());           \r
-                               error = true;\r
-                               e.printStackTrace();\r
-                       } catch (EDAMSystemException e) {\r
-                               logger.log(logger.LOW, "*** EDAM System Excepton syncLocalLinkedNotebooks");\r
-                               status.message.emit(tr("Error: ") +e);\r
-                               logger.log(logger.LOW, e.toString());           \r
-                               error = true;\r
-                               e.printStackTrace();\r
-                       } catch (TException e) {\r
-                               logger.log(logger.LOW, "*** EDAM TExcepton syncLocalLinkedNotebooks");\r
-                               status.message.emit(tr("Error: ") +e);\r
-                               logger.log(logger.LOW, e.toString());           \r
-                               error = true;\r
-                               e.printStackTrace();\r
-                       }\r
-               }\r
-               logger.log(logger.HIGH, "Leaving SyncRunner.syncLocalLinkedNotebooks");\r
-       }\r
-       // Sync Saved Searches with Evernote\r
-       private void syncLocalSavedSearches(Client noteStore) {\r
-               logger.log(logger.HIGH, "Entering SyncRunner.syncLocalSavedSearches");\r
-               List<SavedSearch> remoteList = new ArrayList<SavedSearch>();\r
-               status.message.emit(tr("Sending saved searches."));\r
-       \r
-               logger.log(logger.EXTREME, "Getting saved searches to compare with local");\r
-               try {\r
-                       remoteList = noteStore.listSearches(authToken);\r
-               } catch (EDAMUserException e1) {\r
-                       logger.log(logger.LOW, "*** EDAM User Excepton syncLocalTags getting remote saved search List");\r
-                       status.message.emit(tr("Error: ") +e1);\r
-                       logger.log(logger.LOW, e1.toString());  \r
-                       error = true;\r
-               } catch (EDAMSystemException e1) {\r
-                       logger.log(logger.LOW, "*** EDAM System Excepton syncLocalTags getting remote saved search List");\r
-                       status.message.emit(tr("Error: ") +e1);\r
-                       logger.log(logger.LOW, e1.toString());          \r
-                       error = true;\r
-               } catch (TException e1) {\r
-                       logger.log(logger.LOW, "*** EDAM Transaction Excepton syncLocalTags getting remote saved search List");\r
-                       status.message.emit(tr("Error: ") +e1);\r
-                       logger.log(logger.LOW, e1.toString());  \r
-                       error = true;\r
-               }               \r
-               \r
-               List<SavedSearch> searches = conn.getSavedSearchTable().getDirty();\r
-               int sequence;\r
-               // Sync the local notebooks with Evernote's\r
-               logger.log(logger.EXTREME, "Beginning to send saved searches");\r
-               for (int i=0; i<searches.size() &&  keepRunning; i++) {\r
-                       \r
-//                     if (authRefreshNeeded)\r
-//                             if (!refreshConnection())\r
-//                                     return;\r
-                       \r
-                       SavedSearch enSearch = searches.get(i);\r
-                       try {\r
-                               if (enSearch.getUpdateSequenceNum() > 0) \r
-                                       sequence = noteStore.updateSearch(authToken, enSearch);\r
-                               else {\r
-                                       logger.log(logger.EXTREME, "New saved search found.");\r
-                                       // Look for a tag with the same name.  If one is found, we don't need \r
-                                       // to create another one\r
-                                       boolean found = false;\r
-                                       logger.log(logger.EXTREME, "Matching remote saved search names with local");\r
-                                       for (int k=0; k<remoteList.size() && !found && keepRunning; k++) {\r
-                                               if (remoteList.get(k).getName().equalsIgnoreCase(enSearch.getName())) {\r
-                                                       enSearch = remoteList.get(k);\r
-                                                       found = true;\r
-                                                       logger.log(logger.EXTREME, "Matching saved search found");\r
-                                                       sequence = enSearch.getUpdateSequenceNum();\r
-                                               }\r
-                                       }\r
-\r
-                                       String oldGuid = enSearch.getGuid();\r
-                                       if (!found)\r
-                                               enSearch = noteStore.createSearch(authToken, enSearch);\r
-                                       sequence = enSearch.getUpdateSequenceNum();\r
-                                       logger.log(logger.EXTREME, "Updating tag guid in local database");\r
-                                       conn.getSavedSearchTable().updateSavedSearchGuid(oldGuid, enSearch.getGuid());\r
-                               }\r
-                               logger.log(logger.EXTREME, "Updating tag sequence in local database");\r
-                               conn.getSavedSearchTable().updateSavedSearchSequence(enSearch.getGuid(), sequence);\r
-                               logger.log(logger.EXTREME, "Resetting tag dirty flag");\r
-                               conn.getSavedSearchTable().resetDirtyFlag(enSearch.getGuid());\r
-                               logger.log(logger.EXTREME, "Emitting sequence number to the main thread.");\r
-                               updateSequenceNumber = sequence;\r
-                               conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);\r
-                       } catch (EDAMUserException e) {\r
-                               logger.log(logger.LOW, "*** EDAM User Excepton syncLocalTags");\r
-                               logger.log(logger.LOW, e.toString());   \r
-                               error = true;\r
-                       } catch (EDAMSystemException e) {\r
-                               logger.log(logger.LOW, "** EDAM System Excepton syncLocalTags");\r
-                               logger.log(logger.LOW, e.toString());   \r
-                               error = true;\r
-                       } catch (EDAMNotFoundException e) {\r
-                               logger.log(logger.LOW, "*** EDAM Not Found Excepton syncLocalTags");\r
-                               logger.log(logger.LOW, e.toString());   \r
-                               error = true;\r
-                       } catch (TException e) {\r
-                               logger.log(logger.LOW, "*** EDAM TExcepton syncLocalTags");\r
-                               logger.log(logger.LOW, e.toString());   \r
-                               error = true;\r
-                       }               \r
-               }\r
-\r
-               logger.log(logger.HIGH, "Entering SyncRunner.syncLocalSavedSearches");\r
-       }       \r
-\r
-       // Sync evernote changes with local database\r
-       private void syncRemoteToLocal(Client noteStore) {\r
-               logger.log(logger.HIGH, "Entering SyncRunner.syncRemoteToLocal");\r
-\r
-               List<Note> dirtyNotes = conn.getNoteTable().getDirty();\r
-               dirtyNoteGuids = new ArrayList<String>();\r
-               for (int i=0; i<dirtyNotes.size() && keepRunning; i++) {\r
-                       dirtyNoteGuids.add(dirtyNotes.get(i).getGuid());\r
-               }\r
-               \r
-               int chunkSize = 10;\r
-               SyncChunk chunk = null;\r
-               boolean fullSync = false;\r
-               boolean more = true;\r
-               \r
-               if (updateSequenceNumber == 0)\r
-                       fullSync = true;\r
-               \r
-               status.message.emit(tr("Downloading 0% complete."));\r
-               \r
-               while(more &&  keepRunning) {\r
-                       \r
-//                     if (authRefreshNeeded)\r
-//                             if (!refreshConnection())\r
-//                                     return;\r
-                       \r
-                       int sequence = updateSequenceNumber;\r
-                       try {\r
-//                             conn.beginTransaction();\r
-                               logger.log(logger.EXTREME, "Getting chunk from Evernote");\r
-                               chunk = noteStore.getSyncChunk(authToken, sequence, chunkSize, fullSync);\r
-                               logger.log(logger.LOW, "Chunk High Sequence: " +chunk.getChunkHighUSN());\r
-                       } catch (EDAMUserException e) {\r
-                               error = true;\r
-                               e.printStackTrace();\r
-                               status.message.emit(e.getMessage());\r
-                       } catch (EDAMSystemException e) {\r
-                               error = true;\r
-                               e.printStackTrace();\r
-                               status.message.emit(e.getMessage());\r
-                       } catch (TException e) {\r
-                               error = true;\r
-                               e.printStackTrace();\r
-                               status.message.emit(e.getMessage());\r
-                       } \r
-                       if (error || chunk == null) \r
-                               return;\r
-                               \r
-               \r
-                       \r
-                       syncRemoteTags(chunk.getTags());\r
-                       syncRemoteSavedSearches(chunk.getSearches());\r
-                       syncRemoteNotebooks(chunk.getNotebooks());\r
-                       syncRemoteNotes(noteStore, chunk.getNotes(), fullSync, authToken);\r
-                       syncRemoteResources(noteStore, chunk.getResources());\r
-                       syncRemoteLinkedNotebooks(chunk.getLinkedNotebooks());\r
-                       \r
-                       // Signal about any updated notes to invalidate the cache\r
-                       for (int i=0; i<chunk.getNotesSize(); i++) \r
-                               noteSignal.noteChanged.emit(chunk.getNotes().get(i).getGuid(), null); \r
-                       syncExpungedNotes(chunk);\r
-                       \r
-                       \r
-                       // Check for more notes\r
-                       if (chunk.getChunkHighUSN() <= updateSequenceNumber) \r
-                               more = false;\r
-                       if (error)\r
-                               more = false;\r
-                       logger.log(logger.EXTREME, "More notes? " +more);\r
-\r
-                       \r
-                       // Save the chunk sequence number\r
-                       if (!error && chunk.getChunkHighUSN() > 0 && keepRunning) {\r
-                               logger.log(logger.EXTREME, "emitting sequence number to main thread");\r
-                               updateSequenceNumber = chunk.getChunkHighUSN();\r
-                               conn.getSyncTable().setLastSequenceDate(chunk.getCurrentTime());\r
-                               conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);\r
-//                             conn.commitTransaction();\r
-                       }\r
-                       \r
-                       \r
-                       if (more) {\r
-                               long pct = chunk.getChunkHighUSN() * 100;\r
-                               conn.getSyncTable().setLastSequenceDate(chunk.getCurrentTime());\r
-                               pct = pct/evernoteUpdateCount;\r
-                               status.message.emit(tr("Downloading ") +new Long(pct).toString()+tr("% complete."));\r
-                       }\r
-//                     conn.commitTransaction();\r
-               }\r
-               logger.log(logger.HIGH, "Leaving SyncRunner.syncRemoteToLocal");\r
-       }\r
-       // Sync expunged notes\r
-       private void syncExpungedNotes(SyncChunk chunk) {\r
-               // Do the local deletes\r
-               logger.log(logger.EXTREME, "Doing local deletes");\r
-               List<String> guid = chunk.getExpungedNotes();\r
-               if (guid != null) {\r
-                       for (int i=0; i<guid.size() && keepRunning; i++) {\r
-                               String notebookGuid = "";\r
-                               Note localNote = conn.getNoteTable().getNote(guid.get(i), false, false, false, false, false);\r
-                               if (localNote != null) {\r
-                                       conn.getNoteTable().updateNoteSequence(guid.get(i), 0);\r
-                                       notebookGuid = localNote.getNotebookGuid();\r
-                               }\r
-                               // If the note is in a local notebook (which means we moved it) or if the \r
-                               // note returned is null (which means it is already deleted or flagged expunged) \r
-                               // we delete it.\r
-                               if (!conn.getNotebookTable().isNotebookLocal(notebookGuid) || localNote == null) {\r
-                                       logger.log(logger.EXTREME, "Expunging local note from database");\r
-                                       conn.getNoteTable().expungeNote(guid.get(i), true, false);\r
-                               }\r
-                       }\r
-               }\r
-               guid = chunk.getExpungedNotebooks();\r
-               if (guid != null)\r
-                       for (int i=0; i<guid.size() && keepRunning; i++) {\r
-                               logger.log(logger.EXTREME, "Expunging local notebook from database");\r
-                               conn.getNotebookTable().expungeNotebook(guid.get(i), false);\r
-                       }\r
-               guid = chunk.getExpungedTags();\r
-               if (guid != null)\r
-                       for (int i=0; i<guid.size() && keepRunning; i++) {\r
-                               logger.log(logger.EXTREME, "Expunging tags from local database");\r
-                               conn.getTagTable().expungeTag(guid.get(i), false);\r
-                       }\r
-               guid = chunk.getExpungedSearches();\r
-               if (guid != null) \r
-                       for (int i=0; i<guid.size() && keepRunning; i++) {\r
-                               logger.log(logger.EXTREME, "Expunging saved search from local database");\r
-                               conn.getSavedSearchTable().expungeSavedSearch(guid.get(i), false);\r
-                       }\r
-               guid = chunk.getExpungedLinkedNotebooks();\r
-               if (guid != null) \r
-                       for (int i=0; i<guid.size() && keepRunning; i++) {\r
-                               logger.log(logger.EXTREME, "Expunging linked notebook from local database");\r
-                               conn.getLinkedNotebookTable().expungeNotebook(guid.get(i), false);\r
-                       }\r
-\r
-       }\r
-       // Sync remote tags\r
-       private void syncRemoteTags(List<Tag> tags) {\r
-               logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteTags");\r
-               if (tags != null) {\r
-                       for (int i=0; i<tags.size() && keepRunning; i++) {\r
-                               String oldGuid;\r
-                               oldGuid = conn.getTagTable().findTagByName(tags.get(i).getName());\r
-                               if (oldGuid != null && !tags.get(i).getGuid().equalsIgnoreCase(oldGuid))\r
-                                       conn.getTagTable().updateTagGuid(oldGuid, tags.get(i).getGuid());\r
-                               conn.getTagTable().syncTag(tags.get(i), false);\r
-                       }\r
-               }\r
-               logger.log(logger.EXTREME, "Leaving SyncRunner.syncRemoteTags");\r
-       }\r
-       // Sync remote saved searches\r
-       private void syncRemoteSavedSearches(List<SavedSearch> searches) {\r
-               logger.log(logger.EXTREME, "Entering SyncRunner.syncSavedSearches");\r
-               if (searches != null) {\r
-                       for (int i=0; i<searches.size() && keepRunning; i++) {\r
-                               String oldGuid;\r
-                               oldGuid = conn.getSavedSearchTable().findSavedSearchByName(searches.get(i).getName());\r
-                               if (oldGuid != null && !searches.get(i).getGuid().equalsIgnoreCase(oldGuid))\r
-                                       conn.getSavedSearchTable().updateSavedSearchGuid(oldGuid, searches.get(i).getGuid());\r
-                               conn.getSavedSearchTable().syncSavedSearch(searches.get(i), false);\r
-                       }\r
-               }\r
-               logger.log(logger.EXTREME, "Leaving SyncRunner.syncSavedSearches");\r
-       }\r
-       // Sync remote linked notebooks\r
-       private void syncRemoteLinkedNotebooks(List<LinkedNotebook> books) {\r
-               logger.log(logger.EXTREME, "Entering SyncRunner.syncLinkedNotebooks");\r
-               if (books != null) {\r
-                       for (int i=0; i<books.size() && keepRunning; i++) {\r
-                               conn.getLinkedNotebookTable().updateNotebook(books.get(i), false); \r
-                       }\r
-               }\r
-               logger.log(logger.EXTREME, "Leaving SyncRunner.syncLinkedNotebooks");\r
-       }\r
-       // Sync remote Notebooks 2\r
-       private void syncRemoteNotebooks(List<Notebook> notebooks) {\r
-               logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteNotebooks");\r
-               if (notebooks != null) {\r
-                       for (int i=0; i<notebooks.size() && keepRunning; i++) {\r
-                               String oldGuid;\r
-                               oldGuid = conn.getNotebookTable().findNotebookByName(notebooks.get(i).getName());\r
-                               if (oldGuid != null && !conn.getNotebookTable().isNotebookLocal(oldGuid) && !notebooks.get(i).getGuid().equalsIgnoreCase(oldGuid))\r
-                                       conn.getNotebookTable().updateNotebookGuid(oldGuid, notebooks.get(i).getGuid());\r
-                               conn.getNotebookTable().syncNotebook(notebooks.get(i), false); \r
-                               \r
-                               // Synchronize shared notebook information\r
-//                             if (notebooks.get(i).getSharedNotebookIdsSize() > 0) {\r
-//                                     conn.getSharedNotebookTable().expungeNotebookByGuid(notebooks.get(i).getGuid(), false);\r
-//                                     for (int j=0; j<notebooks.get(i).getSharedNotebookIdsSize(); j++) {\r
-//                                             syncRemoteSharedNotebook(notebooks.get(i).getGuid(), notebooks.get(i).getSharedNotebookIds().get(j), authToken);\r
-//                                     }\r
-//                             }\r
-                       }\r
-               }                       \r
-               logger.log(logger.EXTREME, "Leaving SyncRunner.syncRemoteNotebooks");\r
-       }\r
-       // Sync remote shared notebook\r
-//     private void syncRemoteSharedNotebook(String guid, Long id, String token) {\r
-//             List<SharedNotebook> books = noteStore.getSharedNotebookByAuth(authToken);\r
-//     }\r
-       // Sync remote Resources\r
-       private void syncRemoteResources(Client noteStore, List<Resource> resource) {\r
-               logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteResources");\r
-               if (resource != null) {\r
-                       for (int i=0; i<resource.size() && keepRunning; i++) {\r
-                               syncRemoteResource(noteStore, resource.get(i), authToken);\r
-                       }\r
-               }\r
-               logger.log(logger.EXTREME, "Leaving SyncRunner.syncRemoteResources");\r
-       }\r
-       // Sync remote resource\r
-       private void syncRemoteResource(Client noteStore, Resource resource, String authToken) {\r
-               // This is how the logic for this works.\r
-               // 1.) If the resource is not in the local database, we add it.\r
-               // 2.) If a copy of the resource is in the local database and the note isn't dirty, we update the local copy\r
-               // 3.) If a copy of the resource is in the local databbase and it is dirty and the hash doesn't match, we ignore it because there\r
-               //     is a conflict.  The note conflict should get a copy of the resource at that time.\r
-               \r
-               Note n = conn.getNoteTable().getNote(resource.getNoteGuid(), false, false, false, false, false);\r
-               if (n!=null) {\r
-                       logger.log(logger.HIGH, "Resource for note " +n.getGuid() +" : " +n.getTitle());\r
-               }\r
-               boolean saveNeeded = false;\r
-               /* #1 */                Resource r = getEvernoteResource(noteStore, resource.getGuid(), true,true,true, authToken);\r
-                                               Resource l = conn.getNoteTable().noteResourceTable.getNoteResource(r.getGuid(), false);\r
-                                               if (l == null) {\r
-                                                       logger.log(logger.HIGH, "Local resource not found");\r
-                                                       saveNeeded = true;\r
-                                               } else {\r
-               /* #2 */                        boolean isNoteDirty = conn.getNoteTable().isNoteDirty(r.getNoteGuid());\r
-                                                       if (!isNoteDirty) {\r
-                                                               logger.log(logger.HIGH, "Local resource found, but is not dirty");\r
-                                                               saveNeeded = true;\r
-                                                       } else {\r
-               /* #3 */                                String remoteHash = "";\r
-                                                               if (r != null && r.getData() != null && r.getData().getBodyHash() != null)\r
-                                                                       remoteHash = byteArrayToHexString(r.getData().getBodyHash());\r
-                                                               String localHash = "";\r
-                                                               if (l != null && l.getData() != null && l.getData().getBodyHash() != null)\r
-                                                                       remoteHash = byteArrayToHexString(l.getData().getBodyHash());\r
-                                               \r
-                                                               if (localHash.equalsIgnoreCase(remoteHash))\r
-                                                                       saveNeeded = true;\r
-                                                       }\r
-                                               }\r
-                                               \r
-                                               logger.log(logger.HIGH, "Resource save needed: " +saveNeeded);\r
-                                               if (saveNeeded) \r
-                                                       conn.getNoteTable().noteResourceTable.updateNoteResource(r, false);\r
-                                               if (r.getMime().equalsIgnoreCase("application/vnd.evernote.ink"))\r
-                                                       downloadInkNoteImage(r.getGuid(), authToken);\r
-               \r
-\r
-       }\r
-       // Sync remote notes\r
-       private void syncRemoteNotes(Client noteStore, List<Note> note, boolean fullSync, String token) {\r
-\r
-               if (note != null) {\r
-                       \r
-                       logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteNotes");\r
-                       logger.log(logger.LOW, "Local Dirty Notes: ");\r
-                       logger.log(logger.LOW, "Remote Dirty Notes:");\r
-                       for (int i=0; i<note.size();i++) {\r
-                               logger.log(logger.LOW, i +" : " +note.get(i).getGuid() + " : " +note.get(i).getTitle() );\r
-                       }\r
-                       logger.log(logger.LOW, "---");\r
-                       \r
-                       for (int i=0; i<note.size() && keepRunning; i++) {\r
-                               Note n = getEvernoteNote(noteStore, note.get(i).getGuid(), true, fullSync, true,true, token);\r
-                               syncRemoteNote(n, fullSync, token);\r
-                       }\r
-               }\r
-               logger.log(logger.EXTREME, "Leaving SyncRunner.syncRemoteNotes");\r
-       }\r
-       private void syncRemoteNote(Note n, boolean fullSync, String token) {\r
-               if (n!=null) {\r
-                       \r
-                       // Basically, this is how the sync logic for a note works.\r
-                       // If the remote note has changed and the local has not, we\r
-                       // accept the change.\r
-                       // If both the local & remote have changed but the sequence\r
-                       // numbers are the same, we don't accept the change.  This\r
-                       // seems to happen when attachments are indexed by the server.\r
-                       // If both the local & remote have changed and the sequence numbers\r
-                       // are different we move the local copy to a local notebook (making sure\r
-                       // to copy all resources) and we accept the new one.                    \r
-                       boolean conflictingNote = true;\r
-                       logger.log(logger.EXTREME, "Checking for duplicate note " +n.getGuid() +" : " +n.getTitle());\r
-                       if (dirtyNoteGuids != null && dirtyNoteGuids.contains(n.getGuid())) { \r
-                               logger.log(logger.EXTREME, "Conflict check beginning");\r
-                               conflictingNote = checkForConflict(n);\r
-                               logger.log(logger.EXTREME, "Conflict check results " +conflictingNote);\r
-                               if (conflictingNote)\r
-                                       moveConflictingNote(n.getGuid());\r
-                       }\r
-                       boolean ignoreNote = false;\r
-                       if (ignoreNotebooks.contains(n.getNotebookGuid()))\r
-                               ignoreNote = true;\r
-                       for (int i=0; i<n.getTagGuidsSize(); i++) {\r
-                               if (ignoreTags.contains(n.getTagGuids().get(i))) {\r
-                                       ignoreNote = true;\r
-                                       i=n.getTagGuidsSize();\r
-                               }\r
-                       }\r
-                               \r
-                       if ((conflictingNote || fullSync) && !ignoreNote) {\r
-                               logger.log(logger.EXTREME, "Saving Note");\r
-                               conn.getNoteTable().syncNote(n);\r
-                               // The following was commented out because it caused a race condition on the database where resources \r
-                               // may be lost.  We do the same thing elsewhere;.\r
-//                             noteSignal.noteChanged.emit(n.getGuid(), null);   // Signal to ivalidate note cache \r
-                               noteSignal.noteDownloaded.emit(n, true);                // Signal to add note to index\r
-                                       logger.log(logger.EXTREME, "Note Saved");\r
-                               if (fullSync && n.getResources() != null) {\r
-                                       for (int q=0; q<n.getResources().size() && keepRunning; q++) {\r
-                                               logger.log(logger.EXTREME, "Getting note resources.");\r
-                                               conn.getNoteTable().noteResourceTable.updateNoteResource(n.getResources().get(q), false);\r
-                                               if (n.getResources().get(q).getMime().equalsIgnoreCase("application/vnd.evernote.ink"))\r
-                                                       downloadInkNoteImage(n.getResources().get(q).getGuid(), token);\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-       private Note getEvernoteNote(Client noteStore, String guid, boolean withContent, boolean withResourceData, boolean withResourceRecognition, boolean withResourceAlternateData, String token) { \r
-               Note n = null;\r
-               try {\r
-                       logger.log(logger.EXTREME, "Retrieving note " +guid);\r
-                       n = noteStore.getNote(token, guid, withContent, withResourceData, withResourceRecognition, withResourceAlternateData);\r
-                       logger.log(logger.EXTREME, "Note " +guid +" has been retrieved.");\r
-               } catch (EDAMUserException e) {\r
-                       logger.log(logger.LOW, "*** EDAM User Excepton getEvernoteNote");\r
-                       logger.log(logger.LOW, e.toString());   \r
-                       error = true;\r
-                       e.printStackTrace();\r
-               } catch (EDAMSystemException e) {\r
-                       logger.log(logger.LOW, "*** EDAM System Excepton getEvernoteNote");\r
-                       logger.log(logger.LOW, e.toString());   \r
-                       error = true;\r
-                       e.printStackTrace();\r
-               } catch (EDAMNotFoundException e) {\r
-                       logger.log(logger.LOW, "*** EDAM Not Found Excepton getEvernoteNote");\r
-                       logger.log(logger.LOW, e.toString());   \r
-                       error = true;\r
-                       e.printStackTrace();\r
-               } catch (TException e) {\r
-                       logger.log(logger.LOW, "*** EDAM TExcepton getEvernoteNote");\r
-                       logger.log(logger.LOW, e.toString());   \r
-                       error = true;\r
-                       e.printStackTrace();\r
-               }\r
-               return n;\r
-       }\r
-       private Resource getEvernoteResource(Client noteStore, String guid, boolean withData, boolean withRecognition, boolean withAttributes, String token) { \r
-               Resource n = null;\r
-               try {\r
-                       logger.log(logger.EXTREME, "Retrieving resource " +guid);\r
-                       n = noteStore.getResource(token, guid, withData, withRecognition, withAttributes, withAttributes);\r
-                       logger.log(logger.EXTREME, "Resource " +guid +" has been retrieved.");\r
-               } catch (EDAMUserException e) {\r
-                       logger.log(logger.LOW, "*** EDAM User Excepton getEvernoteNote");\r
-                       logger.log(logger.LOW, e.toString());   \r
-                       error = true;\r
-                       e.printStackTrace();\r
-               } catch (EDAMSystemException e) {\r
-                       logger.log(logger.LOW, "*** EDAM System Excepton getEvernoteNote");\r
-                       logger.log(logger.LOW, e.toString());   \r
-                       error = true;\r
-                       e.printStackTrace();\r
-               } catch (EDAMNotFoundException e) {\r
-                       logger.log(logger.LOW, "*** EDAM Not Found Excepton getEvernoteNote");\r
-                       logger.log(logger.LOW, e.toString());   \r
-                       error = true;\r
-                       e.printStackTrace();\r
-               } catch (TException e) {\r
-                       logger.log(logger.LOW, "*** EDAM TExcepton getEvernoteNote");\r
-                       logger.log(logger.LOW, e.toString());   \r
-                       error = true;\r
-                       e.printStackTrace();\r
-               }\r
-               return n;\r
-       }\r
-\r
-       \r
-       private boolean checkForConflict(Note n) {\r
-               logger.log(logger.EXTREME, "Checking note sequence number  " +n.getGuid());\r
-               Note oldNote = conn.getNoteTable().getNote(n.getGuid(), false, false, false, false, false);\r
-               logger.log(logger.EXTREME, "Local/Remote sequence numbers: " +oldNote.getUpdateSequenceNum()+"/"+n.getUpdateSequenceNum());\r
-               logger.log(logger.LOW, "Remote Note Title:" +n.getTitle());\r
-               logger.log(logger.LOW, "Local Note Title:" +oldNote.getTitle());\r
-               if (oldNote.getUpdateSequenceNum() == n.getUpdateSequenceNum()) {\r
-                       return false;\r
-               } \r
-               boolean oldIsDirty = conn.getNoteTable().isNoteDirty(n.getGuid());\r
-               if (!oldIsDirty) \r
-                       return false;\r
-               return true;\r
-       }\r
-       \r
-       private void moveConflictingNote(String guid) {\r
-               logger.log(logger.EXTREME, "Conflicting change found for note " +guid);\r
-               List<Notebook> books = conn.getNotebookTable().getAllLocal();\r
-               String notebookGuid = null;\r
-               for (int i=0; i<books.size() && keepRunning; i++) {\r
-                       if (books.get(i).getName().equalsIgnoreCase("Conflicting Changes (local)") ||\r
-                                       books.get(i).getName().equalsIgnoreCase("Conflicting Changes")) {\r
-                               notebookGuid = books.get(i).getGuid();\r
-                               i=books.size();\r
-                       }\r
-               }\r
-               \r
-               if (notebookGuid == null) {\r
-                       logger.log(logger.EXTREME, "Building conflicting change notebook " +guid);\r
-                       Calendar currentTime = new GregorianCalendar();\r
-                       Long l = new Long(currentTime.getTimeInMillis());\r
-                       long prevTime = l;\r
-                       while (prevTime==l) {\r
-                               currentTime = new GregorianCalendar();\r
-                               l=currentTime.getTimeInMillis();\r
-                       }\r
-                       String randint = new String(Long.toString(l));\r
-               \r
-                       Notebook newBook = new Notebook();\r
-                       newBook.setUpdateSequenceNum(0);\r
-                       newBook.setGuid(randint);\r
-                       newBook.setName("Conflicting Changes");\r
-                       newBook.setServiceCreated(new Date().getTime());\r
-                       newBook.setServiceUpdated(new Date().getTime());\r
-                       newBook.setDefaultNotebook(false);\r
-                       newBook.setPublished(false);\r
-                       \r
-                       conn.getNotebookTable().addNotebook(newBook, false, true);\r
-                       notebookSignal.listChanged.emit();\r
-                       notebookGuid = newBook.getGuid();\r
-                       refreshNeeded = true;\r
-               }\r
-               \r
-               // Now that we have a good notebook guid, we need to move the conflicting note\r
-               // to the local notebook\r
-               logger.log(logger.EXTREME, "Moving conflicting note " +guid);\r
-               Calendar currentTime = new GregorianCalendar();\r
-               Long l = new Long(currentTime.getTimeInMillis());\r
-               long prevTime = l;\r
-               while (prevTime==l) {\r
-                       currentTime = new GregorianCalendar();\r
-                       l = currentTime.getTimeInMillis();\r
-               }\r
-               String newGuid = new String(Long.toString(l));\r
-                                       \r
-               Note oldNote = conn.getNoteTable().getNote(guid, true, true, false, false, false);\r
-               for (int i=0; i<oldNote.getResources().size() && keepRunning; i++) {\r
-                       l = new Long(currentTime.getTimeInMillis());\r
-                       String newResG = new String(Long.toString(l));\r
-                       String oldResG = oldNote.getResources().get(i).getGuid();\r
-                       conn.getNoteTable().noteResourceTable.resetUpdateSequenceNumber(oldResG, true);\r
-                       conn.getNoteTable().noteResourceTable.updateNoteResourceGuid(oldResG, newResG, true);\r
-               }\r
-               \r
-               conn.getNoteTable().resetNoteSequence(guid);\r
-               conn.getNoteTable().updateNoteGuid(guid, newGuid);\r
-               conn.getNoteTable().updateNoteNotebook(newGuid, notebookGuid, true);\r
-               \r
-               noteSignal.notebookChanged.emit(newGuid, notebookGuid);\r
-               refreshNeeded = true;\r
-               noteSignal.guidChanged.emit(guid,newGuid);\r
-       }\r
-       \r
-\r
-\r
-       \r
-       //******************************************************\r
-       //******************************************************\r
-       //** Utility Functions\r
-       //******************************************************\r
-       //******************************************************\r
-       // Convert a byte array to a hex string\r
-       private static String byteArrayToHexString(byte data[]) {\r
-               StringBuffer buf = new StringBuffer();\r
-           for (byte element : data) {\r
-               int halfbyte = (element >>> 4) & 0x0F;\r
-               int two_halfs = 0;\r
-               do {\r
-                       if ((0 <= halfbyte) && (halfbyte <= 9))\r
-                              buf.append((char) ('0' + halfbyte));\r
-                          else\r
-                               buf.append((char) ('a' + (halfbyte - 10)));\r
-                       halfbyte = element & 0x0F;\r
-               } while(two_halfs++ < 1);\r
-           }\r
-           return buf.toString();              \r
-       }\r
-\r
-       \r
-       \r
-       //*******************************************************\r
-       //* Find dirty tags, which do not have newly created parents\r
-       //*******************************************************\r
-       private Tag findNextTag() {\r
-               logger.log(logger.HIGH, "Entering SyncRunner.findNextTag");\r
-               Tag nextTag = null;\r
-               List<Tag> tags = conn.getTagTable().getDirty();\r
-               \r
-               // Find the parent.  If the parent has a sequence > 0 then it is a good\r
-               // parent.\r
-               for (int i=0; i<tags.size() && keepRunning; i++) {\r
-                       if (!badTagSync.containsKey(tags.get(i).getGuid())) {\r
-                               if (tags.get(i).getParentGuid() == null) {\r
-                                       logger.log(logger.HIGH, "Leaving SyncRunner.findNextTag - tag found without parent");\r
-                                       return tags.get(i);\r
-                               }\r
-                               Tag parentTag = conn.getTagTable().getTag(tags.get(i).getParentGuid());\r
-                               if (parentTag.getUpdateSequenceNum() > 0) {\r
-                                       logger.log(logger.HIGH, "Leaving SyncRunner.findNextTag - tag found");\r
-                                       return tags.get(i);\r
-                               }\r
-                       }\r
-               }\r
-               \r
-               logger.log(logger.HIGH, "Leaving SyncRunner.findNextTag - no tags returned");\r
-               return nextTag;\r
-       }\r
-       \r
-       \r
-          // Connect to Evernote\r
-    public boolean enConnect()  {\r
-       try {\r
-                       userStoreTrans = new THttpClient(userStoreUrl);\r
-                       userStoreTrans.setCustomHeader("User-Agent", userAgent);\r
-               } catch (TTransportException e) {\r
-                       QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, "Transport Excepton", e.getLocalizedMessage());\r
-                       mb.exec();\r
-                       e.printStackTrace();\r
-               }\r
-               userStoreProt = new TBinaryProtocol(userStoreTrans);\r
-           userStore = new UserStore.Client(userStoreProt, userStoreProt);\r
-           syncSignal.saveUserStore.emit(userStore);\r
-           try {\r
-                       //authResult = userStore.authenticate(username, password, consumerKey, consumerSecret);\r
-               user = userStore.getUser(authToken);\r
-               } catch (EDAMUserException e) {\r
-                       QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, "Error", "Invalid Authorization");\r
-                       mb.exec();\r
-                       isConnected = false;\r
-                       return false;\r
-               } catch (EDAMSystemException e) {\r
-                       QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, "EDAM System Excepton", e.getLocalizedMessage());\r
-                       mb.exec();\r
-                       e.printStackTrace();\r
-                       isConnected = false;\r
-               } catch (TException e) {\r
-                       QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, "Transport Excepton", e.getLocalizedMessage());\r
-                       mb.exec();\r
-                       e.printStackTrace();\r
-                       isConnected = false;\r
-               }\r
-               \r
-           boolean versionOk = false;\r
-               try {\r
-                       versionOk = userStore.checkVersion("NixNote", \r
-                   com.evernote.edam.userstore.Constants.EDAM_VERSION_MAJOR, \r
-                     com.evernote.edam.userstore.Constants.EDAM_VERSION_MINOR);\r
-               } catch (TException e) {\r
-                       e.printStackTrace();\r
-                       isConnected = false;\r
-               } \r
-           if (!versionOk) { \r
-               System.err.println("Incomatible EDAM client protocol version"); \r
-               isConnected = false;\r
-           }\r
-           //if (authResult != null) {\r
-               //user = authResult.getUser(); \r
-               //authToken = authResult.getAuthenticationToken(); \r
-           if (user == null || noteStoreUrlBase == null) {\r
-               logger.log(logger.LOW, "Error retrieving user information.  Aborting.");\r
-               System.err.println("Error retrieving user information.");\r
-               isConnected = false;    \r
-                       QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, tr("Connection Error"), tr("Error retrieving user information.  Synchronization not complete"));\r
-                       mb.exec();\r
-                       return false;\r
-               \r
-           }\r
-               noteStoreUrl = noteStoreUrlBase + user.getShardId();\r
-               syncSignal.saveAuthToken.emit(authToken);\r
-               syncSignal.saveNoteStore.emit(localNoteStore);\r
-               \r
-        \r
-               try {\r
-                       noteStoreTrans = new THttpClient(noteStoreUrl);\r
-                       noteStoreTrans.setCustomHeader("User-Agent", userAgent);\r
-               } catch (TTransportException e) {\r
-                       QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, "Transport Excepton", e.getLocalizedMessage());\r
-                       mb.exec();\r
-                       e.printStackTrace();\r
-                       isConnected = false;\r
-               } \r
-               noteStoreProt = new TBinaryProtocol(noteStoreTrans);\r
-               localNoteStore = \r
-                       new NoteStore.Client(noteStoreProt, noteStoreProt); \r
-               isConnected = true;\r
-               //authTimeRemaining = authResult.getExpiration() - authResult.getCurrentTime();\r
-               //authRefreshTime = authTimeRemaining / 2;\r
-           //}\r
-           \r
-               // Get user information\r
-               try {\r
-                       User user = userStore.getUser(authToken);\r
-                       syncSignal.saveUserInformation.emit(user);\r
-               } catch (EDAMUserException e1) {\r
-                       e1.printStackTrace();\r
-               } catch (EDAMSystemException e1) {\r
-                       e1.printStackTrace();\r
-               } catch (TException e1) {\r
-                       e1.printStackTrace();\r
-               }\r
-           \r
-           return isConnected;\r
-    }\r
-       // Disconnect from the database                         \r
-    public void enDisconnect() {\r
-       isConnected = false;\r
-    }\r
-    \r
-    /*\r
-    // Refresh the connection\r
-    private synchronized boolean refreshConnection() {\r
-       \r
-               logger.log(logger.EXTREME, "Entering SyncRunner.refreshConnection()");\r
-//        Calendar cal = Calendar.getInstance();\r
-               \r
-        // If we are not connected let's get out of here\r
-        if (!isConnected)\r
-               return false;\r
-        \r
-               // If we fail too many times, then let's give up.\r
-               if (failedRefreshes >=5) {\r
-                       logger.log(logger.EXTREME, "Refresh attempts have failed.  Disconnecting.");\r
-                       isConnected = false;\r
-                       status.message.emit(tr("Unable to synchronize - Authentication failed"));\r
-                       return false;\r
-               }\r
-        \r
-               // If this is the first time through, then we need to set this\r
-//             if (authRefreshTime == 0 || cal.getTimeInMillis() > authRefreshTime) \r
-//                     authRefreshTime = cal.getTimeInMillis();\r
-               \r
- //            // Default to checking again in 5 min.  This in case we fail.\r
- //            authRefreshTime = authRefreshTime +(5*60*1000);     \r
-\r
-               // Try to get a new token\r
-               AuthenticationResult newAuth = null; \r
-               logger.log(logger.EXTREME, "Beginning to try authentication refresh");\r
-       try {\r
-               if (userStore != null && authToken != null) \r
-                       newAuth = userStore.refreshAuthentication(authToken); \r
-               else\r
-                       return false;\r
-               logger.log(logger.EXTREME, "UserStore.refreshAuthentication has succeeded.");\r
-               } catch (EDAMUserException e) {\r
-                       e.printStackTrace();\r
-                       syncSignal.authRefreshComplete.emit(false);\r
-                       failedRefreshes++;\r
-                       return false;\r
-               } catch (EDAMSystemException e) {\r
-                       e.printStackTrace();\r
-                       syncSignal.authRefreshComplete.emit(false);\r
-                       failedRefreshes++;\r
-                       return false;           \r
-               } catch (TException e) { \r
-                       e.printStackTrace();\r
-                       syncSignal.authRefreshComplete.emit(false);\r
-                       failedRefreshes++;\r
-                       return false;\r
-               }\r
-               \r
-               // If we didn't get a good auth, then we've failed\r
-               if (newAuth == null) {\r
-                       failedRefreshes++;\r
-                       status.message.emit(tr("Unable to synchronize - Authentication failed"));\r
-                       logger.log(logger.EXTREME, "Authentication failure #" +failedRefreshes);\r
-                       status.message.emit(tr("Unable to synchronize - Authentication failed"));\r
-                       syncSignal.authRefreshComplete.emit(false);\r
-                       return false;\r
-               }\r
-               \r
-               // We got a good token.  Now we need to setup the time to renew it.\r
-               logger.log(logger.EXTREME, "Saving authentication tokens");\r
-               authResult = newAuth;\r
-               authToken = new String(newAuth.getAuthenticationToken());\r
-//             authTimeRemaining = authResult.getExpiration() - authResult.getCurrentTime();\r
-//             authRefreshTime = cal.getTimeInMillis() + (authTimeRemaining/4);        \r
-               failedRefreshes=0;\r
-               syncSignal.authRefreshComplete.emit(true);\r
-               authRefreshNeeded = false;\r
-                       \r
-               // This should never happen, but if it does we consider this a faild attempt.\r
-//             if (authTimeRemaining <= 0) {\r
-//                     failedRefreshes++;\r
-//                     syncSignal.authRefreshComplete.emit(false);\r
-//             }\r
-               \r
-               return true;\r
-    }\r
-    \r
-    */\r
-    \r
-       public synchronized boolean addWork(String request) {\r
-               if (workQueue.offer(request))\r
-                       return true;\r
-               return false;\r
-       }\r
-    \r
-    private Note getNoteContent(Note n) {\r
-               QTextCodec codec = QTextCodec.codecForLocale();\r
-               codec = QTextCodec.codecForName("UTF-8");\r
-       n.setContent(codec.toUnicode(new QByteArray(n.getContent())));\r
-       return n;\r
-    }\r
-\r
-\r
-\r
-    //*********************************************************\r
-    //* Special download instructions.  Used for DB upgrades\r
-    //*********************************************************\r
-    private void downloadAllSharedNotebooks(Client noteStore) {\r
-       try {\r
-                       List<SharedNotebook> books = noteStore.listSharedNotebooks(authToken);\r
-                       logger.log(logger.LOW, "Shared notebooks found = " +books.size());\r
-                       for (int i=0; i<books.size(); i++) {\r
-                               conn.getSharedNotebookTable().updateNotebook(books.get(i), false);\r
-                       }\r
-                       conn.getSyncTable().deleteRecord("FullSharedNotebookSync");\r
-               } catch (EDAMUserException e1) {\r
-                       e1.printStackTrace();\r
-                       status.message.emit(tr("User exception Listing shared notebooks."));\r
-                       logger.log(logger.LOW, e1.getMessage());\r
-                       return;\r
-               } catch (EDAMSystemException e1) {\r
-                       e1.printStackTrace();\r
-                       status.message.emit(tr("System exception Listing shared notebooks."));\r
-                       logger.log(logger.LOW, e1.getMessage());\r
-                       return;\r
-               } catch (TException e1) {\r
-                       e1.printStackTrace();\r
-                       status.message.emit(tr("Transaction exception Listing shared notebooks."));\r
-                       logger.log(logger.LOW, e1.getMessage());\r
-                       return;\r
-               } catch (EDAMNotFoundException e1) {\r
-                       e1.printStackTrace();\r
-                       status.message.emit(tr("EDAM Not Found exception Listing shared notebooks."));\r
-                       logger.log(logger.LOW, e1.getMessage());\r
-               }\r
-    }\r
-    private void downloadAllNotebooks(Client noteStore) {\r
-       try {\r
-                       List<Notebook> books = noteStore.listNotebooks(authToken);\r
-                       logger.log(logger.LOW, "Shared notebooks found = " +books.size());\r
-                       for (int i=0; i<books.size(); i++) {\r
-                               conn.getNotebookTable().updateNotebook(books.get(i), false);\r
-                       }\r
-                       conn.getSyncTable().deleteRecord("FullNotebookSync");\r
-               } catch (EDAMUserException e1) {\r
-                       e1.printStackTrace();\r
-                       status.message.emit(tr("User exception Listing notebooks."));\r
-                       logger.log(logger.LOW, e1.getMessage());\r
-                       return;\r
-               } catch (EDAMSystemException e1) {\r
-                       e1.printStackTrace();\r
-                       status.message.emit(tr("System exception Listing notebooks."));\r
-                       logger.log(logger.LOW, e1.getMessage());\r
-                       return;\r
-               } catch (TException e1) {\r
-                       e1.printStackTrace();\r
-                       status.message.emit(tr("Transaction exception Listing notebooks."));\r
-                       logger.log(logger.LOW, e1.getMessage());\r
-                       return;\r
-               }\r
-    }\r
-    private void downloadAllLinkedNotebooks(Client noteStore) {\r
-       try {\r
-                       List<LinkedNotebook> books = noteStore.listLinkedNotebooks(authToken);\r
-                       logger.log(logger.LOW, "Linked notebooks found = " +books.size());\r
-                       for (int i=0; i<books.size(); i++) {\r
-                               conn.getLinkedNotebookTable().updateNotebook(books.get(i), false);\r
-                       }\r
-                       conn.getSyncTable().deleteRecord("FullLinkedNotebookSync");\r
-               } catch (EDAMUserException e1) {\r
-                       e1.printStackTrace();\r
-                       status.message.emit(tr("User exception Listing linked notebooks."));\r
-                       logger.log(logger.LOW, e1.getMessage());\r
-                       return;\r
-               } catch (EDAMSystemException e1) {\r
-                       e1.printStackTrace();\r
-                       status.message.emit(tr("System exception Listing linked notebooks."));\r
-                       logger.log(logger.LOW, e1.getMessage());\r
-                       return;\r
-               } catch (TException e1) {\r
-                       e1.printStackTrace();\r
-                       status.message.emit(tr("Transaction exception Listing lineked notebooks."));\r
-                       logger.log(logger.LOW, e1.getMessage());\r
-                       return;\r
-               } catch (EDAMNotFoundException e1) {\r
-                       e1.printStackTrace();\r
-                       status.message.emit(tr("EDAM Not Found exception Listing linked notebooks."));\r
-                       logger.log(logger.LOW, e1.getMessage());\r
-               }\r
-    }\r
-\r
-    \r
-    private void downloadInkNoteImage(String guid, String authToken) {\r
-               String urlBase = noteStoreUrl.replace("/edam/note/", "/shard/") + "/res/"+guid+".ink?slice=";\r
-//             urlBase = "https://www.evernote.com/shard/s1/res/52b567a9-54ae-4a08-afc5-d5bae275b2a8.ink?slice=";\r
-               Integer slice = 1;\r
-               Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(guid, false);\r
-               conn.getInkImagesTable().expungeImage(r.getGuid());\r
-               int sliceCount = 1+((r.getHeight()-1)/480);\r
-               HttpClient http = new DefaultHttpClient();\r
-       for (int i=0; i<sliceCount; i++) {\r
-               String url = urlBase + slice.toString();\r
-               HttpPost post = new HttpPost(url);\r
-               post.getParams().setParameter("auth", authToken);\r
-               List <NameValuePair> nvps = new ArrayList <NameValuePair>();\r
-            nvps.add(new BasicNameValuePair("auth", authToken));\r
-\r
-            try {\r
-                               post.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));\r
-                       } catch (UnsupportedEncodingException e1) {\r
-                               e1.printStackTrace();\r
-                       }\r
-               try {\r
-                       HttpResponse response = http.execute(post);\r
-                       HttpEntity resEntity = response.getEntity();\r
-                       InputStream is = resEntity.getContent();\r
-                       QByteArray data = writeToFile(is);\r
-                       conn.getInkImagesTable().saveImage(guid, slice, data);\r
-                       } catch (ClientProtocolException e) {\r
-                               e.printStackTrace();\r
-                       } catch (IOException e) {\r
-                               e.printStackTrace();\r
-                       }\r
-\r
-                       slice++;\r
-       }\r
-       http.getConnectionManager().shutdown(); \r
-               noteSignal.noteChanged.emit(r.getNoteGuid(), null);   // Signal to ivalidate note cache\r
-    }\r
-    \r
-    \r
-    public QByteArray writeToFile(InputStream iStream) throws IOException {\r
-\r
-           File temp = File.createTempFile("nn-inknote-temp", ".png");\r
-\r
-           // Save InputStream to the file.\r
-           BufferedOutputStream fOut = null;\r
-           try {\r
-             fOut = new BufferedOutputStream(new FileOutputStream(temp));\r
-             byte[] buffer = new byte[32 * 1024];\r
-             int bytesRead = 0;\r
-             while ((bytesRead = iStream.read(buffer)) != -1) {\r
-               fOut.write(buffer, 0, bytesRead);\r
-             }\r
-           }\r
-           finally {\r
-               iStream.close();\r
-               fOut.close();\r
-           }\r
-           QFile tempFile = new QFile(temp.getAbsoluteFile().toString());\r
-           tempFile.open(OpenModeFlag.ReadOnly);\r
-           QByteArray data = tempFile.readAll();\r
-           tempFile.close();\r
-           tempFile.remove();\r
-           return data;\r
-    }\r
-    \r
-    \r
-       //******************************************\r
-       //* Begin syncing shared notebooks \r
-       //******************************************\r
-    private void syncLinkedNotebooks() {\r
-       logger.log(logger.MEDIUM, "Authenticating linked Notebooks");\r
-       status.message.emit(tr("Synchronizing shared notebooks."));\r
-       List<LinkedNotebook> books = conn.getLinkedNotebookTable().getAll();\r
-       \r
-       errorSharedNotebooks.clear();\r
-               \r
-       for (int i=0; i<books.size(); i++) {\r
-               if (errorSharedNotebooksIgnored.containsKey(books.get(i).getGuid()))\r
-                       break;\r
-               try {\r
-                       logger.log(logger.EXTREME, "Checking notebook: " +books.get(i).getShareName());\r
-                               long lastSyncDate = conn.getLinkedNotebookTable().getLastSequenceDate(books.get(i).getGuid());\r
-                               int lastSequenceNumber = conn.getLinkedNotebookTable().getLastSequenceNumber(books.get(i).getGuid());\r
-\r
-                               logger.log(logger.EXTREME, "Last Sequence Number on file: " +lastSequenceNumber);\r
-                               \r
-                               // Authenticate to the owner's shard\r
-                               String linkedNoteStoreUrl       = noteStoreUrlBase + books.get(i).getShardId();\r
-                               logger.log(logger.EXTREME, "linkedNoteStoreURL: " +linkedNoteStoreUrl);\r
-                               THttpClient linkedNoteStoreTrans        = new THttpClient(linkedNoteStoreUrl);\r
-                               TBinaryProtocol linkedNoteStoreProt     = new TBinaryProtocol(linkedNoteStoreTrans);\r
-                               Client linkedNoteStore = new NoteStore.Client(linkedNoteStoreProt, linkedNoteStoreProt);        \r
-\r
-                               linkedAuthResult = null;\r
-                               if (books.get(i).getShareKey() != null) {\r
-                                       logger.log(logger.EXTREME, "Share Key Not Null: " +books.get(i).getShareKey());\r
-                                       linkedAuthResult = linkedNoteStore.authenticateToSharedNotebook(books.get(i).getShareKey(), authToken);\r
-                                       logger.log(logger.EXTREME, "Authentication Token" +linkedAuthResult.getAuthenticationToken());\r
-                               } else {\r
-                                       logger.log(logger.EXTREME, "Share key is null");\r
-                                       linkedAuthResult = new AuthenticationResult();\r
-                                       linkedAuthResult.setAuthenticationToken("");\r
-                               }\r
-                               SyncState linkedSyncState = \r
-                                       linkedNoteStore.getLinkedNotebookSyncState(linkedAuthResult.getAuthenticationToken(), books.get(i));\r
-                               if (linkedSyncState.getUpdateCount() > lastSequenceNumber) {\r
-                                       logger.log(logger.EXTREME, "Remote changes found");\r
-                                       if (lastSyncDate < linkedSyncState.getFullSyncBefore()) {\r
-                                               lastSequenceNumber = 0;\r
-                                       } \r
-                                       logger.log(logger.EXTREME, "Calling syncLinkedNotebook for " +books.get(i).getShareName());\r
-                                       syncLinkedNotebook(linkedNoteStore, books.get(i), \r
-                                                       lastSequenceNumber, linkedSyncState.getUpdateCount(), authToken);\r
-                               }\r
-                       \r
-                       // Synchronize local changes\r
-                       syncLocalLinkedNoteChanges(linkedNoteStore, books.get(i));\r
-                               \r
-               } catch (EDAMUserException e) {\r
-                       e.printStackTrace();\r
-               } catch (EDAMNotFoundException e) {\r
-                       status.message.emit(tr("Error synchronizing \" " +\r
-                                       books.get(i).getShareName()+"\". Please verify you still have access to that shared notebook."));\r
-                       errorSharedNotebooks.add(books.get(i).getGuid());\r
-                       errorSharedNotebooksIgnored.put(books.get(i).getGuid(), books.get(i).getGuid());\r
-                       logger.log(logger.LOW, "Error synchronizing shared notebook.  EDAMNotFound: "+e.getMessage());\r
-                       logger.log(logger.LOW, e.getStackTrace());\r
-                       error = true;\r
-                       e.printStackTrace();\r
-               } catch (EDAMSystemException e) {\r
-                       error = true;\r
-                       logger.log(logger.LOW, "System error authenticating against shared notebook. "+\r
-                                       "Key: "+books.get(i).getShareKey() +" Error:" +e.getMessage());\r
-                       e.printStackTrace();\r
-               } catch (TException e) {\r
-                       error = true;\r
-                       e.printStackTrace();\r
-               }\r
-       }\r
-       \r
-       // Cleanup tags\r
-       conn.getTagTable().removeUnusedLinkedTags();\r
-       conn.getTagTable().cleanupTags();\r
-       tagSignal.listChanged.emit();\r
-       return;\r
-       }\r
-\r
-    \r
-    //**************************************************************\r
-    //* Linked notebook contents (from someone else's account)\r
-    //*************************************************************\r
-       private void syncLinkedNotebook(Client linkedNoteStore, LinkedNotebook book, int usn, int highSequence, String token) {\r
-               logger.log(logger.EXTREME, "Entering syncLinkedNotebook");\r
-               if (ignoreLinkedNotebooks.contains(book.getGuid()))\r
-                       return;\r
-               List<Note> dirtyNotes = conn.getNoteTable().getDirtyLinkedNotes();\r
-               if (dirtyNoteGuids == null) \r
-                       dirtyNoteGuids = new ArrayList<String>();\r
-\r
-               for (int i=0; i<dirtyNotes.size() && keepRunning; i++) {\r
-                       dirtyNoteGuids.add(dirtyNotes.get(i).getGuid());\r
-               }\r
-               boolean fullSync = false;\r
-               if (usn == 0)\r
-                       fullSync = true;\r
-               boolean syncError = false;\r
-               while (usn < highSequence && !syncError) {\r
-                       refreshNeeded = true;\r
-                       try {\r
-                               SyncChunk chunk = \r
-                                       linkedNoteStore.getLinkedNotebookSyncChunk(token, book, usn, 10, fullSync);\r
-                               \r
-                               // Expunge notes\r
-                               syncExpungedNotes(chunk);\r
-\r
-                               logger.log(logger.EXTREME, "Syncing remote notes: " +chunk.getNotesSize());\r
-                               syncRemoteNotes(linkedNoteStore, chunk.getNotes(), fullSync, linkedAuthResult.getAuthenticationToken());\r
-                               logger.log(logger.EXTREME, "Finding new linked tags");\r
-                               findNewLinkedTags(linkedNoteStore, chunk.getNotes(), linkedAuthResult.getAuthenticationToken());\r
-                               // Sync resources\r
-                               logger.log(logger.EXTREME, "Synchronizing tags: " +chunk.getTagsSize());\r
-                               for (int i=0; i<chunk.getResourcesSize(); i++) {\r
-                                       syncRemoteResource(linkedNoteStore, chunk.getResources().get(i), linkedAuthResult.getAuthenticationToken());\r
-                               }\r
-                               logger.log(logger.EXTREME, "Synchronizing linked notebooks: " +chunk.getNotebooksSize());\r
-                               syncRemoteLinkedNotebooks(linkedNoteStore, chunk.getNotebooks(), false, book);\r
-                               syncLinkedTags(chunk.getTags(), book.getGuid());\r
-                               \r
-                               // Go through & signal any notes that have changed so we can refresh the user's view\r
-                               for (int i=0; i<chunk.getNotesSize(); i++) \r
-                                       noteSignal.noteChanged.emit(chunk.getNotes().get(i).getGuid(), null);\r
-\r
-                               // Expunge Notebook records\r
-                               logger.log(logger.EXTREME, "Expunging linked notebooks: " +chunk.getExpungedLinkedNotebooksSize());\r
-                               for (int i=0; i<chunk.getExpungedLinkedNotebooksSize(); i++) {\r
-                                       conn.getLinkedNotebookTable().expungeNotebook(chunk.getExpungedLinkedNotebooks().get(i), false);\r
-                               }\r
-                               usn = chunk.getChunkHighUSN();\r
-                               conn.getLinkedNotebookTable().setLastSequenceDate(book.getGuid(),chunk.getCurrentTime());\r
-                               conn.getLinkedNotebookTable().setLastSequenceNumber(book.getGuid(),chunk.getChunkHighUSN());\r
-                       } catch (EDAMUserException e) {\r
-                               syncError = true;\r
-                               status.message.emit(tr("EDAM UserException synchronizing linked notbook.  See the log for datails."));\r
-                               e.printStackTrace();\r
-                               logger.log(logger.LOW, tr("EDAM UserException synchronizing linked notbook ")+ e.getMessage());\r
-                       } catch (EDAMSystemException e) {\r
-                               syncError = true;\r
-                               status.message.emit(tr("EDAM SystemException synchronizing linked notbook.  See the log for datails."));\r
-                               e.printStackTrace();\r
-                               logger.log(logger.LOW, tr("EDAM SystemException synchronizing linked notbook.  See the log for datails") +e.getMessage());\r
-                       } catch (EDAMNotFoundException e) {\r
-                               syncError = true;\r
-                               status.message.emit(tr("Notebook URL not found. Removing notobook ") +book.getShareName());\r
-                               conn.getNotebookTable().deleteLinkedTags(book.getGuid());\r
-                               conn.getLinkedNotebookTable().expungeNotebook(book.getGuid(), false);\r
-                               logger.log(logger.LOW, tr("Notebook URL not found. Removing notobook ") +e.getMessage());\r
-                       } catch (TException e) {\r
-                               syncError = true;\r
-                               status.message.emit(tr("EDAM TException synchronizing linked notbook.  See the log for datails."));\r
-                               e.printStackTrace();\r
-                               logger.log(logger.LOW, tr("EDAM TException synchronizing linked notbook.  See the log for datails." )+e.getMessage());\r
-                       }\r
-               }\r
-               logger.log(logger.EXTREME, "leaving syncLinkedNotebook");\r
-       }\r
-       // Sync remote tags\r
-       private void syncLinkedTags(List<Tag> tags, String notebookGuid) {\r
-               logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteTags");\r
-               if (tags != null) {\r
-                       for (int i=0; i<tags.size() && keepRunning; i++) {\r
-                               conn.getTagTable().syncLinkedTag(tags.get(i), notebookGuid, false);\r
-                       }\r
-               }\r
-               logger.log(logger.EXTREME, "Leaving SyncRunner.syncRemoteTags");\r
-       }\r
-       \r
-       // Sync notebooks from a linked notebook\r
-       private void syncRemoteLinkedNotebooks(Client noteStore, List<Notebook> notebooks, boolean readOnly, LinkedNotebook linked) {\r
-               logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteNotebooks");\r
-               if (notebooks != null) {\r
-                       for (int i=0; i<notebooks.size() && keepRunning; i++) {\r
-                               try {\r
-                                       logger.log(logger.EXTREME, "auth token:" +linkedAuthResult.getAuthenticationToken());\r
-                                       if (!linkedAuthResult.getAuthenticationToken().equals("")) {\r
-                                               SharedNotebook s = noteStore.getSharedNotebookByAuth(linkedAuthResult.getAuthenticationToken());\r
-                                               logger.log(logger.EXTREME, "share key:"+s.getShareKey() +" notebookGuid" +s.getNotebookGuid());\r
-                                               conn.getLinkedNotebookTable().setNotebookGuid(s.getShareKey(), s.getNotebookGuid());\r
-                                               readOnly = !s.isNotebookModifiable();\r
-                                       } else {\r
-                                               readOnly = true;\r
-                                       }\r
-                                       notebooks.get(i).setName(linked.getShareName());\r
-                                       notebooks.get(i).setDefaultNotebook(false);\r
-                                       conn.getNotebookTable().syncLinkedNotebook(notebooks.get(i), false, readOnly); \r
-                               } catch (EDAMUserException e) {\r
-                                       readOnly = true;\r
-                                       e.printStackTrace();\r
-                               } catch (EDAMNotFoundException e) {\r
-                                       readOnly = true;\r
-                                       e.printStackTrace();\r
-                               } catch (EDAMSystemException e) {\r
-                                       readOnly = true;\r
-                                       e.printStackTrace();\r
-                               } catch (TException e) {\r
-                                       readOnly = true;\r
-                                       e.printStackTrace();\r
-                               }\r
-\r
-                       }\r
-               }                       \r
-               logger.log(logger.EXTREME, "Leaving SyncRunner.syncRemoteNotebooks");\r
-       }\r
-\r
-       private void findNewLinkedTags(Client noteStore, List<Note> newNotes, String token) {\r
-               if (newNotes == null)\r
-                       return;\r
-               for (int i=0; i<newNotes.size(); i++) {\r
-                       Note n = newNotes.get(i);\r
-                       for (int j=0; j<n.getTagGuidsSize(); j++) {\r
-                               String tag = n.getTagGuids().get(j);\r
-                               if (!conn.getTagTable().exists(tag)) {\r
-                                       Tag newTag;\r
-                                       try {\r
-                                               newTag = noteStore.getTag(token, tag);\r
-                                               conn.getTagTable().addTag(newTag, false);\r
-                                       } catch (EDAMUserException e) {\r
-                                               e.printStackTrace();\r
-                                       } catch (EDAMSystemException e) {\r
-                                               e.printStackTrace();\r
-                                       } catch (EDAMNotFoundException e) {\r
-                                               e.printStackTrace();\r
-                                       } catch (TException e) {\r
-                                               e.printStackTrace();\r
-                                       }\r
-                                       \r
-                               }\r
-                       }\r
-               }\r
-       }\r
-\r
-       // Synchronize changes locally done to linked notes\r
-       private void syncLocalLinkedNoteChanges(Client noteStore, LinkedNotebook book) {\r
-               logger.log(logger.EXTREME, "Entering SyncRunner.synclocalLinkedNoteChanges");\r
-               String notebookGuid = conn.getLinkedNotebookTable().getNotebookGuid(book.getGuid());\r
-               logger.log(logger.EXTREME, "Finding changes for " +book.getShareName() +":" +book.getGuid() + ":" +notebookGuid);\r
-               List<Note> notes = conn.getNoteTable().getDirtyLinked(notebookGuid);\r
-               logger.log(logger.EXTREME, "Number of changes found: " +notes.size());\r
-               for (int i=0; i<notes.size(); i++) {\r
-                       logger.log(logger.EXTREME, "Calling syncLocalNote with key " +linkedAuthResult.getAuthenticationToken());\r
-                       syncLocalNote(noteStore, notes.get(i), linkedAuthResult.getAuthenticationToken());\r
-               }\r
-               logger.log(logger.EXTREME, "Leaving SyncRunner.synclocalLinkedNoteChanges");\r
-       }\r
-\r
-}\r
+/*
+ * This file is part of NixNote/NeighborNote 
+ * Copyright 2009 Randy Baumgarte
+ * Copyright 2013 Yuki Takahashi
+ * 
+ * This file may be licensed under the terms of of the
+ * GNU General Public License Version 2 (the ``GPL'').
+ *
+ * Software distributed under the License is distributed
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
+ * express or implied. See the GPL for the specific language
+ * governing rights and limitations.
+ *
+ * You should have received a copy of the GPL along with this
+ * program. If not, go to http://www.gnu.org/licenses/gpl.html
+ * or write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+*/
+package cx.fbn.nevernote.threads;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.List;
+import java.util.TreeSet;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.protocol.HTTP;
+
+import com.evernote.edam.error.EDAMErrorCode;
+import com.evernote.edam.error.EDAMNotFoundException;
+import com.evernote.edam.error.EDAMSystemException;
+import com.evernote.edam.error.EDAMUserException;
+import com.evernote.edam.notestore.NoteStore;
+import com.evernote.edam.notestore.NoteStore.Client;
+import com.evernote.edam.notestore.SyncChunk;
+import com.evernote.edam.notestore.SyncState;
+import com.evernote.edam.type.Data;
+import com.evernote.edam.type.LinkedNotebook;
+import com.evernote.edam.type.Note;
+import com.evernote.edam.type.Notebook;
+import com.evernote.edam.type.Resource;
+import com.evernote.edam.type.SavedSearch;
+import com.evernote.edam.type.SharedNotebook;
+import com.evernote.edam.type.Tag;
+import com.evernote.edam.type.User;
+import com.evernote.edam.userstore.AuthenticationResult;
+import com.evernote.edam.userstore.UserStore;
+import com.evernote.thrift.TException;
+import com.evernote.thrift.protocol.TBinaryProtocol;
+import com.evernote.thrift.transport.THttpClient;
+import com.evernote.thrift.transport.TTransportException;
+import com.trolltech.qt.core.QByteArray;
+import com.trolltech.qt.core.QFile;
+import com.trolltech.qt.core.QIODevice.OpenModeFlag;
+import com.trolltech.qt.core.QObject;
+import com.trolltech.qt.core.QTextCodec;
+import com.trolltech.qt.gui.QMessageBox;
+
+import cx.fbn.nevernote.signals.LimitSignal;
+import cx.fbn.nevernote.signals.NoteIndexSignal;
+import cx.fbn.nevernote.signals.NoteResourceSignal;
+import cx.fbn.nevernote.signals.NoteSignal;
+import cx.fbn.nevernote.signals.NotebookSignal;
+import cx.fbn.nevernote.signals.SavedSearchSignal;
+import cx.fbn.nevernote.signals.StatusSignal;
+import cx.fbn.nevernote.signals.SyncSignal;
+import cx.fbn.nevernote.signals.TagSignal;
+import cx.fbn.nevernote.sql.DatabaseConnection;
+import cx.fbn.nevernote.sql.DeletedItemRecord;
+import cx.fbn.nevernote.utilities.ApplicationLogger;
+
+
+public class SyncRunner extends QObject implements Runnable {
+       
+       private final ApplicationLogger logger;
+       private DatabaseConnection              conn;
+       private boolean                                 idle;
+       public boolean                                  error;
+       public volatile List<String>    errorSharedNotebooks;
+       public volatile HashMap<String,String>  errorSharedNotebooksIgnored;
+       public volatile boolean                 isConnected;
+       public volatile boolean                 keepRunning;
+       public volatile String                  authToken;
+       private long                                    evernoteUpdateCount;
+       private final String userAgent = "NeighborNote/" + System.getProperty("os.name")
+                                                       +"/"+System.getProperty("java.vendor") + "/"
+                                                       + System.getProperty("java.version") +";";
+       
+       public volatile NoteStore.Client                localNoteStore;
+       private UserStore.Client                                userStore;
+       
+       public volatile StatusSignal                    status;
+       public volatile TagSignal                               tagSignal;
+       public volatile NotebookSignal                  notebookSignal;
+       public volatile NoteIndexSignal                 noteIndexSignal;
+       public volatile NoteSignal                              noteSignal;
+       public volatile SavedSearchSignal               searchSignal;
+       public volatile NoteResourceSignal              resourceSignal;
+       public volatile SyncSignal                              syncSignal;
+       public volatile LimitSignal                             limitSignal;
+       public volatile boolean                                 authRefreshNeeded;
+       public volatile boolean                                 syncNeeded;
+       public volatile boolean                                 disableUploads;
+       public volatile boolean                                 syncDeletedContent;
+       private volatile List<String>                   dirtyNoteGuids;
+       
+    public volatile String username = ""; 
+    public volatile String password = ""; 
+       public volatile String userStoreUrl;
+    public String noteStoreUrlBase;
+    private THttpClient userStoreTrans;
+    private TBinaryProtocol userStoreProt;
+    //private AuthenticationResult authResult;
+    private AuthenticationResult linkedAuthResult;
+    private User user; 
+//         private long authTimeRemaining;
+    public long authRefreshTime;
+    public long failedRefreshes = 0;
+    public  THttpClient noteStoreTrans;
+    public TBinaryProtocol noteStoreProt;
+    public String noteStoreUrl;
+    public long sequenceDate;
+    public int updateSequenceNumber;
+    private boolean refreshNeeded;
+    private volatile LinkedBlockingQueue<String> workQueue;
+       private static int MAX_QUEUED_WAITING = 1000;
+       String dbuid;
+       String dburl;
+       String indexUrl;
+       String resourceUrl;
+       String behaviorUrl;
+       
+       String dbpswd;
+       String dbcpswd;
+       private final TreeSet<String> ignoreTags;
+       private final TreeSet<String> ignoreNotebooks;
+       private final TreeSet<String> ignoreLinkedNotebooks;
+       private HashMap<String,String> badTagSync;
+
+       
+       public SyncRunner(String logname, String u, String i, String r, String b, String uid, String pswd, String cpswd) {
+               logger = new ApplicationLogger(logname);
+               
+               noteSignal = new NoteSignal();
+               status = new StatusSignal();
+               tagSignal = new TagSignal();
+               notebookSignal = new NotebookSignal();
+               noteIndexSignal = new NoteIndexSignal();
+               noteSignal = new NoteSignal();
+               searchSignal = new SavedSearchSignal();
+               syncSignal = new SyncSignal();
+               resourceSignal = new NoteResourceSignal();
+               limitSignal = new LimitSignal();
+               resourceUrl = r;
+               indexUrl = i;
+               behaviorUrl = b;
+               
+               dbuid = uid;
+               dburl = u;
+               dbpswd = pswd;
+               dbcpswd = cpswd;
+//             this.setAutoDelete(false);
+               
+               isConnected = false;
+               syncNeeded = false;
+               authRefreshNeeded = false;
+               keepRunning = true;
+               idle = true;
+               disableUploads = false;
+               ignoreTags = new TreeSet<String>();
+               ignoreNotebooks = new TreeSet<String>();
+               ignoreLinkedNotebooks = new TreeSet<String>();
+               
+//             setAutoDelete(false);
+               workQueue=new LinkedBlockingQueue<String>(MAX_QUEUED_WAITING);
+       }
+       @Override
+       public void run() {
+               errorSharedNotebooks = new ArrayList<String>();
+               errorSharedNotebooksIgnored = new HashMap<String,String>();
+               try {
+                       logger.log(logger.EXTREME, "Starting thread");
+                       conn = new DatabaseConnection(logger, dburl, indexUrl, resourceUrl, behaviorUrl, dbuid, dbpswd, dbcpswd, 200);
+                       while(keepRunning) {
+                               logger.log(logger.EXTREME, "Blocking until work is found");
+                               String work = workQueue.take();
+                               logger.log(logger.LOW, "Dirty Notes Before Sync: " +new Integer(conn.getNoteTable().getDirtyCount()).toString());
+                               logger.log(logger.EXTREME, "Work found: " +work);
+                               if (work.equalsIgnoreCase("stop")) {
+                                       idle=false;
+                                       return;
+                               }
+                               conn.getNoteTable().dumpDirtyNotes();  // Debugging statement
+                               idle=false;
+                               error=false;
+                               if (syncNeeded) {
+                                       logger.log(logger.EXTREME, "SyncNeeded is true");
+                                       refreshNeeded=false;
+                                       sequenceDate = conn.getSyncTable().getLastSequenceDate();
+                                       updateSequenceNumber = conn.getSyncTable().getUpdateSequenceNumber();
+                                       try {
+                                               logger.log(logger.EXTREME, "Beginning sync");
+                                               evernoteSync(localNoteStore);
+                                               logger.log(logger.EXTREME, "Sync finished");
+                                       } catch (UnknownHostException e) {
+                                               status.message.emit(e.getMessage());
+                                       }
+                               }
+                               idle=true;
+                               logger.log(logger.EXTREME, "Signaling refresh finished.  refreshNeeded=" +refreshNeeded);
+                               syncSignal.finished.emit(refreshNeeded);
+                               if (error) {
+                                       syncSignal.errorDisconnect.emit();
+                                       status.message.emit(tr("Error synchronizing - see log for details."));
+                               }
+                               logger.log(logger.LOW, "Dirty Notes After Sync: " +new Integer(conn.getNoteTable().getDirtyCount()).toString());
+                               conn.getNoteTable().dumpDirtyNotes();
+                               logger.log(logger.LOW, "---");
+                       }
+               }       
+               catch (InterruptedException e1) {
+                       e1.printStackTrace();
+               }
+               conn.dbShutdown();
+       }
+
+       
+       public DatabaseConnection getConnection() {
+               return conn;
+       }
+
+       public boolean isIdle() {
+               return idle;
+       }
+
+
+       public void setConnected(boolean c) {
+               isConnected = c;
+       }
+       public void setKeepRunning(boolean r) {
+               logger.log(logger.EXTREME, "Setting keepRunning=" +r);
+               keepRunning = r;
+       }
+       public void setNoteStore(NoteStore.Client c) {
+               logger.log(logger.EXTREME, "Setting NoteStore in sync thread");
+               localNoteStore = c;
+       }
+       public void setUserStore(UserStore.Client c) {
+               logger.log(logger.EXTREME, "Setting UserStore in sync thread");
+               userStore = c;
+       }
+
+       public void setEvernoteUpdateCount(long s) {
+               logger.log(logger.EXTREME, "Setting Update Count in sync thread");
+               evernoteUpdateCount = s;
+       }
+       
+       //***************************************************************
+    //***************************************************************
+    //** These functions deal with Evernote communications
+    //***************************************************************
+    //***************************************************************
+       // Synchronize changes with Evernote
+       @SuppressWarnings("unused")
+       private void evernoteSync(Client noteStore) throws java.net.UnknownHostException {
+               logger.log(logger.HIGH, "Entering SyncRunner.evernoteSync");
+               
+               // Rebuild list of tags & notebooks to ignore
+               ignoreNotebooks.clear();
+               List<String> ignore = conn.getSyncTable().getIgnoreRecords("NOTEBOOK");
+               for (int i=0; i<ignore.size(); i++) 
+                       ignoreNotebooks.add(ignore.get(i));
+               
+               ignore.clear();
+               ignore = conn.getSyncTable().getIgnoreRecords("LINKEDNOTEBOOK");
+               for (int i=0; i<ignore.size(); i++) 
+                       ignoreLinkedNotebooks.add(ignore.get(i));
+               
+               ignoreTags.clear();
+               ignore = conn.getSyncTable().getIgnoreRecords("TAG");
+               for (int i=0; i<ignore.size(); i++) 
+                       ignoreTags.add(ignore.get(i));
+
+               // Make sure we are connected & should keep running
+               if (isConnected && keepRunning) {
+                       error = false;
+                       logger.log(logger.EXTREME, "Synchronizing with Evernote");
+                       status.message.emit(tr("Synchronizing with Evernote"));
+                       
+                       // Get user information
+                       try {
+                               logger.log(logger.EXTREME, "getting user from userstore");
+                               User user = userStore.getUser(authToken);
+                               logger.log(logger.EXTREME, "Saving user information");
+                               syncSignal.saveUserInformation.emit(user);
+                       } catch (EDAMUserException e1) {
+                               e1.printStackTrace();
+                               status.message.emit(tr("User exception getting user account information.  Aborting sync and disconnecting"));
+                               syncSignal.errorDisconnect.emit();
+                               error = true;
+                               enDisconnect();
+                               return;
+                       } catch (EDAMSystemException e1) {
+                               if (e1.getErrorCode() == EDAMErrorCode.RATE_LIMIT_REACHED) {
+                                       limitSignal.rateLimitReached.emit(e1.getRateLimitDuration());
+                               }
+                               
+                               e1.printStackTrace();
+                               status.message.emit(tr("System error user account information.  Aborting sync and disconnecting!"));
+                               syncSignal.errorDisconnect.emit();
+                               error = true;
+                               enDisconnect();
+                               return;
+                       } catch (TException e1) {
+                               e1.printStackTrace();
+                               syncSignal.errorDisconnect.emit();
+                               error = true;
+                               status.message.emit(tr("Transaction error getting user account information.  Aborting sync and disconnecting!"));
+                               enDisconnect();
+                               return;
+                       }
+                       
+                       // Get sync state
+                       SyncState syncState = null;
+                       try {   
+                               logger.log(logger.EXTREME, "Getting sync state");
+                               syncState = noteStore.getSyncState(authToken);  
+                               syncSignal.saveUploadAmount.emit(syncState.getUploaded());
+                               syncSignal.saveEvernoteUpdateCount.emit(syncState.getUpdateCount());
+                               evernoteUpdateCount = syncState.getUpdateCount();
+                       } catch (EDAMUserException e) {
+                               e.printStackTrace();
+                               status.message.emit(tr("Error getting sync state! Aborting sync and disconnecting!"));
+                               syncSignal.errorDisconnect.emit();
+                               enDisconnect();
+                               return;
+                       } catch (EDAMSystemException e) {
+                               if (e.getErrorCode() == EDAMErrorCode.RATE_LIMIT_REACHED) {
+                                       limitSignal.rateLimitReached.emit(e.getRateLimitDuration());
+                               }
+                               e.printStackTrace();
+                               status.message.emit(tr("Error getting sync state! Aborting sync and disconnecting!"));
+                               syncSignal.errorDisconnect.emit();
+                               enDisconnect();
+                               return;
+                       } catch (TException e) {
+                               e.printStackTrace();
+                               status.message.emit(tr("Error getting sync state! Aborting sync and disconnecting!"));
+                               syncSignal.errorDisconnect.emit();
+                               enDisconnect();
+                               return;
+                       }
+                       
+                       if (syncState == null) {
+                               logger.log(logger.EXTREME, "Sync State is null");
+                               status.message.emit(tr("Syncronization Error!"));
+                               return;
+                       }
+
+                       // Determine what to do. 
+                       // If we need to do a full sync.
+                       logger.log(logger.LOW, "Full Sequence Before: " +syncState.getFullSyncBefore());
+                       logger.log(logger.LOW, "Last Sequence Date: " +sequenceDate);
+                       logger.log(logger.LOW, "Var Last Sequence Number: " +updateSequenceNumber);
+                       logger.log(logger.LOW, "DB Last Sequence Number: " + conn.getSyncTable().getUpdateSequenceNumber());
+                       if (syncState.getFullSyncBefore() > sequenceDate) {
+                               logger.log(logger.EXTREME, "Full sequence date has expired");
+                               sequenceDate = 0;
+                               conn.getSyncTable().setLastSequenceDate(0);
+                               updateSequenceNumber = 0;
+                               conn.getSyncTable().setUpdateSequenceNumber(0);
+                       }
+                       // Check for "special" sync instructions
+                       String syncLinked = conn.getSyncTable().getRecord("FullLinkedNotebookSync");
+                       String syncShared = conn.getSyncTable().getRecord("FullSharedNotebookSync");
+                       String syncNotebooks = conn.getSyncTable().getRecord("FullNotebookSync");
+                       String syncInkNoteImages = conn.getSyncTable().getRecord("FullInkNoteImageSync");
+                       if (syncLinked != null) {
+                               downloadAllLinkedNotebooks(localNoteStore);
+                       }
+                       if (syncShared != null) {
+                               downloadAllSharedNotebooks(localNoteStore);
+                       }
+                       if (syncNotebooks != null) {
+                               downloadAllNotebooks(localNoteStore);
+                       }
+                       
+                       if (syncInkNoteImages != null) {
+                               List<String> guids = conn.getNoteTable().noteResourceTable.findInkNotes();
+                               for (int i=0; i<guids.size(); i++) {
+                                       downloadInkNoteImage(guids.get(i), authToken);
+                               }
+                               conn.getSyncTable().deleteRecord("FullInkNoteImageSync");
+                       }
+                       
+                       // If there are remote changes
+                       logger.log(logger.LOW, "Update Count: " +syncState.getUpdateCount());
+                       logger.log(logger.LOW, "Last Update Count: " +updateSequenceNumber);
+                       
+                       if (syncState.getUpdateCount() > updateSequenceNumber) {
+                               logger.log(logger.EXTREME, "Refresh needed is true");
+                               refreshNeeded = true;
+                               logger.log(logger.EXTREME, "Downloading changes");
+                               syncRemoteToLocal(localNoteStore);
+                       }
+                       
+                       //*****************************************
+                       //* Sync linked/shared notebooks 
+                       //*****************************************
+                       syncLinkedNotebooks();
+                       //conn.getNoteTable().getDirty();
+                       //disableUploads = true;   /// DELETE THIS LINE!!!!
+                       if (!disableUploads) {
+                               logger.log(logger.EXTREME, "Uploading changes");
+                               // Synchronize remote changes
+                               if (!error)
+                                       syncExpunged(localNoteStore);
+                               if (!error)
+                                       syncLocalTags(localNoteStore);
+                               if (!error)
+                                       syncLocalNotebooks(localNoteStore);
+                               if (!error)
+                                       syncLocalLinkedNotebooks(localNoteStore);
+                               if (!error) 
+                                       syncDeletedNotes(localNoteStore);
+                               if (!error)
+                                       syncLocalNotes();
+                               if (!error)
+                                       syncLocalSavedSearches(localNoteStore);
+                       }
+                       
+                       status.message.emit(tr("Cleaning up"));
+                       List<String> notes = conn.getNoteTable().expungeIgnoreSynchronizedNotes(conn.getSyncTable().getIgnoreRecords("NOTEBOOK"), 
+                                       conn.getSyncTable().getIgnoreRecords("TAG"), conn.getSyncTable().getIgnoreRecords("LINKEDNOTEBOOK"));
+                       if (notes.size() > 0)
+                               syncSignal.refreshLists.emit();
+                       
+                       //*****************************************
+                       //* End of synchronization
+                       //*****************************************
+                       if (refreshNeeded)
+                               syncSignal.refreshLists.emit();
+                       
+                       if (!error) {
+                               logger.log(logger.LOW, "Sync completed.  Errors=" +error);
+                               if (!disableUploads) 
+                                       status.message.emit(tr("Synchronizing complete"));
+                               else
+                                       status.message.emit(tr("Download syncronization complete.  Uploads have been disabled."));
+                               
+                               logger.log(logger.EXTREME, "Saving sync time");
+                               if (syncState.getCurrentTime() > sequenceDate)
+                                       sequenceDate = syncState.getCurrentTime();
+                               if (syncState.getUpdateCount() > updateSequenceNumber)
+                                       updateSequenceNumber = syncState.getUpdateCount();
+                               conn.getSyncTable().setLastSequenceDate(sequenceDate);
+                               conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);
+                       }
+               }
+               logger.log(logger.HIGH, "Leaving SyncRunner.evernoteSync");
+       }
+       
+       // Sync deleted items with Evernote
+       private void syncExpunged(Client noteStore) {
+               logger.log(logger.HIGH, "Entering SyncRunner.syncExpunged");
+               
+               List<DeletedItemRecord> expunged = conn.getDeletedTable().getAllDeleted();
+               boolean error = false;
+               for (int i=0; i<expunged.size() && keepRunning; i++) {
+
+//                     if (authRefreshNeeded)
+//                             if (!refreshConnection())
+//                                     return;
+
+                       try {
+                               if (expunged.get(i).type.equalsIgnoreCase("TAG")) {
+                                       logger.log(logger.EXTREME, "Tag expunged");
+                                       conn.getDeletedTable().expungeDeletedItem(expunged.get(i).guid, "TAG"); 
+                                       updateSequenceNumber = noteStore.expungeTag(authToken, expunged.get(i).guid);
+                                       conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);
+                                       conn.getSyncTable().setLastSequenceDate(sequenceDate);
+                                       conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);                              
+                               }
+                               if      (expunged.get(i).type.equalsIgnoreCase("NOTEBOOK")) {
+                                       logger.log(logger.EXTREME, "Notebook expunged");
+                                       conn.getDeletedTable().expungeDeletedItem(expunged.get(i).guid, "NOTEBOOK");
+                                       updateSequenceNumber = noteStore.expungeNotebook(authToken, expunged.get(i).guid);
+                                       conn.getSyncTable().setLastSequenceDate(sequenceDate);
+                                       conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);
+                               }
+                               if (expunged.get(i).type.equalsIgnoreCase("NOTE")) {
+                                       logger.log(logger.EXTREME, "Note expunged");
+                                       conn.getDeletedTable().expungeDeletedItem(expunged.get(i).guid, "NOTE");
+                                       updateSequenceNumber = noteStore.deleteNote(authToken, expunged.get(i).guid);
+                                       refreshNeeded = true;
+                                       conn.getSyncTable().setLastSequenceDate(sequenceDate);
+                                       conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);
+                               }
+                               if (expunged.get(i).type.equalsIgnoreCase("SAVEDSEARCH")) {
+                                       logger.log(logger.EXTREME, "saved search expunged");
+                                       conn.getDeletedTable().expungeDeletedItem(expunged.get(i).guid, "SAVEDSEARCH");
+                                       updateSequenceNumber = noteStore.expungeSearch(authToken, expunged.get(i).guid);
+                                       conn.getSyncTable().setLastSequenceDate(sequenceDate);
+                                       conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);
+                               }
+                       } catch (EDAMUserException e) {
+                               logger.log(logger.LOW, "EDAM User Excepton in syncExpunged: " +expunged.get(i).guid);   // This can happen if we try to delete a deleted note
+                       } catch (EDAMSystemException e) {
+                               if (e.getErrorCode() == EDAMErrorCode.RATE_LIMIT_REACHED) {
+                                       limitSignal.rateLimitReached.emit(e.getRateLimitDuration());
+                               }
+                               logger.log(logger.LOW, "EDAM System Excepton in syncExpunged: "+expunged.get(i).guid);
+                               logger.log(logger.LOW, e.getStackTrace());
+                               error=true;
+                       } catch (EDAMNotFoundException e) {
+                               logger.log(logger.LOW, "EDAM Not Found Excepton in syncExpunged: "+expunged.get(i).guid);
+                       } catch (TException e) {
+                               logger.log(logger.LOW, "EDAM TExcepton in syncExpunged: "+expunged.get(i).guid);
+                               logger.log(logger.LOW, e.getStackTrace());
+                               error=true;
+                       }
+               }
+               if (!error)
+                       conn.getDeletedTable().expungeAllDeletedRecords();
+               
+               logger.log(logger.HIGH, "Leaving SyncRunner.syncExpunged");
+
+       }
+       private void syncDeletedNotes(Client noteStore) {
+               if (syncDeletedContent)
+                       return;
+               logger.log(logger.HIGH, "Entering SyncRunner.syncDeletedNotes");
+               status.message.emit(tr("Synchronizing deleted notes."));
+
+               List<Note> notes = conn.getNoteTable().getDirty();
+               // Sync the local notebooks with Evernote's
+               for (int i=0; i<notes.size() && keepRunning; i++) {
+                       
+//                     if (authRefreshNeeded)
+//                             if (!refreshConnection())
+//                                     return;
+                       
+                       Note enNote = notes.get(i);
+                       try {
+                               if (enNote.getUpdateSequenceNum() > 0 && (enNote.isActive() == false || enNote.getDeleted() > 0)) {
+                                       // Check that the note is valid.  
+                                       if (enNote.isActive() == true || enNote.getDeleted() == 0) {
+                                               conn.getNoteTable().deleteNote(enNote.getGuid());
+                                               enNote = conn.getNoteTable().getNote(enNote.getGuid(), false, false, false, false, false);
+                                       }
+                                       if (syncDeletedContent) {
+                                               logger.log(logger.EXTREME, "Deleted note found & synch content selected");
+                                               Note delNote = conn.getNoteTable().getNote(enNote.getGuid(), true, true, true, true, true);
+                                               delNote = getNoteContent(delNote);
+                                               delNote = noteStore.updateNote(authToken, delNote);
+                                               enNote.setUpdateSequenceNum(delNote.getUpdateSequenceNum());
+                                               conn.getNoteTable().updateNoteSequence(enNote.getGuid(), enNote.getUpdateSequenceNum());
+                                       } else {
+                                               logger.log(logger.EXTREME, "Deleted note found & sync content not selected");
+                                               int usn = noteStore.deleteNote(authToken, enNote.getGuid());
+                                               enNote.setUpdateSequenceNum(usn);
+                                               conn.getNoteTable().updateNoteSequence(enNote.getGuid(), enNote.getUpdateSequenceNum());                                                
+                                       }
+                                       logger.log(logger.EXTREME, "Resetting deleted dirty flag");
+                                       conn.getNoteTable().resetDirtyFlag(enNote.getGuid());
+                                       updateSequenceNumber = enNote.getUpdateSequenceNum();
+                                       logger.log(logger.EXTREME, "Saving sequence number");
+                                       conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);
+                               }                               
+                       } catch (EDAMUserException e) {
+                               logger.log(logger.LOW, "*** EDAM User Excepton syncLocalNotes "+e);
+                               //status.message.emit("Error sending local note: " +e.getParameter());
+                               //logger.log(logger.LOW, e.toString()); 
+                               //error = true;
+                       } catch (EDAMSystemException e) {
+                               if (e.getErrorCode() == EDAMErrorCode.RATE_LIMIT_REACHED) {
+                                       limitSignal.rateLimitReached.emit(e.getRateLimitDuration());
+                               }
+                               logger.log(logger.LOW, "*** EDAM System Excepton syncLocalNotes "+e);
+                               status.message.emit(tr("Error: ") +e);
+                               logger.log(logger.LOW, e.toString());           
+                               error = true;
+                       } catch (EDAMNotFoundException e) {
+                               logger.log(logger.LOW, "*** EDAM Not Found Excepton syncLocalNotes " +e);
+                               //status.message.emit("Error deleting local note: " +e +" - Continuing");
+                               //logger.log(logger.LOW, e.toString());         
+                               //error = true;
+                       } catch (TException e) {
+                               logger.log(logger.LOW, "*** EDAM TExcepton syncLocalNotes "+e);
+                               status.message.emit(tr("Error sending local note: ") +e);
+                               logger.log(logger.LOW, e.toString());   
+                               error = true;
+                       }               
+               }
+       }
+       // Sync notes with Evernote
+       private void syncLocalNotes() {
+               logger.log(logger.HIGH, "Entering SyncRunner.syncNotes");
+               logger.log(logger.LOW, "Dirty local notes found: " +new Integer(conn.getNoteTable().getDirtyCount()).toString());
+               status.message.emit(tr("Sending local notes."));
+
+               List<Note> notes = conn.getNoteTable().getDirty();
+               // Sync the local notebooks with Evernote's
+               for (int i=0; i<notes.size() && keepRunning; i++) {
+                       syncLocalNote(localNoteStore, notes.get(i), authToken);
+               }
+               logger.log(logger.HIGH, "Leaving SyncRunner.syncNotes");
+
+       }
+       // Sync notes with Evernote
+       private void syncLocalNote(Client noteStore, Note enNote, String token) {
+               logger.log(logger.HIGH, "Entering SyncRunner.syncNotes");
+               status.message.emit(tr("Sending local notes."));
+                       
+               if (enNote.isActive()) {
+                       try {
+                               if (enNote.getUpdateSequenceNum() > 0) {
+                                       logger.log(logger.EXTREME, "Active dirty note found - non new - " +enNote.getGuid());
+                                       logger.log(logger.EXTREME, "Fetching note content");
+                                       enNote = getNoteContent(enNote);
+                                       logger.log(logger.MEDIUM, "Updating note : "+ enNote.getGuid() +" <title>" +enNote.getTitle()+"</title>");
+                                       enNote = noteStore.updateNote(token, enNote);
+                               } else { 
+                                       logger.log(logger.EXTREME, "Active dirty found - new note " +enNote.getGuid());
+                                       String oldGuid = enNote.getGuid();
+                                       logger.log(logger.MEDIUM, "Fetching note content");
+                                       enNote = getNoteContent(enNote);
+                                       logger.log(logger.MEDIUM, "Creating note : "+ enNote.getGuid() +" <title>" +enNote.getTitle()+"</title>");
+                                       enNote = noteStore.createNote(token, enNote);
+                                       logger.log(logger.MEDIUM, "New note Guid : "+ enNote.getGuid() +" <title>" +enNote.getTitle()+"</title>");
+                                       noteSignal.guidChanged.emit(oldGuid, enNote.getGuid());
+                                       conn.getNoteTable().updateNoteGuid(oldGuid, enNote.getGuid());
+                               }
+                               updateSequenceNumber = enNote.getUpdateSequenceNum();
+                               logger.log(logger.EXTREME, "Saving note");
+                               conn.getNoteTable().updateNoteSequence(enNote.getGuid(), enNote.getUpdateSequenceNum());
+                               List<Resource> rl = enNote.getResources();
+                               logger.log(logger.EXTREME, "Getting note resources");
+                               for (int j=0; j<enNote.getResourcesSize() && keepRunning; j++) {
+                                       Resource newRes = rl.get(j);
+                                       Data d = newRes.getData();
+                                       if (d!=null) {  
+                                               logger.log(logger.EXTREME, "Calculating resource hash");
+                                               String hash = byteArrayToHexString(d.getBodyHash());
+                                               logger.log(logger.EXTREME, "updating resources by hash");
+                                               String oldGuid = conn.getNoteTable().noteResourceTable.getNoteResourceGuidByHashHex(enNote.getGuid(), hash);
+                                               conn.getNoteTable().updateNoteResourceGuidbyHash(enNote.getGuid(), newRes.getGuid(), hash);
+                                               resourceSignal.resourceGuidChanged.emit(enNote.getGuid(), oldGuid, newRes.getGuid());
+                                       }
+                               }
+                               logger.log(logger.EXTREME, "Resetting note dirty flag");
+                               conn.getNoteTable().resetDirtyFlag(enNote.getGuid());
+                               updateSequenceNumber = enNote.getUpdateSequenceNum();
+                               logger.log(logger.EXTREME, "Emitting note sequence number change");
+                               conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);
+
+                       } catch (EDAMUserException e) {
+                               logger.log(logger.LOW, "*** EDAM User Excepton syncLocalNotes "+e);
+                               status.message.emit(tr("Error sending local note: ")     +e.getParameter());
+                               logger.log(logger.LOW, e.toString());   
+                               error = true;
+                       } catch (EDAMSystemException e) {
+                               if (e.getErrorCode() == EDAMErrorCode.RATE_LIMIT_REACHED) {
+                                       limitSignal.rateLimitReached.emit(e.getRateLimitDuration());
+                               }
+                               logger.log(logger.LOW, "*** EDAM System Excepton syncLocalNotes "+e);
+                               status.message.emit(tr("Error: ") +e);
+                               logger.log(logger.LOW, e.toString());           
+                               error = true;
+                       } catch (EDAMNotFoundException e) {
+                               logger.log(logger.LOW, "*** EDAM Not Found Excepton syncLocalNotes " +e);
+                               status.message.emit(tr("Error sending local note: ") +e);
+                               logger.log(logger.LOW, e.toString());   
+                               error = true;
+                       } catch (TException e) {
+                               logger.log(logger.LOW, "*** EDAM TExcepton syncLocalNotes "+e);
+                               status.message.emit(tr("Error sending local note: ") +e);
+                               logger.log(logger.LOW, e.toString());   
+                               error = true;
+                       }
+               }
+               logger.log(logger.HIGH, "Leaving SyncRunner.syncLocalNote");
+
+       }
+
+       // Sync Notebooks with Evernote
+       private void syncLocalNotebooks(Client noteStore) {
+               logger.log(logger.HIGH, "Entering SyncRunner.syncLocalNotebooks");
+               
+               status.message.emit(tr("Sending local notebooks."));
+               List<Notebook> remoteList = new ArrayList<Notebook>();
+               try {
+                       logger.log(logger.EXTREME, "Getting remote notebooks to compare with local");
+                       remoteList = noteStore.listNotebooks(authToken);
+               } catch (EDAMUserException e1) {
+                       logger.log(logger.LOW, "*** EDAM User Excepton syncLocalNotebooks getting remote Notebook List");
+                       status.message.emit(tr("Error: ") +e1);
+                       logger.log(logger.LOW, e1.toString());          
+                       error = true;
+               } catch (EDAMSystemException e1) {
+                       if (e1.getErrorCode() == EDAMErrorCode.RATE_LIMIT_REACHED) {
+                               limitSignal.rateLimitReached.emit(e1.getRateLimitDuration());
+                       }
+                       logger.log(logger.LOW, "*** EDAM System Excepton syncLocalNotebooks getting remote Notebook List");
+                       status.message.emit(tr("Error: ") +e1);
+                       logger.log(logger.LOW, e1.toString());  
+                       error = true;
+               } catch (TException e1) {
+                       logger.log(logger.LOW, "*** EDAM Transaction Excepton syncLocalNotebooks getting remote Notebook List");
+                       status.message.emit(tr("Error: ") +e1);
+                       logger.log(logger.LOW, e1.toString());  
+                       error = true;
+               }
+               logger.log(logger.EXTREME, "Getting local dirty notebooks");
+               List<Notebook> notebooks = conn.getNotebookTable().getDirty();
+               int sequence;
+               // Sync the local notebooks with Evernote's
+               for (int i=0; i<notebooks.size() && keepRunning; i++) {
+                       
+//                     if (authRefreshNeeded)
+//                             if (!refreshConnection())
+//                                     return;
+                       
+                       Notebook enNotebook = notebooks.get(i);
+                       try {
+                               if (enNotebook.getUpdateSequenceNum() > 0) {
+                                       logger.log(logger.EXTREME, "Existing notebook is dirty");
+                                       sequence = noteStore.updateNotebook(authToken, enNotebook);
+                               } else {
+                                       logger.log(logger.EXTREME, "New dirty notebook found");
+                                       String oldGuid = enNotebook.getGuid();
+                                       boolean found = false;
+                                       
+                                       // Look for a notebook with the same name.  If one is found, we don't need 
+                                       // to create another one
+                                       logger.log(logger.EXTREME, "Looking for matching notebook name");
+                                       for (int k=0; k<remoteList.size() && !found && keepRunning; k++) {
+                                               if (remoteList.get(k).getName().equalsIgnoreCase(enNotebook.getName())) {
+                                                       enNotebook = remoteList.get(k);
+                                                       logger.log(logger.EXTREME, "Matching notebook found");
+                                                       found = true;
+                                               }
+                                       }
+                                       if (!found)
+                                               enNotebook = noteStore.createNotebook(authToken, enNotebook);
+                                       
+                                       logger.log(logger.EXTREME, "Updating notebook in database");
+                                       conn.getNotebookTable().updateNotebookGuid(oldGuid, enNotebook.getGuid());
+                                       sequence = enNotebook.getUpdateSequenceNum();
+                               }
+                               logger.log(logger.EXTREME, "Updating notebook sequence in database");
+                               conn.getNotebookTable().updateNotebookSequence(enNotebook.getGuid(), sequence);
+                               logger.log(logger.EXTREME, "Resetting dirty flag in notebook");
+                               conn.getNotebookTable().resetDirtyFlag(enNotebook.getGuid());
+                               updateSequenceNumber = sequence;
+                               logger.log(logger.EXTREME, "Emitting sequence number to main thread");
+                               conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);
+                       } catch (EDAMUserException e) {
+                               logger.log(logger.LOW, "*** EDAM User Excepton syncLocalNotebooks");
+                               logger.log(logger.LOW, e.toString() + ": Stack : " +enNotebook.getStack());     
+                               error = true;
+                       } catch (EDAMSystemException e) {
+                               if (e.getErrorCode() == EDAMErrorCode.RATE_LIMIT_REACHED) {
+                                       limitSignal.rateLimitReached.emit(e.getRateLimitDuration());
+                               }
+                               logger.log(logger.LOW, "*** EDAM System Excepton syncLocalNotebooks");
+                               logger.log(logger.LOW, e.toString());           
+                               error = true;
+                       } catch (EDAMNotFoundException e) {
+                               logger.log(logger.LOW, "*** EDAM Not Found Excepton syncLocalNotebooks");
+                               logger.log(logger.LOW, e.toString());           
+                               error = true;
+                       } catch (TException e) {
+                               logger.log(logger.LOW, "*** EDAM TExcepton syncLocalNotebooks");
+                               logger.log(logger.LOW, e.toString());   
+                               error = true;
+                       }               
+               }
+               logger.log(logger.HIGH, "Leaving SyncRunner.syncLocalNotebooks");
+
+       }
+       // Sync Tags with Evernote
+       private void syncLocalTags(Client noteStore) {
+               logger.log(logger.HIGH, "Entering SyncRunner.syncLocalTags");
+               List<Tag> remoteList = new ArrayList<Tag>();
+               status.message.emit(tr("Sending local tags."));
+               
+               try {
+                       logger.log(logger.EXTREME, "Getting remote tags to compare names with the local tags");
+                       remoteList = noteStore.listTags(authToken);
+               } catch (EDAMUserException e1) {
+                       logger.log(logger.LOW, "*** EDAM User Excepton syncLocalTags getting remote Tag List");
+                       status.message.emit(tr("Error: ") +e1);
+                       logger.log(logger.LOW, e1.toString());  
+                       error = true;
+               } catch (EDAMSystemException e1) {
+                       if (e1.getErrorCode() == EDAMErrorCode.RATE_LIMIT_REACHED) {
+                               limitSignal.rateLimitReached.emit(e1.getRateLimitDuration());
+                       }
+                       logger.log(logger.LOW, "*** EDAM System Excepton syncLocalTags getting remote Tag List");
+                       status.message.emit(tr("Error: ") +e1);
+                       logger.log(logger.LOW, e1.toString());          
+                       error = true;
+               } catch (TException e1) {
+                       logger.log(logger.LOW, "*** EDAM Transaction Excepton syncLocalTags getting remote Tag List");
+                       status.message.emit(tr("Error: ") +e1);
+                       logger.log(logger.LOW, e1.toString());  
+                       error = true;
+               }               
+               
+               int sequence;
+               
+               if (badTagSync == null)
+                       badTagSync = new HashMap<String,String>();
+               else
+                       badTagSync.clear();
+               
+               Tag enTag = findNextTag();
+               
+               // This is a hack.  Sometimes this function goes flookey and goes into a 
+               // perpetual loop.  This causes  NeverNote to flood Evernote's servers.
+               // This is a safety valve to prevent unlimited loops.
+               int maxCount = conn.getTagTable().getDirty().size()+10;
+               int loopCount = 0;
+               
+               while(enTag!=null && loopCount < maxCount) {
+                       loopCount++;
+//                     if (authRefreshNeeded)
+//                             if (!refreshConnection())
+//                                     return;
+
+                       try {
+                               if (enTag.getUpdateSequenceNum() > 0) {
+                                       logger.log(logger.EXTREME, "Updating tag");
+                                       sequence = noteStore.updateTag(authToken, enTag);
+                               } else {
+                                       
+                                       // Look for a tag with the same name.  If one is found, we don't need 
+                                       // to create another one
+                                       logger.log(logger.EXTREME, "New tag.  Comparing with remote names");
+                                       boolean found = false;
+                                       String oldGuid = enTag.getGuid();
+                                       for (int k=0; k<remoteList.size() && !found && keepRunning; k++) {
+                                               if (remoteList.get(k).getName().equalsIgnoreCase(enTag.getName())) {
+                                                       conn.getTagTable().updateTagGuid(enTag.getGuid(), remoteList.get(k).getGuid());
+                                                       enTag = remoteList.get(k);
+                                                       logger.log(logger.EXTREME, "Matching tag name found");
+                                                       found = true;
+                                               }
+                                       }
+                                       if (!found)
+                                               enTag = noteStore.createTag(authToken, enTag);
+                                       else
+                                               enTag.setUpdateSequenceNum(noteStore.updateTag(authToken,enTag));
+                                       sequence = enTag.getUpdateSequenceNum();
+                                       if (!oldGuid.equals(enTag.getGuid())) {
+                                               logger.log(logger.EXTREME, "Updating tag guid");
+                                               conn.getTagTable().updateTagGuid(oldGuid, enTag.getGuid());
+                                       }
+                               }
+                               logger.log(logger.EXTREME, "Updating tag sequence number");
+                               conn.getTagTable().updateTagSequence(enTag.getGuid(), sequence);
+                               logger.log(logger.EXTREME, "Resetting tag dirty flag");
+                               conn.getTagTable().resetDirtyFlag(enTag.getGuid());
+                               logger.log(logger.EXTREME, "Emitting sequence number to the main thread.");
+                               updateSequenceNumber = sequence;
+                               conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);
+                       } catch (EDAMUserException e) {
+                               logger.log(logger.LOW, "*** EDAM User Excepton syncLocalTags: " +enTag.getName());
+                               logger.log(logger.LOW, e.toString());
+                               badTagSync.put(enTag.getGuid(),null);
+                               error = true;
+                       } catch (EDAMSystemException e) {
+                               if (e.getErrorCode() == EDAMErrorCode.RATE_LIMIT_REACHED) {
+                                       limitSignal.rateLimitReached.emit(e.getRateLimitDuration());
+                               }
+                               logger.log(logger.LOW, "** EDAM System Excepton syncLocalTags: " +enTag.getName());
+                               logger.log(logger.LOW, e.toString());   
+                               badTagSync.put(enTag.getGuid(),null);
+                               error = true;
+                       } catch (EDAMNotFoundException e) {
+                               logger.log(logger.LOW, "*** EDAM Not Found Excepton syncLocalTags: " +enTag.getName());
+                               logger.log(logger.LOW, e.toString());
+                               badTagSync.put(enTag.getGuid(),null);
+                               error = true;
+                       } catch (TException e) {
+                               logger.log(logger.LOW, "*** EDAM TExcepton syncLocalTags: " +enTag.getName());
+                               logger.log(logger.LOW, e.toString());
+                               badTagSync.put(enTag.getGuid(),null);
+                               error = true;
+                       }       
+                       
+                       // Find the next tag
+                       logger.log(logger.EXTREME, "Finding next tag");
+                       enTag = findNextTag();
+               }
+               logger.log(logger.HIGH, "Leaving SyncRunner.syncLocalTags");
+       }
+       private void syncLocalLinkedNotebooks(Client noteStore) {
+               logger.log(logger.HIGH, "Entering SyncRunner.syncLocalLinkedNotebooks");
+               
+               List<String> list = conn.getLinkedNotebookTable().getDirtyGuids();
+               for (int i=0; i<list.size(); i++) {
+                       LinkedNotebook book = conn.getLinkedNotebookTable().getNotebook(list.get(i));
+                       try {
+                               noteStore.updateLinkedNotebook(authToken, book);
+                       } catch (EDAMUserException e) {
+                               logger.log(logger.LOW, "*** EDAM User Excepton syncLocalLinkedNotebooks");
+                               status.message.emit(tr("Error: ") +e);
+                               logger.log(logger.LOW, e.toString());           
+                               error = true;
+                               e.printStackTrace();
+                       } catch (EDAMNotFoundException e) {
+                               logger.log(logger.LOW, "*** EDAM Not Found Excepton syncLocalLinkedNotebooks");
+                               status.message.emit(tr("Error: ") +e);
+                               logger.log(logger.LOW, e.toString());           
+                               error = true;
+                               e.printStackTrace();
+                       } catch (EDAMSystemException e) {
+                               if (e.getErrorCode() == EDAMErrorCode.RATE_LIMIT_REACHED) {
+                                       limitSignal.rateLimitReached.emit(e.getRateLimitDuration());
+                               }
+                               logger.log(logger.LOW, "*** EDAM System Excepton syncLocalLinkedNotebooks");
+                               status.message.emit(tr("Error: ") +e);
+                               logger.log(logger.LOW, e.toString());           
+                               error = true;
+                               e.printStackTrace();
+                       } catch (TException e) {
+                               logger.log(logger.LOW, "*** EDAM TExcepton syncLocalLinkedNotebooks");
+                               status.message.emit(tr("Error: ") +e);
+                               logger.log(logger.LOW, e.toString());           
+                               error = true;
+                               e.printStackTrace();
+                       }
+               }
+               logger.log(logger.HIGH, "Leaving SyncRunner.syncLocalLinkedNotebooks");
+       }
+       // Sync Saved Searches with Evernote
+       private void syncLocalSavedSearches(Client noteStore) {
+               logger.log(logger.HIGH, "Entering SyncRunner.syncLocalSavedSearches");
+               List<SavedSearch> remoteList = new ArrayList<SavedSearch>();
+               status.message.emit(tr("Sending saved searches."));
+       
+               logger.log(logger.EXTREME, "Getting saved searches to compare with local");
+               try {
+                       remoteList = noteStore.listSearches(authToken);
+               } catch (EDAMUserException e1) {
+                       logger.log(logger.LOW, "*** EDAM User Excepton syncLocalTags getting remote saved search List");
+                       status.message.emit(tr("Error: ") +e1);
+                       logger.log(logger.LOW, e1.toString());  
+                       error = true;
+               } catch (EDAMSystemException e1) {
+                       if (e1.getErrorCode() == EDAMErrorCode.RATE_LIMIT_REACHED) {
+                               limitSignal.rateLimitReached.emit(e1.getRateLimitDuration());
+                       }
+                       logger.log(logger.LOW, "*** EDAM System Excepton syncLocalTags getting remote saved search List");
+                       status.message.emit(tr("Error: ") +e1);
+                       logger.log(logger.LOW, e1.toString());          
+                       error = true;
+               } catch (TException e1) {
+                       logger.log(logger.LOW, "*** EDAM Transaction Excepton syncLocalTags getting remote saved search List");
+                       status.message.emit(tr("Error: ") +e1);
+                       logger.log(logger.LOW, e1.toString());  
+                       error = true;
+               }               
+               
+               List<SavedSearch> searches = conn.getSavedSearchTable().getDirty();
+               int sequence;
+               // Sync the local notebooks with Evernote's
+               logger.log(logger.EXTREME, "Beginning to send saved searches");
+               for (int i=0; i<searches.size() &&  keepRunning; i++) {
+                       
+//                     if (authRefreshNeeded)
+//                             if (!refreshConnection())
+//                                     return;
+                       
+                       SavedSearch enSearch = searches.get(i);
+                       try {
+                               if (enSearch.getUpdateSequenceNum() > 0) 
+                                       sequence = noteStore.updateSearch(authToken, enSearch);
+                               else {
+                                       logger.log(logger.EXTREME, "New saved search found.");
+                                       // Look for a tag with the same name.  If one is found, we don't need 
+                                       // to create another one
+                                       boolean found = false;
+                                       logger.log(logger.EXTREME, "Matching remote saved search names with local");
+                                       for (int k=0; k<remoteList.size() && !found && keepRunning; k++) {
+                                               if (remoteList.get(k).getName().equalsIgnoreCase(enSearch.getName())) {
+                                                       enSearch = remoteList.get(k);
+                                                       found = true;
+                                                       logger.log(logger.EXTREME, "Matching saved search found");
+                                                       sequence = enSearch.getUpdateSequenceNum();
+                                               }
+                                       }
+
+                                       String oldGuid = enSearch.getGuid();
+                                       if (!found)
+                                               enSearch = noteStore.createSearch(authToken, enSearch);
+                                       sequence = enSearch.getUpdateSequenceNum();
+                                       logger.log(logger.EXTREME, "Updating tag guid in local database");
+                                       conn.getSavedSearchTable().updateSavedSearchGuid(oldGuid, enSearch.getGuid());
+                               }
+                               logger.log(logger.EXTREME, "Updating tag sequence in local database");
+                               conn.getSavedSearchTable().updateSavedSearchSequence(enSearch.getGuid(), sequence);
+                               logger.log(logger.EXTREME, "Resetting tag dirty flag");
+                               conn.getSavedSearchTable().resetDirtyFlag(enSearch.getGuid());
+                               logger.log(logger.EXTREME, "Emitting sequence number to the main thread.");
+                               updateSequenceNumber = sequence;
+                               conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);
+                       } catch (EDAMUserException e) {
+                               logger.log(logger.LOW, "*** EDAM User Excepton syncLocalTags");
+                               logger.log(logger.LOW, e.toString());   
+                               error = true;
+                       } catch (EDAMSystemException e) {
+                               if (e.getErrorCode() == EDAMErrorCode.RATE_LIMIT_REACHED) {
+                                       limitSignal.rateLimitReached.emit(e.getRateLimitDuration());
+                               }
+                               logger.log(logger.LOW, "** EDAM System Excepton syncLocalTags");
+                               logger.log(logger.LOW, e.toString());   
+                               error = true;
+                       } catch (EDAMNotFoundException e) {
+                               logger.log(logger.LOW, "*** EDAM Not Found Excepton syncLocalTags");
+                               logger.log(logger.LOW, e.toString());   
+                               error = true;
+                       } catch (TException e) {
+                               logger.log(logger.LOW, "*** EDAM TExcepton syncLocalTags");
+                               logger.log(logger.LOW, e.toString());   
+                               error = true;
+                       }               
+               }
+
+               logger.log(logger.HIGH, "Entering SyncRunner.syncLocalSavedSearches");
+       }       
+
+       // Sync evernote changes with local database
+       private void syncRemoteToLocal(Client noteStore) {
+               logger.log(logger.HIGH, "Entering SyncRunner.syncRemoteToLocal");
+
+               List<Note> dirtyNotes = conn.getNoteTable().getDirty();
+               dirtyNoteGuids = new ArrayList<String>();
+               for (int i=0; i<dirtyNotes.size() && keepRunning; i++) {
+                       dirtyNoteGuids.add(dirtyNotes.get(i).getGuid());
+               }
+               
+               int chunkSize = 10;
+               SyncChunk chunk = null;
+               boolean fullSync = false;
+               boolean more = true;
+               
+               if (updateSequenceNumber == 0)
+                       fullSync = true;
+               
+               status.message.emit(tr("Downloading 0% complete."));
+               
+               while(more &&  keepRunning) {
+                       
+//                     if (authRefreshNeeded)
+//                             if (!refreshConnection())
+//                                     return;
+                       
+                       int sequence = updateSequenceNumber;
+                       try {
+//                             conn.beginTransaction();
+                               logger.log(logger.EXTREME, "Getting chunk from Evernote");
+                               chunk = noteStore.getSyncChunk(authToken, sequence, chunkSize, fullSync);
+                               logger.log(logger.LOW, "Chunk High Sequence: " +chunk.getChunkHighUSN());
+                       } catch (EDAMUserException e) {
+                               error = true;
+                               e.printStackTrace();
+                               status.message.emit(e.getMessage());
+                       } catch (EDAMSystemException e) {
+                               if (e.getErrorCode() == EDAMErrorCode.RATE_LIMIT_REACHED) {
+                                       limitSignal.rateLimitReached.emit(e.getRateLimitDuration());
+                               }
+                               error = true;
+                               e.printStackTrace();
+                               status.message.emit(e.getMessage());
+                       } catch (TException e) {
+                               error = true;
+                               e.printStackTrace();
+                               status.message.emit(e.getMessage());
+                       } 
+                       if (error || chunk == null) 
+                               return;
+                               
+               
+                       
+                       syncRemoteTags(chunk.getTags());
+                       syncRemoteSavedSearches(chunk.getSearches());
+                       syncRemoteNotebooks(chunk.getNotebooks());
+                       syncRemoteNotes(noteStore, chunk.getNotes(), fullSync, authToken);
+                       syncRemoteResources(noteStore, chunk.getResources());
+                       syncRemoteLinkedNotebooks(chunk.getLinkedNotebooks());
+                       
+                       // Signal about any updated notes to invalidate the cache
+                       for (int i=0; i<chunk.getNotesSize(); i++) 
+                               noteSignal.noteChanged.emit(chunk.getNotes().get(i).getGuid(), null); 
+                       syncExpungedNotes(chunk);
+                       
+                       
+                       // Check for more notes
+                       if (chunk.getChunkHighUSN() <= updateSequenceNumber) 
+                               more = false;
+                       if (error)
+                               more = false;
+                       logger.log(logger.EXTREME, "More notes? " +more);
+
+                       
+                       // Save the chunk sequence number
+                       if (!error && chunk.getChunkHighUSN() > 0 && keepRunning) {
+                               logger.log(logger.EXTREME, "emitting sequence number to main thread");
+                               updateSequenceNumber = chunk.getChunkHighUSN();
+                               conn.getSyncTable().setLastSequenceDate(chunk.getCurrentTime());
+                               conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);
+//                             conn.commitTransaction();
+                       }
+                       
+                       
+                       if (more) {
+                               long pct = chunk.getChunkHighUSN() * 100;
+                               conn.getSyncTable().setLastSequenceDate(chunk.getCurrentTime());
+                               pct = pct/evernoteUpdateCount;
+                               status.message.emit(tr("Downloading ") +new Long(pct).toString()+tr("% complete."));
+                       }
+//                     conn.commitTransaction();
+               }
+               logger.log(logger.HIGH, "Leaving SyncRunner.syncRemoteToLocal");
+       }
+       // Sync expunged notes
+       private void syncExpungedNotes(SyncChunk chunk) {
+               // Do the local deletes
+               logger.log(logger.EXTREME, "Doing local deletes");
+               List<String> guid = chunk.getExpungedNotes();
+               if (guid != null) {
+                       for (int i=0; i<guid.size() && keepRunning; i++) {
+                               String notebookGuid = "";
+                               Note localNote = conn.getNoteTable().getNote(guid.get(i), false, false, false, false, false);
+                               if (localNote != null) {
+                                       conn.getNoteTable().updateNoteSequence(guid.get(i), 0);
+                                       notebookGuid = localNote.getNotebookGuid();
+                               }
+                               // If the note is in a local notebook (which means we moved it) or if the 
+                               // note returned is null (which means it is already deleted or flagged expunged) 
+                               // we delete it.
+                               if (!conn.getNotebookTable().isNotebookLocal(notebookGuid) || localNote == null) {
+                                       logger.log(logger.EXTREME, "Expunging local note from database");
+                                       conn.getNoteTable().expungeNote(guid.get(i), true, false);
+                               }
+                       }
+               }
+               guid = chunk.getExpungedNotebooks();
+               if (guid != null)
+                       for (int i=0; i<guid.size() && keepRunning; i++) {
+                               logger.log(logger.EXTREME, "Expunging local notebook from database");
+                               conn.getNotebookTable().expungeNotebook(guid.get(i), false);
+                       }
+               guid = chunk.getExpungedTags();
+               if (guid != null)
+                       for (int i=0; i<guid.size() && keepRunning; i++) {
+                               logger.log(logger.EXTREME, "Expunging tags from local database");
+                               conn.getTagTable().expungeTag(guid.get(i), false);
+                       }
+               guid = chunk.getExpungedSearches();
+               if (guid != null) 
+                       for (int i=0; i<guid.size() && keepRunning; i++) {
+                               logger.log(logger.EXTREME, "Expunging saved search from local database");
+                               conn.getSavedSearchTable().expungeSavedSearch(guid.get(i), false);
+                       }
+               guid = chunk.getExpungedLinkedNotebooks();
+               if (guid != null) 
+                       for (int i=0; i<guid.size() && keepRunning; i++) {
+                               logger.log(logger.EXTREME, "Expunging linked notebook from local database");
+                               conn.getLinkedNotebookTable().expungeNotebook(guid.get(i), false);
+                       }
+
+       }
+       // Sync remote tags
+       private void syncRemoteTags(List<Tag> tags) {
+               logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteTags");
+               if (tags != null) {
+                       for (int i=0; i<tags.size() && keepRunning; i++) {
+                               String oldGuid;
+                               oldGuid = conn.getTagTable().findTagByName(tags.get(i).getName());
+                               if (oldGuid != null && !tags.get(i).getGuid().equalsIgnoreCase(oldGuid))
+                                       conn.getTagTable().updateTagGuid(oldGuid, tags.get(i).getGuid());
+                               conn.getTagTable().syncTag(tags.get(i), false);
+                       }
+               }
+               logger.log(logger.EXTREME, "Leaving SyncRunner.syncRemoteTags");
+       }
+       // Sync remote saved searches
+       private void syncRemoteSavedSearches(List<SavedSearch> searches) {
+               logger.log(logger.EXTREME, "Entering SyncRunner.syncSavedSearches");
+               if (searches != null) {
+                       for (int i=0; i<searches.size() && keepRunning; i++) {
+                               String oldGuid;
+                               oldGuid = conn.getSavedSearchTable().findSavedSearchByName(searches.get(i).getName());
+                               if (oldGuid != null && !searches.get(i).getGuid().equalsIgnoreCase(oldGuid))
+                                       conn.getSavedSearchTable().updateSavedSearchGuid(oldGuid, searches.get(i).getGuid());
+                               conn.getSavedSearchTable().syncSavedSearch(searches.get(i), false);
+                       }
+               }
+               logger.log(logger.EXTREME, "Leaving SyncRunner.syncSavedSearches");
+       }
+       // Sync remote linked notebooks
+       private void syncRemoteLinkedNotebooks(List<LinkedNotebook> books) {
+               logger.log(logger.EXTREME, "Entering SyncRunner.syncLinkedNotebooks");
+               if (books != null) {
+                       for (int i=0; i<books.size() && keepRunning; i++) {
+                               conn.getLinkedNotebookTable().updateNotebook(books.get(i), false); 
+                       }
+               }
+               logger.log(logger.EXTREME, "Leaving SyncRunner.syncLinkedNotebooks");
+       }
+       // Sync remote Notebooks 2
+       private void syncRemoteNotebooks(List<Notebook> notebooks) {
+               logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteNotebooks");
+               if (notebooks != null) {
+                       for (int i=0; i<notebooks.size() && keepRunning; i++) {
+                               String oldGuid;
+                               oldGuid = conn.getNotebookTable().findNotebookByName(notebooks.get(i).getName());
+                               if (oldGuid != null && !conn.getNotebookTable().isNotebookLocal(oldGuid) && !notebooks.get(i).getGuid().equalsIgnoreCase(oldGuid))
+                                       conn.getNotebookTable().updateNotebookGuid(oldGuid, notebooks.get(i).getGuid());
+                               conn.getNotebookTable().syncNotebook(notebooks.get(i), false); 
+                               
+                               // Synchronize shared notebook information
+//                             if (notebooks.get(i).getSharedNotebookIdsSize() > 0) {
+//                                     conn.getSharedNotebookTable().expungeNotebookByGuid(notebooks.get(i).getGuid(), false);
+//                                     for (int j=0; j<notebooks.get(i).getSharedNotebookIdsSize(); j++) {
+//                                             syncRemoteSharedNotebook(notebooks.get(i).getGuid(), notebooks.get(i).getSharedNotebookIds().get(j), authToken);
+//                                     }
+//                             }
+                       }
+               }                       
+               logger.log(logger.EXTREME, "Leaving SyncRunner.syncRemoteNotebooks");
+       }
+       // Sync remote shared notebook
+//     private void syncRemoteSharedNotebook(String guid, Long id, String token) {
+//             List<SharedNotebook> books = noteStore.getSharedNotebookByAuth(authToken);
+//     }
+       // Sync remote Resources
+       private void syncRemoteResources(Client noteStore, List<Resource> resource) {
+               logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteResources");
+               if (resource != null) {
+                       for (int i=0; i<resource.size() && keepRunning; i++) {
+                               syncRemoteResource(noteStore, resource.get(i), authToken);
+                       }
+               }
+               logger.log(logger.EXTREME, "Leaving SyncRunner.syncRemoteResources");
+       }
+       // Sync remote resource
+       private void syncRemoteResource(Client noteStore, Resource resource, String authToken) {
+               // This is how the logic for this works.
+               // 1.) If the resource is not in the local database, we add it.
+               // 2.) If a copy of the resource is in the local database and the note isn't dirty, we update the local copy
+               // 3.) If a copy of the resource is in the local databbase and it is dirty and the hash doesn't match, we ignore it because there
+               //     is a conflict.  The note conflict should get a copy of the resource at that time.
+               
+               Note n = conn.getNoteTable().getNote(resource.getNoteGuid(), false, false, false, false, false);
+               if (n!=null) {
+                       logger.log(logger.HIGH, "Resource for note " +n.getGuid() +" : " +n.getTitle());
+               }
+               boolean saveNeeded = false;
+               /* #1 */                Resource r = getEvernoteResource(noteStore, resource.getGuid(), true,true,true, authToken);
+                                               Resource l = conn.getNoteTable().noteResourceTable.getNoteResource(r.getGuid(), false);
+                                               if (l == null) {
+                                                       logger.log(logger.HIGH, "Local resource not found");
+                                                       saveNeeded = true;
+                                               } else {
+               /* #2 */                        boolean isNoteDirty = conn.getNoteTable().isNoteDirty(r.getNoteGuid());
+                                                       if (!isNoteDirty) {
+                                                               logger.log(logger.HIGH, "Local resource found, but is not dirty");
+                                                               saveNeeded = true;
+                                                       } else {
+               /* #3 */                                String remoteHash = "";
+                                                               if (r != null && r.getData() != null && r.getData().getBodyHash() != null)
+                                                                       remoteHash = byteArrayToHexString(r.getData().getBodyHash());
+                                                               String localHash = "";
+                                                               if (l != null && l.getData() != null && l.getData().getBodyHash() != null)
+                                                                       remoteHash = byteArrayToHexString(l.getData().getBodyHash());
+                                               
+                                                               if (localHash.equalsIgnoreCase(remoteHash))
+                                                                       saveNeeded = true;
+                                                       }
+                                               }
+                                               
+                                               logger.log(logger.HIGH, "Resource save needed: " +saveNeeded);
+                                               if (saveNeeded) 
+                                                       conn.getNoteTable().noteResourceTable.updateNoteResource(r, false);
+                                               if (r.getMime().equalsIgnoreCase("application/vnd.evernote.ink"))
+                                                       downloadInkNoteImage(r.getGuid(), authToken);
+               
+
+       }
+       // Sync remote notes
+       private void syncRemoteNotes(Client noteStore, List<Note> note, boolean fullSync, String token) {
+
+               if (note != null) {
+                       
+                       logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteNotes");
+                       logger.log(logger.LOW, "Local Dirty Notes: ");
+                       logger.log(logger.LOW, "Remote Dirty Notes:");
+                       for (int i=0; i<note.size();i++) {
+                               logger.log(logger.LOW, i +" : " +note.get(i).getGuid() + " : " +note.get(i).getTitle() );
+                       }
+                       logger.log(logger.LOW, "---");
+                       
+                       for (int i=0; i<note.size() && keepRunning; i++) {
+                               Note n = getEvernoteNote(noteStore, note.get(i).getGuid(), true, fullSync, true,true, token);
+                               syncRemoteNote(n, fullSync, token);
+                       }
+               }
+               logger.log(logger.EXTREME, "Leaving SyncRunner.syncRemoteNotes");
+       }
+       private void syncRemoteNote(Note n, boolean fullSync, String token) {
+               if (n!=null) {
+                       
+                       // Basically, this is how the sync logic for a note works.
+                       // If the remote note has changed and the local has not, we
+                       // accept the change.
+                       // If both the local & remote have changed but the sequence
+                       // numbers are the same, we don't accept the change.  This
+                       // seems to happen when attachments are indexed by the server.
+                       // If both the local & remote have changed and the sequence numbers
+                       // are different we move the local copy to a local notebook (making sure
+                       // to copy all resources) and we accept the new one.                    
+                       boolean conflictingNote = true;
+                       logger.log(logger.EXTREME, "Checking for duplicate note " +n.getGuid() +" : " +n.getTitle());
+                       if (dirtyNoteGuids != null && dirtyNoteGuids.contains(n.getGuid())) { 
+                               logger.log(logger.EXTREME, "Conflict check beginning");
+                               conflictingNote = checkForConflict(n);
+                               logger.log(logger.EXTREME, "Conflict check results " +conflictingNote);
+                               if (conflictingNote)
+                                       moveConflictingNote(n.getGuid());
+                       }
+                       boolean ignoreNote = false;
+                       if (ignoreNotebooks.contains(n.getNotebookGuid()))
+                               ignoreNote = true;
+                       for (int i=0; i<n.getTagGuidsSize(); i++) {
+                               if (ignoreTags.contains(n.getTagGuids().get(i))) {
+                                       ignoreNote = true;
+                                       i=n.getTagGuidsSize();
+                               }
+                       }
+                               
+                       if ((conflictingNote || fullSync) && !ignoreNote) {
+                               logger.log(logger.EXTREME, "Saving Note");
+                               conn.getNoteTable().syncNote(n);
+                               // The following was commented out because it caused a race condition on the database where resources 
+                               // may be lost.  We do the same thing elsewhere;.
+//                             noteSignal.noteChanged.emit(n.getGuid(), null);   // Signal to ivalidate note cache 
+                               noteSignal.noteDownloaded.emit(n, true);                // Signal to add note to index
+                                       logger.log(logger.EXTREME, "Note Saved");
+                               if (fullSync && n.getResources() != null) {
+                                       for (int q=0; q<n.getResources().size() && keepRunning; q++) {
+                                               logger.log(logger.EXTREME, "Getting note resources.");
+                                               conn.getNoteTable().noteResourceTable.updateNoteResource(n.getResources().get(q), false);
+                                               if (n.getResources().get(q).getMime().equalsIgnoreCase("application/vnd.evernote.ink"))
+                                                       downloadInkNoteImage(n.getResources().get(q).getGuid(), token);
+                                       }
+                               }
+                       }
+               }
+       }
+       private Note getEvernoteNote(Client noteStore, String guid, boolean withContent, boolean withResourceData, boolean withResourceRecognition, boolean withResourceAlternateData, String token) { 
+               Note n = null;
+               try {
+                       logger.log(logger.EXTREME, "Retrieving note " +guid);
+                       n = noteStore.getNote(token, guid, withContent, withResourceData, withResourceRecognition, withResourceAlternateData);
+                       logger.log(logger.EXTREME, "Note " +guid +" has been retrieved.");
+               } catch (EDAMUserException e) {
+                       logger.log(logger.LOW, "*** EDAM User Excepton getEvernoteNote");
+                       logger.log(logger.LOW, e.toString());   
+                       error = true;
+                       e.printStackTrace();
+               } catch (EDAMSystemException e) {
+                       if (e.getErrorCode() == EDAMErrorCode.RATE_LIMIT_REACHED) {
+                               limitSignal.rateLimitReached.emit(e.getRateLimitDuration());
+                       }
+                       logger.log(logger.LOW, "*** EDAM System Excepton getEvernoteNote");
+                       logger.log(logger.LOW, e.toString());   
+                       error = true;
+                       e.printStackTrace();
+               } catch (EDAMNotFoundException e) {
+                       logger.log(logger.LOW, "*** EDAM Not Found Excepton getEvernoteNote");
+                       logger.log(logger.LOW, e.toString());   
+                       error = true;
+                       e.printStackTrace();
+               } catch (TException e) {
+                       logger.log(logger.LOW, "*** EDAM TExcepton getEvernoteNote");
+                       logger.log(logger.LOW, e.toString());   
+                       error = true;
+                       e.printStackTrace();
+               }
+               return n;
+       }
+       private Resource getEvernoteResource(Client noteStore, String guid, boolean withData, boolean withRecognition, boolean withAttributes, String token) { 
+               Resource n = null;
+               try {
+                       logger.log(logger.EXTREME, "Retrieving resource " +guid);
+                       n = noteStore.getResource(token, guid, withData, withRecognition, withAttributes, withAttributes);
+                       logger.log(logger.EXTREME, "Resource " +guid +" has been retrieved.");
+               } catch (EDAMUserException e) {
+                       logger.log(logger.LOW, "*** EDAM User Excepton getEvernoteNote");
+                       logger.log(logger.LOW, e.toString());   
+                       error = true;
+                       e.printStackTrace();
+               } catch (EDAMSystemException e) {
+                       if (e.getErrorCode() == EDAMErrorCode.RATE_LIMIT_REACHED) {
+                               limitSignal.rateLimitReached.emit(e.getRateLimitDuration());
+                       }
+                       logger.log(logger.LOW, "*** EDAM System Excepton getEvernoteNote");
+                       logger.log(logger.LOW, e.toString());   
+                       error = true;
+                       e.printStackTrace();
+               } catch (EDAMNotFoundException e) {
+                       logger.log(logger.LOW, "*** EDAM Not Found Excepton getEvernoteNote");
+                       logger.log(logger.LOW, e.toString());   
+                       error = true;
+                       e.printStackTrace();
+               } catch (TException e) {
+                       logger.log(logger.LOW, "*** EDAM TExcepton getEvernoteNote");
+                       logger.log(logger.LOW, e.toString());   
+                       error = true;
+                       e.printStackTrace();
+               }
+               return n;
+       }
+
+       
+       private boolean checkForConflict(Note n) {
+               logger.log(logger.EXTREME, "Checking note sequence number  " +n.getGuid());
+               Note oldNote = conn.getNoteTable().getNote(n.getGuid(), false, false, false, false, false);
+               logger.log(logger.EXTREME, "Local/Remote sequence numbers: " +oldNote.getUpdateSequenceNum()+"/"+n.getUpdateSequenceNum());
+               logger.log(logger.LOW, "Remote Note Title:" +n.getTitle());
+               logger.log(logger.LOW, "Local Note Title:" +oldNote.getTitle());
+               if (oldNote.getUpdateSequenceNum() == n.getUpdateSequenceNum()) {
+                       return false;
+               } 
+               boolean oldIsDirty = conn.getNoteTable().isNoteDirty(n.getGuid());
+               if (!oldIsDirty) 
+                       return false;
+               return true;
+       }
+       
+       private void moveConflictingNote(String guid) {
+               logger.log(logger.EXTREME, "Conflicting change found for note " +guid);
+               List<Notebook> books = conn.getNotebookTable().getAllLocal();
+               String notebookGuid = null;
+               for (int i=0; i<books.size() && keepRunning; i++) {
+                       if (books.get(i).getName().equalsIgnoreCase("Conflicting Changes (local)") ||
+                                       books.get(i).getName().equalsIgnoreCase("Conflicting Changes")) {
+                               notebookGuid = books.get(i).getGuid();
+                               i=books.size();
+                       }
+               }
+               
+               if (notebookGuid == null) {
+                       logger.log(logger.EXTREME, "Building conflicting change notebook " +guid);
+                       Calendar currentTime = new GregorianCalendar();
+                       Long l = new Long(currentTime.getTimeInMillis());
+                       long prevTime = l;
+                       while (prevTime==l) {
+                               currentTime = new GregorianCalendar();
+                               l=currentTime.getTimeInMillis();
+                       }
+                       String randint = new String(Long.toString(l));
+               
+                       Notebook newBook = new Notebook();
+                       newBook.setUpdateSequenceNum(0);
+                       newBook.setGuid(randint);
+                       newBook.setName("Conflicting Changes");
+                       newBook.setServiceCreated(new Date().getTime());
+                       newBook.setServiceUpdated(new Date().getTime());
+                       newBook.setDefaultNotebook(false);
+                       newBook.setPublished(false);
+                       
+                       conn.getNotebookTable().addNotebook(newBook, false, true);
+                       notebookSignal.listChanged.emit();
+                       notebookGuid = newBook.getGuid();
+                       refreshNeeded = true;
+               }
+               
+               // Now that we have a good notebook guid, we need to move the conflicting note
+               // to the local notebook
+               logger.log(logger.EXTREME, "Moving conflicting note " +guid);
+               Calendar currentTime = new GregorianCalendar();
+               Long l = new Long(currentTime.getTimeInMillis());
+               long prevTime = l;
+               while (prevTime==l) {
+                       currentTime = new GregorianCalendar();
+                       l = currentTime.getTimeInMillis();
+               }
+               String newGuid = new String(Long.toString(l));
+                                       
+               Note oldNote = conn.getNoteTable().getNote(guid, true, true, false, false, false);
+               for (int i=0; i<oldNote.getResources().size() && keepRunning; i++) {
+                       l = new Long(currentTime.getTimeInMillis());
+                       String newResG = new String(Long.toString(l));
+                       String oldResG = oldNote.getResources().get(i).getGuid();
+                       conn.getNoteTable().noteResourceTable.resetUpdateSequenceNumber(oldResG, true);
+                       conn.getNoteTable().noteResourceTable.updateNoteResourceGuid(oldResG, newResG, true);
+               }
+               
+               conn.getNoteTable().resetNoteSequence(guid);
+               conn.getNoteTable().updateNoteGuid(guid, newGuid);
+               conn.getNoteTable().updateNoteNotebook(newGuid, notebookGuid, true);
+               
+               noteSignal.notebookChanged.emit(newGuid, notebookGuid);
+               refreshNeeded = true;
+               noteSignal.guidChanged.emit(guid,newGuid);
+       }
+       
+
+
+       
+       //******************************************************
+       //******************************************************
+       //** Utility Functions
+       //******************************************************
+       //******************************************************
+       // Convert a byte array to a hex string
+       private static String byteArrayToHexString(byte data[]) {
+               StringBuffer buf = new StringBuffer();
+           for (byte element : data) {
+               int halfbyte = (element >>> 4) & 0x0F;
+               int two_halfs = 0;
+               do {
+                       if ((0 <= halfbyte) && (halfbyte <= 9))
+                              buf.append((char) ('0' + halfbyte));
+                          else
+                               buf.append((char) ('a' + (halfbyte - 10)));
+                       halfbyte = element & 0x0F;
+               } while(two_halfs++ < 1);
+           }
+           return buf.toString();              
+       }
+
+       
+       
+       //*******************************************************
+       //* Find dirty tags, which do not have newly created parents
+       //*******************************************************
+       private Tag findNextTag() {
+               logger.log(logger.HIGH, "Entering SyncRunner.findNextTag");
+               Tag nextTag = null;
+               List<Tag> tags = conn.getTagTable().getDirty();
+               
+               // Find the parent.  If the parent has a sequence > 0 then it is a good
+               // parent.
+               for (int i=0; i<tags.size() && keepRunning; i++) {
+                       if (!badTagSync.containsKey(tags.get(i).getGuid())) {
+                               if (tags.get(i).getParentGuid() == null) {
+                                       logger.log(logger.HIGH, "Leaving SyncRunner.findNextTag - tag found without parent");
+                                       return tags.get(i);
+                               }
+                               Tag parentTag = conn.getTagTable().getTag(tags.get(i).getParentGuid());
+                               if (parentTag.getUpdateSequenceNum() > 0) {
+                                       logger.log(logger.HIGH, "Leaving SyncRunner.findNextTag - tag found");
+                                       return tags.get(i);
+                               }
+                       }
+               }
+               
+               logger.log(logger.HIGH, "Leaving SyncRunner.findNextTag - no tags returned");
+               return nextTag;
+       }
+       
+       
+          // Connect to Evernote
+    public boolean enConnect()  {
+       try {
+                       userStoreTrans = new THttpClient(userStoreUrl);
+                       userStoreTrans.setCustomHeader("User-Agent", userAgent);
+               } catch (TTransportException e) {
+                       QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, "Transport Excepton", e.getLocalizedMessage());
+                       mb.exec();
+                       e.printStackTrace();
+               }
+               userStoreProt = new TBinaryProtocol(userStoreTrans);
+           userStore = new UserStore.Client(userStoreProt, userStoreProt);
+           
+           syncSignal.saveUserStore.emit(userStore);
+           try {
+                       //authResult = userStore.authenticate(username, password, consumerKey, consumerSecret);
+               user = userStore.getUser(authToken);
+               } catch (EDAMUserException e) {
+                       QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, "Error", "Invalid Authorization");
+                       mb.exec();
+                       isConnected = false;
+                       return false;
+               } catch (EDAMSystemException e) {
+                       if (e.getErrorCode() == EDAMErrorCode.RATE_LIMIT_REACHED) {
+                               limitSignal.rateLimitReached.emit(e.getRateLimitDuration());
+                       }
+                       QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, "EDAM System Excepton", e.getLocalizedMessage());
+                       mb.exec();
+                       e.printStackTrace();
+                       isConnected = false;
+               } catch (TException e) {
+                       QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, "Transport Excepton", e.getLocalizedMessage());
+                       mb.exec();
+                       e.printStackTrace();
+                       isConnected = false;
+               }
+               
+           boolean versionOk = false;
+               try {
+                       versionOk = userStore.checkVersion("NeighborNote", 
+                   com.evernote.edam.userstore.Constants.EDAM_VERSION_MAJOR, 
+                     com.evernote.edam.userstore.Constants.EDAM_VERSION_MINOR);
+               } catch (TException e) {
+                       e.printStackTrace();
+                       isConnected = false;
+               } 
+           if (!versionOk) { 
+               System.err.println("Incomatible EDAM client protocol version"); 
+               isConnected = false;
+           }
+           //if (authResult != null) {
+               //user = authResult.getUser(); 
+               //authToken = authResult.getAuthenticationToken(); 
+           if (user == null || noteStoreUrlBase == null) {
+               logger.log(logger.LOW, "Error retrieving user information.  Aborting.");
+               System.err.println("Error retrieving user information.");
+               isConnected = false;    
+                       QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, tr("Connection Error"), tr("Error retrieving user information.  Synchronization not complete"));
+                       mb.exec();
+                       return false;
+               
+           }
+               noteStoreUrl = noteStoreUrlBase + user.getShardId();
+               syncSignal.saveAuthToken.emit(authToken);
+               syncSignal.saveNoteStore.emit(localNoteStore);
+               
+        
+               try {
+                       noteStoreTrans = new THttpClient(noteStoreUrl);
+                       noteStoreTrans.setCustomHeader("User-Agent", userAgent);
+               } catch (TTransportException e) {
+                       QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, "Transport Excepton", e.getLocalizedMessage());
+                       mb.exec();
+                       e.printStackTrace();
+                       isConnected = false;
+               } 
+               noteStoreProt = new TBinaryProtocol(noteStoreTrans);
+               localNoteStore = 
+                       new NoteStore.Client(noteStoreProt, noteStoreProt); 
+               isConnected = true;
+               //authTimeRemaining = authResult.getExpiration() - authResult.getCurrentTime();
+               //authRefreshTime = authTimeRemaining / 2;
+           //}
+           
+               // Get user information
+               try {
+                       User user = userStore.getUser(authToken);
+                       syncSignal.saveUserInformation.emit(user);
+               } catch (EDAMUserException e1) {
+                       e1.printStackTrace();
+               } catch (EDAMSystemException e1) {
+                       if (e1.getErrorCode() == EDAMErrorCode.RATE_LIMIT_REACHED) {
+                               limitSignal.rateLimitReached.emit(e1.getRateLimitDuration());
+                       }
+                       e1.printStackTrace();
+               } catch (TException e1) {
+                       e1.printStackTrace();
+               }
+           
+           return isConnected;
+    }
+       // Disconnect from the database                         
+    public void enDisconnect() {
+       isConnected = false;
+    }
+    
+    /*
+    // Refresh the connection
+    private synchronized boolean refreshConnection() {
+       
+               logger.log(logger.EXTREME, "Entering SyncRunner.refreshConnection()");
+//        Calendar cal = Calendar.getInstance();
+               
+        // If we are not connected let's get out of here
+        if (!isConnected)
+               return false;
+        
+               // If we fail too many times, then let's give up.
+               if (failedRefreshes >=5) {
+                       logger.log(logger.EXTREME, "Refresh attempts have failed.  Disconnecting.");
+                       isConnected = false;
+                       status.message.emit(tr("Unable to synchronize - Authentication failed"));
+                       return false;
+               }
+        
+               // If this is the first time through, then we need to set this
+//             if (authRefreshTime == 0 || cal.getTimeInMillis() > authRefreshTime) 
+//                     authRefreshTime = cal.getTimeInMillis();
+               
+ //            // Default to checking again in 5 min.  This in case we fail.
+ //            authRefreshTime = authRefreshTime +(5*60*1000);     
+
+               // Try to get a new token
+               AuthenticationResult newAuth = null; 
+               logger.log(logger.EXTREME, "Beginning to try authentication refresh");
+       try {
+               if (userStore != null && authToken != null) 
+                       newAuth = userStore.refreshAuthentication(authToken); 
+               else
+                       return false;
+               logger.log(logger.EXTREME, "UserStore.refreshAuthentication has succeeded.");
+               } catch (EDAMUserException e) {
+                       e.printStackTrace();
+                       syncSignal.authRefreshComplete.emit(false);
+                       failedRefreshes++;
+                       return false;
+               } catch (EDAMSystemException e) {
+                       e.printStackTrace();
+                       syncSignal.authRefreshComplete.emit(false);
+                       failedRefreshes++;
+                       return false;           
+               } catch (TException e) { 
+                       e.printStackTrace();
+                       syncSignal.authRefreshComplete.emit(false);
+                       failedRefreshes++;
+                       return false;
+               }
+               
+               // If we didn't get a good auth, then we've failed
+               if (newAuth == null) {
+                       failedRefreshes++;
+                       status.message.emit(tr("Unable to synchronize - Authentication failed"));
+                       logger.log(logger.EXTREME, "Authentication failure #" +failedRefreshes);
+                       status.message.emit(tr("Unable to synchronize - Authentication failed"));
+                       syncSignal.authRefreshComplete.emit(false);
+                       return false;
+               }
+               
+               // We got a good token.  Now we need to setup the time to renew it.
+               logger.log(logger.EXTREME, "Saving authentication tokens");
+               authResult = newAuth;
+               authToken = new String(newAuth.getAuthenticationToken());
+//             authTimeRemaining = authResult.getExpiration() - authResult.getCurrentTime();
+//             authRefreshTime = cal.getTimeInMillis() + (authTimeRemaining/4);        
+               failedRefreshes=0;
+               syncSignal.authRefreshComplete.emit(true);
+               authRefreshNeeded = false;
+                       
+               // This should never happen, but if it does we consider this a faild attempt.
+//             if (authTimeRemaining <= 0) {
+//                     failedRefreshes++;
+//                     syncSignal.authRefreshComplete.emit(false);
+//             }
+               
+               return true;
+    }
+    
+    */
+    
+       public synchronized boolean addWork(String request) {
+               if (workQueue.offer(request))
+                       return true;
+               return false;
+       }
+    
+    private Note getNoteContent(Note n) {
+               QTextCodec codec = QTextCodec.codecForLocale();
+               codec = QTextCodec.codecForName("UTF-8");
+       n.setContent(codec.toUnicode(new QByteArray(n.getContent())));
+       return n;
+    }
+
+
+
+    //*********************************************************
+    //* Special download instructions.  Used for DB upgrades
+    //*********************************************************
+    private void downloadAllSharedNotebooks(Client noteStore) {
+       try {
+                       List<SharedNotebook> books = noteStore.listSharedNotebooks(authToken);
+                       logger.log(logger.LOW, "Shared notebooks found = " +books.size());
+                       for (int i=0; i<books.size(); i++) {
+                               conn.getSharedNotebookTable().updateNotebook(books.get(i), false);
+                       }
+                       conn.getSyncTable().deleteRecord("FullSharedNotebookSync");
+               } catch (EDAMUserException e1) {
+                       e1.printStackTrace();
+                       status.message.emit(tr("User exception Listing shared notebooks."));
+                       logger.log(logger.LOW, e1.getMessage());
+                       return;
+               } catch (EDAMSystemException e1) {
+                       if (e1.getErrorCode() == EDAMErrorCode.RATE_LIMIT_REACHED) {
+                               limitSignal.rateLimitReached.emit(e1.getRateLimitDuration());
+                       }
+                       e1.printStackTrace();
+                       status.message.emit(tr("System exception Listing shared notebooks."));
+                       logger.log(logger.LOW, e1.getMessage());
+                       return;
+               } catch (TException e1) {
+                       e1.printStackTrace();
+                       status.message.emit(tr("Transaction exception Listing shared notebooks."));
+                       logger.log(logger.LOW, e1.getMessage());
+                       return;
+               } catch (EDAMNotFoundException e1) {
+                       e1.printStackTrace();
+                       status.message.emit(tr("EDAM Not Found exception Listing shared notebooks."));
+                       logger.log(logger.LOW, e1.getMessage());
+               }
+    }
+    private void downloadAllNotebooks(Client noteStore) {
+       try {
+                       List<Notebook> books = noteStore.listNotebooks(authToken);
+                       logger.log(logger.LOW, "Shared notebooks found = " +books.size());
+                       for (int i=0; i<books.size(); i++) {
+                               conn.getNotebookTable().updateNotebook(books.get(i), false);
+                       }
+                       conn.getSyncTable().deleteRecord("FullNotebookSync");
+               } catch (EDAMUserException e1) {
+                       e1.printStackTrace();
+                       status.message.emit(tr("User exception Listing notebooks."));
+                       logger.log(logger.LOW, e1.getMessage());
+                       return;
+               } catch (EDAMSystemException e1) {
+                       if (e1.getErrorCode() == EDAMErrorCode.RATE_LIMIT_REACHED) {
+                               limitSignal.rateLimitReached.emit(e1.getRateLimitDuration());
+                       }
+                       e1.printStackTrace();
+                       status.message.emit(tr("System exception Listing notebooks."));
+                       logger.log(logger.LOW, e1.getMessage());
+                       return;
+               } catch (TException e1) {
+                       e1.printStackTrace();
+                       status.message.emit(tr("Transaction exception Listing notebooks."));
+                       logger.log(logger.LOW, e1.getMessage());
+                       return;
+               }
+    }
+    private void downloadAllLinkedNotebooks(Client noteStore) {
+       try {
+                       List<LinkedNotebook> books = noteStore.listLinkedNotebooks(authToken);
+                       logger.log(logger.LOW, "Linked notebooks found = " +books.size());
+                       for (int i=0; i<books.size(); i++) {
+                               conn.getLinkedNotebookTable().updateNotebook(books.get(i), false);
+                       }
+                       conn.getSyncTable().deleteRecord("FullLinkedNotebookSync");
+               } catch (EDAMUserException e1) {
+                       e1.printStackTrace();
+                       status.message.emit(tr("User exception Listing linked notebooks."));
+                       logger.log(logger.LOW, e1.getMessage());
+                       return;
+               } catch (EDAMSystemException e1) {
+                       if (e1.getErrorCode() == EDAMErrorCode.RATE_LIMIT_REACHED) {
+                               limitSignal.rateLimitReached.emit(e1.getRateLimitDuration());
+                       }
+                       e1.printStackTrace();
+                       status.message.emit(tr("System exception Listing linked notebooks."));
+                       logger.log(logger.LOW, e1.getMessage());
+                       return;
+               } catch (TException e1) {
+                       e1.printStackTrace();
+                       status.message.emit(tr("Transaction exception Listing lineked notebooks."));
+                       logger.log(logger.LOW, e1.getMessage());
+                       return;
+               } catch (EDAMNotFoundException e1) {
+                       e1.printStackTrace();
+                       status.message.emit(tr("EDAM Not Found exception Listing linked notebooks."));
+                       logger.log(logger.LOW, e1.getMessage());
+               }
+    }
+
+    
+    private void downloadInkNoteImage(String guid, String authToken) {
+               String urlBase = noteStoreUrl.replace("/edam/note/", "/shard/") + "/res/"+guid+".ink?slice=";
+//             urlBase = "https://www.evernote.com/shard/s1/res/52b567a9-54ae-4a08-afc5-d5bae275b2a8.ink?slice=";
+               Integer slice = 1;
+               Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(guid, false);
+               conn.getInkImagesTable().expungeImage(r.getGuid());
+               int sliceCount = 1+((r.getHeight()-1)/480);
+               HttpClient http = new DefaultHttpClient();
+       for (int i=0; i<sliceCount; i++) {
+               String url = urlBase + slice.toString();
+               HttpPost post = new HttpPost(url);
+               post.getParams().setParameter("auth", authToken);
+               List <NameValuePair> nvps = new ArrayList <NameValuePair>();
+            nvps.add(new BasicNameValuePair("auth", authToken));
+
+            try {
+                               post.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
+                       } catch (UnsupportedEncodingException e1) {
+                               e1.printStackTrace();
+                       }
+               try {
+                       HttpResponse response = http.execute(post);
+                       HttpEntity resEntity = response.getEntity();
+                       InputStream is = resEntity.getContent();
+                       QByteArray data = writeToFile(is);
+                       conn.getInkImagesTable().saveImage(guid, slice, data);
+                       } catch (ClientProtocolException e) {
+                               e.printStackTrace();
+                       } catch (IOException e) {
+                               e.printStackTrace();
+                       }
+
+                       slice++;
+       }
+       http.getConnectionManager().shutdown(); 
+               noteSignal.noteChanged.emit(r.getNoteGuid(), null);   // Signal to ivalidate note cache
+    }
+    
+    
+    public QByteArray writeToFile(InputStream iStream) throws IOException {
+
+           File temp = File.createTempFile("nn-inknote-temp", ".png");
+
+           // Save InputStream to the file.
+           BufferedOutputStream fOut = null;
+           try {
+             fOut = new BufferedOutputStream(new FileOutputStream(temp));
+             byte[] buffer = new byte[32 * 1024];
+             int bytesRead = 0;
+             while ((bytesRead = iStream.read(buffer)) != -1) {
+               fOut.write(buffer, 0, bytesRead);
+             }
+           }
+           finally {
+               iStream.close();
+               fOut.close();
+           }
+           QFile tempFile = new QFile(temp.getAbsoluteFile().toString());
+           tempFile.open(OpenModeFlag.ReadOnly);
+           QByteArray data = tempFile.readAll();
+           tempFile.close();
+           tempFile.remove();
+           return data;
+    }
+    
+    
+       //******************************************
+       //* Begin syncing shared notebooks 
+       //******************************************
+    private void syncLinkedNotebooks() {
+       logger.log(logger.MEDIUM, "Authenticating linked Notebooks");
+       status.message.emit(tr("Synchronizing shared notebooks."));
+       List<LinkedNotebook> books = conn.getLinkedNotebookTable().getAll();
+       
+       errorSharedNotebooks.clear();
+               
+       for (int i=0; i<books.size(); i++) {
+               if (errorSharedNotebooksIgnored.containsKey(books.get(i).getGuid()))
+                       break;
+               try {
+                       logger.log(logger.EXTREME, "Checking notebook: " +books.get(i).getShareName());
+                               long lastSyncDate = conn.getLinkedNotebookTable().getLastSequenceDate(books.get(i).getGuid());
+                               int lastSequenceNumber = conn.getLinkedNotebookTable().getLastSequenceNumber(books.get(i).getGuid());
+
+                               logger.log(logger.EXTREME, "Last Sequence Number on file: " +lastSequenceNumber);
+                               
+                               // Authenticate to the owner's shard
+                               String linkedNoteStoreUrl       = noteStoreUrlBase + books.get(i).getShardId();
+                               logger.log(logger.EXTREME, "linkedNoteStoreURL: " +linkedNoteStoreUrl);
+                               THttpClient linkedNoteStoreTrans        = new THttpClient(linkedNoteStoreUrl);
+                               TBinaryProtocol linkedNoteStoreProt     = new TBinaryProtocol(linkedNoteStoreTrans);
+                               Client linkedNoteStore = new NoteStore.Client(linkedNoteStoreProt, linkedNoteStoreProt);        
+
+                               linkedAuthResult = null;
+                               if (books.get(i).getShareKey() != null) {
+                                       logger.log(logger.EXTREME, "Share Key Not Null: " +books.get(i).getShareKey());
+                                       linkedAuthResult = linkedNoteStore.authenticateToSharedNotebook(books.get(i).getShareKey(), authToken);
+                                       logger.log(logger.EXTREME, "Authentication Token" +linkedAuthResult.getAuthenticationToken());
+                               } else {
+                                       logger.log(logger.EXTREME, "Share key is null");
+                                       linkedAuthResult = new AuthenticationResult();
+                                       linkedAuthResult.setAuthenticationToken("");
+                               }
+                               SyncState linkedSyncState = 
+                                       linkedNoteStore.getLinkedNotebookSyncState(linkedAuthResult.getAuthenticationToken(), books.get(i));
+                               if (linkedSyncState.getUpdateCount() > lastSequenceNumber) {
+                                       logger.log(logger.EXTREME, "Remote changes found");
+                                       if (lastSyncDate < linkedSyncState.getFullSyncBefore()) {
+                                               lastSequenceNumber = 0;
+                                       } 
+                                       logger.log(logger.EXTREME, "Calling syncLinkedNotebook for " +books.get(i).getShareName());
+                                       syncLinkedNotebook(linkedNoteStore, books.get(i), 
+                                                       lastSequenceNumber, linkedSyncState.getUpdateCount(), authToken);
+                               }
+                       
+                       // Synchronize local changes
+                       syncLocalLinkedNoteChanges(linkedNoteStore, books.get(i));
+                               
+               } catch (EDAMUserException e) {
+                       e.printStackTrace();
+               } catch (EDAMNotFoundException e) {
+                       status.message.emit(tr("Error synchronizing \" " +
+                                       books.get(i).getShareName()+"\". Please verify you still have access to that shared notebook."));
+                       errorSharedNotebooks.add(books.get(i).getGuid());
+                       errorSharedNotebooksIgnored.put(books.get(i).getGuid(), books.get(i).getGuid());
+                       logger.log(logger.LOW, "Error synchronizing shared notebook.  EDAMNotFound: "+e.getMessage());
+                       logger.log(logger.LOW, e.getStackTrace());
+                       error = true;
+                       e.printStackTrace();
+               } catch (EDAMSystemException e) {
+                       if (e.getErrorCode() == EDAMErrorCode.RATE_LIMIT_REACHED) {
+                               limitSignal.rateLimitReached.emit(e.getRateLimitDuration());
+                       }
+                       error = true;
+                       logger.log(logger.LOW, "System error authenticating against shared notebook. "+
+                                       "Key: "+books.get(i).getShareKey() +" Error:" +e.getMessage());
+                       e.printStackTrace();
+               } catch (TException e) {
+                       error = true;
+                       e.printStackTrace();
+               }
+       }
+       
+       // Cleanup tags
+       conn.getTagTable().removeUnusedLinkedTags();
+       conn.getTagTable().cleanupTags();
+       tagSignal.listChanged.emit();
+       return;
+       }
+
+    
+    //**************************************************************
+    //* Linked notebook contents (from someone else's account)
+    //*************************************************************
+       private void syncLinkedNotebook(Client linkedNoteStore, LinkedNotebook book, int usn, int highSequence, String token) {
+               logger.log(logger.EXTREME, "Entering syncLinkedNotebook");
+               if (ignoreLinkedNotebooks.contains(book.getGuid()))
+                       return;
+               List<Note> dirtyNotes = conn.getNoteTable().getDirtyLinkedNotes();
+               if (dirtyNoteGuids == null) 
+                       dirtyNoteGuids = new ArrayList<String>();
+
+               for (int i=0; i<dirtyNotes.size() && keepRunning; i++) {
+                       dirtyNoteGuids.add(dirtyNotes.get(i).getGuid());
+               }
+               boolean fullSync = false;
+               if (usn == 0)
+                       fullSync = true;
+               boolean syncError = false;
+               while (usn < highSequence && !syncError) {
+                       refreshNeeded = true;
+                       try {
+                               SyncChunk chunk = 
+                                       linkedNoteStore.getLinkedNotebookSyncChunk(token, book, usn, 10, fullSync);
+                               
+                               // Expunge notes
+                               syncExpungedNotes(chunk);
+
+                               logger.log(logger.EXTREME, "Syncing remote notes: " +chunk.getNotesSize());
+                               syncRemoteNotes(linkedNoteStore, chunk.getNotes(), fullSync, linkedAuthResult.getAuthenticationToken());
+                               logger.log(logger.EXTREME, "Finding new linked tags");
+                               findNewLinkedTags(linkedNoteStore, chunk.getNotes(), linkedAuthResult.getAuthenticationToken());
+                               // Sync resources
+                               logger.log(logger.EXTREME, "Synchronizing tags: " +chunk.getTagsSize());
+                               for (int i=0; i<chunk.getResourcesSize(); i++) {
+                                       syncRemoteResource(linkedNoteStore, chunk.getResources().get(i), linkedAuthResult.getAuthenticationToken());
+                               }
+                               logger.log(logger.EXTREME, "Synchronizing linked notebooks: " +chunk.getNotebooksSize());
+                               syncRemoteLinkedNotebooks(linkedNoteStore, chunk.getNotebooks(), false, book);
+                               syncLinkedTags(chunk.getTags(), book.getGuid());
+                               
+                               // Go through & signal any notes that have changed so we can refresh the user's view
+                               for (int i=0; i<chunk.getNotesSize(); i++) 
+                                       noteSignal.noteChanged.emit(chunk.getNotes().get(i).getGuid(), null);
+
+                               // Expunge Notebook records
+                               logger.log(logger.EXTREME, "Expunging linked notebooks: " +chunk.getExpungedLinkedNotebooksSize());
+                               for (int i=0; i<chunk.getExpungedLinkedNotebooksSize(); i++) {
+                                       conn.getLinkedNotebookTable().expungeNotebook(chunk.getExpungedLinkedNotebooks().get(i), false);
+                               }
+                               usn = chunk.getChunkHighUSN();
+                               conn.getLinkedNotebookTable().setLastSequenceDate(book.getGuid(),chunk.getCurrentTime());
+                               conn.getLinkedNotebookTable().setLastSequenceNumber(book.getGuid(),chunk.getChunkHighUSN());
+                       } catch (EDAMUserException e) {
+                               syncError = true;
+                               status.message.emit(tr("EDAM UserException synchronizing linked notbook.  See the log for datails."));
+                               e.printStackTrace();
+                               logger.log(logger.LOW, tr("EDAM UserException synchronizing linked notbook ")+ e.getMessage());
+                       } catch (EDAMSystemException e) {
+                               if (e.getErrorCode() == EDAMErrorCode.RATE_LIMIT_REACHED) {
+                                       limitSignal.rateLimitReached.emit(e.getRateLimitDuration());
+                               }
+                               syncError = true;
+                               status.message.emit(tr("EDAM SystemException synchronizing linked notbook.  See the log for datails."));
+                               e.printStackTrace();
+                               logger.log(logger.LOW, tr("EDAM SystemException synchronizing linked notbook.  See the log for datails") +e.getMessage());
+                       } catch (EDAMNotFoundException e) {
+                               syncError = true;
+                               status.message.emit(tr("Notebook URL not found. Removing notobook ") +book.getShareName());
+                               conn.getNotebookTable().deleteLinkedTags(book.getGuid());
+                               conn.getLinkedNotebookTable().expungeNotebook(book.getGuid(), false);
+                               logger.log(logger.LOW, tr("Notebook URL not found. Removing notobook ") +e.getMessage());
+                       } catch (TException e) {
+                               syncError = true;
+                               status.message.emit(tr("EDAM TException synchronizing linked notbook.  See the log for datails."));
+                               e.printStackTrace();
+                               logger.log(logger.LOW, tr("EDAM TException synchronizing linked notbook.  See the log for datails." )+e.getMessage());
+                       }
+               }
+               logger.log(logger.EXTREME, "leaving syncLinkedNotebook");
+       }
+       // Sync remote tags
+       private void syncLinkedTags(List<Tag> tags, String notebookGuid) {
+               logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteTags");
+               if (tags != null) {
+                       for (int i=0; i<tags.size() && keepRunning; i++) {
+                               conn.getTagTable().syncLinkedTag(tags.get(i), notebookGuid, false);
+                       }
+               }
+               logger.log(logger.EXTREME, "Leaving SyncRunner.syncRemoteTags");
+       }
+       
+       // Sync notebooks from a linked notebook
+       private void syncRemoteLinkedNotebooks(Client noteStore, List<Notebook> notebooks, boolean readOnly, LinkedNotebook linked) {
+               logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteNotebooks");
+               if (notebooks != null) {
+                       for (int i=0; i<notebooks.size() && keepRunning; i++) {
+                               try {
+                                       logger.log(logger.EXTREME, "auth token:" +linkedAuthResult.getAuthenticationToken());
+                                       if (!linkedAuthResult.getAuthenticationToken().equals("")) {
+                                               SharedNotebook s = noteStore.getSharedNotebookByAuth(linkedAuthResult.getAuthenticationToken());
+                                               logger.log(logger.EXTREME, "share key:"+s.getShareKey() +" notebookGuid" +s.getNotebookGuid());
+                                               conn.getLinkedNotebookTable().setNotebookGuid(s.getShareKey(), s.getNotebookGuid());
+                                               readOnly = !s.isNotebookModifiable();
+                                       } else {
+                                               readOnly = true;
+                                       }
+                                       notebooks.get(i).setName(linked.getShareName());
+                                       notebooks.get(i).setDefaultNotebook(false);
+                                       conn.getNotebookTable().syncLinkedNotebook(notebooks.get(i), false, readOnly); 
+                               } catch (EDAMUserException e) {
+                                       readOnly = true;
+                                       e.printStackTrace();
+                               } catch (EDAMNotFoundException e) {
+                                       readOnly = true;
+                                       e.printStackTrace();
+                               } catch (EDAMSystemException e) {
+                                       if (e.getErrorCode() == EDAMErrorCode.RATE_LIMIT_REACHED) {
+                                               limitSignal.rateLimitReached.emit(e.getRateLimitDuration());
+                                       }
+                                       readOnly = true;
+                                       e.printStackTrace();
+                               } catch (TException e) {
+                                       readOnly = true;
+                                       e.printStackTrace();
+                               }
+
+                       }
+               }                       
+               logger.log(logger.EXTREME, "Leaving SyncRunner.syncRemoteNotebooks");
+       }
+
+       private void findNewLinkedTags(Client noteStore, List<Note> newNotes, String token) {
+               if (newNotes == null)
+                       return;
+               for (int i=0; i<newNotes.size(); i++) {
+                       Note n = newNotes.get(i);
+                       for (int j=0; j<n.getTagGuidsSize(); j++) {
+                               String tag = n.getTagGuids().get(j);
+                               if (!conn.getTagTable().exists(tag)) {
+                                       Tag newTag;
+                                       try {
+                                               newTag = noteStore.getTag(token, tag);
+                                               conn.getTagTable().addTag(newTag, false);
+                                       } catch (EDAMUserException e) {
+                                               e.printStackTrace();
+                                       } catch (EDAMSystemException e) {
+                                               if (e.getErrorCode() == EDAMErrorCode.RATE_LIMIT_REACHED) {
+                                                       limitSignal.rateLimitReached.emit(e.getRateLimitDuration());
+                                               }
+                                               e.printStackTrace();
+                                       } catch (EDAMNotFoundException e) {
+                                               e.printStackTrace();
+                                       } catch (TException e) {
+                                               e.printStackTrace();
+                                       }
+                                       
+                               }
+                       }
+               }
+       }
+
+       // Synchronize changes locally done to linked notes
+       private void syncLocalLinkedNoteChanges(Client noteStore, LinkedNotebook book) {
+               logger.log(logger.EXTREME, "Entering SyncRunner.synclocalLinkedNoteChanges");
+               String notebookGuid = conn.getLinkedNotebookTable().getNotebookGuid(book.getGuid());
+               logger.log(logger.EXTREME, "Finding changes for " +book.getShareName() +":" +book.getGuid() + ":" +notebookGuid);
+               List<Note> notes = conn.getNoteTable().getDirtyLinked(notebookGuid);
+               logger.log(logger.EXTREME, "Number of changes found: " +notes.size());
+               for (int i=0; i<notes.size(); i++) {
+                       logger.log(logger.EXTREME, "Calling syncLocalNote with key " +linkedAuthResult.getAuthenticationToken());
+                       syncLocalNote(noteStore, notes.get(i), linkedAuthResult.getAuthenticationToken());
+               }
+               logger.log(logger.EXTREME, "Leaving SyncRunner.synclocalLinkedNoteChanges");
+       }
+
+}