OSDN Git Service

Cleanup public linked notebook table logic.
[neighbornote/NeighborNote.git] / src / cx / fbn / nevernote / threads / SyncRunner.java
index 8ad6119..f2e1cae 100644 (file)
@@ -29,6 +29,7 @@ import java.util.ArrayList;
 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.Vector;\r
@@ -53,6 +54,7 @@ import com.evernote.edam.error.EDAMNotFoundException;
 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
@@ -94,8 +96,11 @@ public class SyncRunner extends QObject implements Runnable {
                public volatile boolean                 keepRunning;\r
                public volatile String                  authToken;\r
                private long                                    evernoteUpdateCount;\r
+               private final String userAgent = "NeverNote/" + System.getProperty("os.name")\r
+                                                               +"/"+System.getProperty("java.vendor") + "/"\r
+                                                               + System.getProperty("java.version") +";";\r
                \r
-               public volatile NoteStore.Client                noteStore;\r
+               public volatile NoteStore.Client                localNoteStore;\r
                private UserStore.Client                                userStore;\r
                \r
                public volatile StatusSignal                    status;\r
@@ -136,15 +141,18 @@ public class SyncRunner extends QObject implements Runnable {
                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 uid, String pswd, String cpswd) {\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
@@ -156,6 +164,8 @@ public class SyncRunner extends QObject implements Runnable {
                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
@@ -167,9 +177,6 @@ public class SyncRunner extends QObject implements Runnable {
                authRefreshNeeded = false;\r
                keepRunning = true;\r
                idle = true;\r
-               noteStore = null;\r
-               userStore = null;\r
-               authToken = null;\r
                disableUploads = false;\r
                ignoreTags = new TreeSet<String>();\r
                ignoreNotebooks = new TreeSet<String>();\r
@@ -182,12 +189,14 @@ public class SyncRunner extends QObject implements Runnable {
        public void run() {\r
                try {\r
                        logger.log(logger.EXTREME, "Starting thread");\r
-                       conn = new DatabaseConnection(logger, dburl, dbuid, dbpswd, dbcpswd, 200);\r
+                       conn = new DatabaseConnection(logger, dburl, indexUrl, resourceUrl, dbuid, dbpswd, dbcpswd, 200);\r
                        while(keepRunning) {\r
                                String work = workQueue.take();\r
                                logger.log(logger.EXTREME, "Work found: " +work);\r
-                               if (work.equalsIgnoreCase("stop"))\r
+                               if (work.equalsIgnoreCase("stop")) {\r
+                                       idle=false;\r
                                        return;\r
+                               }\r
                                idle=false;\r
                                error=false;\r
                                if (authRefreshNeeded == true || !isConnected) {\r
@@ -201,13 +210,12 @@ public class SyncRunner extends QObject implements Runnable {
                                        updateSequenceNumber = conn.getSyncTable().getUpdateSequenceNumber();\r
                                        try {\r
                                                logger.log(logger.EXTREME, "Beginning sync");\r
-                                               evernoteSync();\r
+                                               evernoteSync(localNoteStore);\r
                                                logger.log(logger.EXTREME, "Sync finished");\r
                                        } catch (UnknownHostException e) {\r
                                                status.message.emit(e.getMessage());\r
                                        }\r
                                }\r
-                               dirtyNoteGuids = null;\r
                                idle=true;\r
                                logger.log(logger.EXTREME, "Signaling refresh finished.  refreshNeeded=" +refreshNeeded);\r
                                syncSignal.finished.emit(refreshNeeded);\r
@@ -242,7 +250,7 @@ public class SyncRunner extends QObject implements Runnable {
        }\r
        public void setNoteStore(NoteStore.Client c) {\r
                logger.log(logger.EXTREME, "Setting NoteStore in sync thread");\r
-               noteStore = c;\r
+               localNoteStore = c;\r
        }\r
        public void setUserStore(UserStore.Client c) {\r
                logger.log(logger.EXTREME, "Setting UserStore in sync thread");\r
@@ -261,7 +269,7 @@ public class SyncRunner extends QObject implements Runnable {
     //***************************************************************\r
        // Synchronize changes with Evernote\r
        @SuppressWarnings("unused")\r
-       private void evernoteSync() throws java.net.UnknownHostException {\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
@@ -366,13 +374,13 @@ public class SyncRunner extends QObject implements Runnable {
                        String syncNotebooks = conn.getSyncTable().getRecord("FullNotebookSync");\r
                        String syncInkNoteImages = conn.getSyncTable().getRecord("FullInkNoteImageSync");\r
                        if (syncLinked != null) {\r
-                               downloadAllLinkedNotebooks();\r
+                               downloadAllLinkedNotebooks(localNoteStore);\r
                        }\r
                        if (syncShared != null) {\r
-                               downloadAllSharedNotebooks();\r
+                               downloadAllSharedNotebooks(localNoteStore);\r
                        }\r
                        if (syncNotebooks != null) {\r
-                               downloadAllNotebooks();\r
+                               downloadAllNotebooks(localNoteStore);\r
                        }\r
                        \r
                        if (syncInkNoteImages != null) {\r
@@ -391,7 +399,7 @@ public class SyncRunner extends QObject implements Runnable {
                                logger.log(logger.EXTREME, "Refresh needed is true");\r
                                refreshNeeded = true;\r
                                logger.log(logger.EXTREME, "Downloading changes");\r
-                               syncRemoteToLocal();\r
+                               syncRemoteToLocal(localNoteStore);\r
                        }\r
                        \r
                        //*****************************************\r
@@ -403,19 +411,19 @@ public class SyncRunner extends QObject implements Runnable {
                                logger.log(logger.EXTREME, "Uploading changes");\r
                                // Synchronize remote changes\r
                                if (!error)\r
-                                       syncExpunged();\r
+                                       syncExpunged(localNoteStore);\r
                                if (!error)\r
-                                       syncLocalTags();\r
+                                       syncLocalTags(localNoteStore);\r
                                if (!error)\r
-                                       syncLocalNotebooks();\r
+                                       syncLocalNotebooks(localNoteStore);\r
                                if (!error)\r
-                                       syncLocalLinkedNotebooks();\r
+                                       syncLocalLinkedNotebooks(localNoteStore);\r
                                if (!error) \r
-                                       syncDeletedNotes();\r
+                                       syncDeletedNotes(localNoteStore);\r
                                if (!error)\r
                                        syncLocalNotes();\r
                                if (!error)\r
-                                       syncLocalSavedSearches();\r
+                                       syncLocalSavedSearches(localNoteStore);\r
                        }\r
                        \r
                        status.message.emit(tr("Cleaning up"));\r
@@ -450,13 +458,13 @@ public class SyncRunner extends QObject implements Runnable {
        }\r
        \r
        // Sync deleted items with Evernote\r
-       private void syncExpunged() {\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
+\r
                        if (authRefreshNeeded)\r
                                if (!refreshConnection())\r
                                        return;\r
@@ -476,6 +484,7 @@ public class SyncRunner extends QObject implements Runnable {
                                if (expunged.get(i).type.equalsIgnoreCase("NOTE")) {\r
                                        logger.log(logger.EXTREME, "Note expunged");\r
                                        updateSequenceNumber = noteStore.deleteNote(authToken, expunged.get(i).guid);\r
+                                       refreshNeeded = true;\r
                                        conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);\r
                                }\r
                                if (expunged.get(i).type.equalsIgnoreCase("SAVEDSEARCH")) {\r
@@ -507,7 +516,7 @@ public class SyncRunner extends QObject implements Runnable {
                logger.log(logger.HIGH, "Leaving SyncRunner.syncExpunged");\r
 \r
        }\r
-       private void syncDeletedNotes() {\r
+       private void syncDeletedNotes(Client noteStore) {\r
                if (syncDeletedContent)\r
                        return;\r
                logger.log(logger.HIGH, "Entering SyncRunner.syncDeletedNotes");\r
@@ -574,13 +583,13 @@ public class SyncRunner extends QObject implements Runnable {
                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(notes.get(i), authToken);\r
+                       syncLocalNote(localNoteStore, notes.get(i), authToken);\r
                }\r
                logger.log(logger.HIGH, "Entering SyncRunner.syncNotes");\r
 \r
        }\r
        // Sync notes with Evernote\r
-       private void syncLocalNote(Note enNote, String token) {\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
@@ -654,7 +663,7 @@ public class SyncRunner extends QObject implements Runnable {
        }\r
 \r
        // Sync Notebooks with Evernote\r
-       private void syncLocalNotebooks() {\r
+       private void syncLocalNotebooks(Client noteStore) {\r
                logger.log(logger.HIGH, "Entering SyncRunner.syncLocalNotebooks");\r
                \r
                status.message.emit(tr("Sending local notebooks."));\r
@@ -744,7 +753,7 @@ public class SyncRunner extends QObject implements Runnable {
 \r
        }\r
        // Sync Tags with Evernote\r
-       private void syncLocalTags() {\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
@@ -771,6 +780,11 @@ public class SyncRunner extends QObject implements Runnable {
                \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
                while(enTag!=null) {\r
                        if (authRefreshNeeded)\r
@@ -814,20 +828,24 @@ public class SyncRunner extends QObject implements Runnable {
                                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
+                               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");\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");\r
-                               logger.log(logger.LOW, e.toString());   \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");\r
-                               logger.log(logger.LOW, e.toString());           \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
@@ -837,7 +855,7 @@ public class SyncRunner extends QObject implements Runnable {
                }\r
                logger.log(logger.HIGH, "Leaving SyncRunner.syncLocalTags");\r
        }\r
-       private void syncLocalLinkedNotebooks() {\r
+       private void syncLocalLinkedNotebooks(Client noteStore) {\r
                logger.log(logger.HIGH, "Entering SyncRunner.syncLocalLinkedNotebooks");\r
                \r
                List<String> list = conn.getLinkedNotebookTable().getDirtyGuids();\r
@@ -874,7 +892,7 @@ public class SyncRunner extends QObject implements Runnable {
                logger.log(logger.HIGH, "Leaving SyncRunner.syncLocalLinkedNotebooks");\r
        }\r
        // Sync Saved Searches with Evernote\r
-       private void syncLocalSavedSearches() {\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
@@ -960,11 +978,12 @@ public class SyncRunner extends QObject implements Runnable {
                                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() {\r
+       private void syncRemoteToLocal(Client noteStore) {\r
                logger.log(logger.HIGH, "Entering SyncRunner.syncRemoteToLocal");\r
 \r
                List<Note> dirtyNotes = conn.getNoteTable().getDirty();\r
@@ -989,9 +1008,9 @@ public class SyncRunner extends QObject implements Runnable {
                                if (!refreshConnection())\r
                                        return;\r
                        \r
-                       chunk = null;\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
                        } catch (EDAMUserException e) {\r
@@ -1015,9 +1034,13 @@ public class SyncRunner extends QObject implements Runnable {
                        syncRemoteTags(chunk.getTags());\r
                        syncRemoteSavedSearches(chunk.getSearches());\r
                        syncRemoteNotebooks(chunk.getNotebooks());\r
-                       syncRemoteNotes(chunk.getNotes(), fullSync, authToken);\r
-                       syncRemoteResources(chunk.getResources());\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
@@ -1030,11 +1053,12 @@ public class SyncRunner extends QObject implements Runnable {
 \r
                        \r
                        // Save the chunk sequence number\r
-                       if (!error && chunk.getChunkHighUSN() > 0) {\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
@@ -1044,8 +1068,8 @@ public class SyncRunner extends QObject implements Runnable {
                                pct = pct/evernoteUpdateCount;\r
                                status.message.emit(tr("Downloading ") +new Long(pct).toString()+tr("% complete."));\r
                        }\r
+//                     conn.commitTransaction();\r
                }\r
-\r
                logger.log(logger.HIGH, "Leaving SyncRunner.syncRemoteToLocal");\r
        }\r
        // Sync expunged notes\r
@@ -1158,17 +1182,17 @@ public class SyncRunner extends QObject implements Runnable {
 //             List<SharedNotebook> books = noteStore.getSharedNotebookByAuth(authToken);\r
 //     }\r
        // Sync remote Resources\r
-       private void syncRemoteResources(List<Resource> resource) {\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(resource.get(i), authToken);\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(Resource resource, String authToken) {\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
@@ -1176,7 +1200,7 @@ public class SyncRunner extends QObject implements Runnable {
                //     is a conflict.  The note conflict should get a copy of the resource at that time.\r
                \r
                boolean saveNeeded = false;\r
-               /* #1 */                Resource r = getEvernoteResource(resource.getGuid(), true,true,true, authToken);\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
                                                        saveNeeded = true;\r
@@ -1204,11 +1228,11 @@ public class SyncRunner extends QObject implements Runnable {
 \r
        }\r
        // Sync remote notes\r
-       private void syncRemoteNotes(List<Note> note, boolean fullSync, String token) {\r
+       private void syncRemoteNotes(Client noteStore, List<Note> note, boolean fullSync, String token) {\r
                logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteNotes");\r
                if (note != null) {\r
                        for (int i=0; i<note.size() && keepRunning; i++) {\r
-                               Note n = getEvernoteNote(note.get(i).getGuid(), true, fullSync, true,true, token);\r
+                               Note n = getEvernoteNote(noteStore, note.get(i).getGuid(), true, fullSync, true,true, token);\r
                                syncRemoteNote(n, fullSync, token);\r
                        }\r
                }\r
@@ -1248,7 +1272,9 @@ public class SyncRunner extends QObject implements Runnable {
                        if ((conflictingNote || fullSync) && !ignoreNote) {\r
                                logger.log(logger.EXTREME, "Saving Note");\r
                                conn.getNoteTable().syncNote(n, false);\r
-                               noteSignal.noteChanged.emit(n.getGuid(), null);   // Signal to ivalidate note cache\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
@@ -1262,7 +1288,7 @@ public class SyncRunner extends QObject implements Runnable {
                        }\r
                }\r
        }\r
-       private Note getEvernoteNote(String guid, boolean withContent, boolean withResourceData, boolean withResourceRecognition, boolean withResourceAlternateData, String token) { \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
@@ -1291,7 +1317,7 @@ public class SyncRunner extends QObject implements Runnable {
                }\r
                return n;\r
        }\r
-       private Resource getEvernoteResource(String guid, boolean withData, boolean withRecognition, boolean withAttributes, String token) { \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
@@ -1437,14 +1463,16 @@ public class SyncRunner extends QObject implements Runnable {
                // 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 (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
+                       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
@@ -1457,6 +1485,7 @@ public class SyncRunner extends QObject implements Runnable {
     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
@@ -1502,11 +1531,12 @@ public class SyncRunner extends QObject implements Runnable {
                authToken = authResult.getAuthenticationToken(); \r
                noteStoreUrl = noteStoreUrlBase + user.getShardId();\r
                syncSignal.saveAuthToken.emit(authToken);\r
-               syncSignal.saveNoteStore.emit(noteStore);\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
@@ -1514,7 +1544,7 @@ public class SyncRunner extends QObject implements Runnable {
                        isConnected = false;\r
                } \r
                noteStoreProt = new TBinaryProtocol(noteStoreTrans);\r
-               noteStore = \r
+               localNoteStore = \r
                        new NoteStore.Client(noteStoreProt, noteStoreProt); \r
                isConnected = true;\r
                authTimeRemaining = authResult.getExpiration() - authResult.getCurrentTime();\r
@@ -1634,7 +1664,7 @@ public class SyncRunner extends QObject implements Runnable {
     //*********************************************************\r
     //* Special download instructions.  Used for DB upgrades\r
     //*********************************************************\r
-    private void downloadAllSharedNotebooks() {\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
@@ -1663,7 +1693,7 @@ public class SyncRunner extends QObject implements Runnable {
                        logger.log(logger.LOW, e1.getMessage());\r
                }\r
     }\r
-    private void downloadAllNotebooks() {\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
@@ -1688,7 +1718,7 @@ public class SyncRunner extends QObject implements Runnable {
                        return;\r
                }\r
     }\r
-    private void downloadAllLinkedNotebooks() {\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
@@ -1737,7 +1767,6 @@ public class SyncRunner extends QObject implements Runnable {
             try {\r
                                post.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));\r
                        } catch (UnsupportedEncodingException e1) {\r
-                               // TODO Auto-generated catch block\r
                                e1.printStackTrace();\r
                        }\r
                try {\r
@@ -1798,21 +1827,34 @@ public class SyncRunner extends QObject implements Runnable {
                try {\r
                                long lastSyncDate = conn.getLinkedNotebookTable().getLastSequenceDate(books.get(i).getGuid());\r
                                int lastSequenceNumber = conn.getLinkedNotebookTable().getLastSequenceNumber(books.get(i).getGuid());\r
-                               linkedAuthResult = noteStore.authenticateToSharedNotebook(books.get(i).getShareKey(), authToken);\r
+\r
+                               // Authenticate to the owner's shard\r
+                               String linkedNoteStoreUrl       = noteStoreUrlBase + books.get(i).getShardId();\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
+                                       linkedAuthResult = linkedNoteStore.authenticateToSharedNotebook(books.get(i).getShareKey(), authToken);\r
+                               else {\r
+                                       linkedAuthResult = new AuthenticationResult();\r
+                                       linkedAuthResult.setAuthenticationToken("");\r
+                               }\r
                                SyncState linkedSyncState = \r
-                                       noteStore.getLinkedNotebookSyncState(linkedAuthResult.getAuthenticationToken(), books.get(i));\r
+                                       linkedNoteStore.getLinkedNotebookSyncState(linkedAuthResult.getAuthenticationToken(), books.get(i));\r
                                if (linkedSyncState.getUpdateCount() > lastSequenceNumber) {\r
                                        if (lastSyncDate < linkedSyncState.getFullSyncBefore()) {\r
                                                lastSequenceNumber = 0;\r
                                        } \r
-                                       syncLinkedNotebook(books.get(i), lastSequenceNumber, linkedSyncState.getUpdateCount());\r
+                                       syncLinkedNotebook(linkedNoteStore, books.get(i), \r
+                                                       lastSequenceNumber, linkedSyncState.getUpdateCount(), linkedAuthResult.getAuthenticationToken());\r
                                }\r
                        \r
                        // Synchronize local changes\r
-                       syncLocalLinkedNoteChanges(books.get(i));\r
+                       syncLocalLinkedNoteChanges(linkedNoteStore, books.get(i));\r
                                \r
                } catch (EDAMUserException e) {\r
-                       // TODO Auto-generated catch block\r
                        e.printStackTrace();\r
                } catch (EDAMNotFoundException e) {\r
                        status.message.emit(tr("Error synchronizing \" " +\r
@@ -1820,10 +1862,10 @@ public class SyncRunner extends QObject implements Runnable {
                        error = true;\r
                        e.printStackTrace();\r
                } catch (EDAMSystemException e) {\r
-                       // TODO Auto-generated catch block\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
-                       // TODO Auto-generated catch block\r
                        e.printStackTrace();\r
                }\r
        }\r
@@ -1838,8 +1880,9 @@ public class SyncRunner extends QObject implements Runnable {
     //**************************************************************\r
     //* Linked notebook contents (from someone else's account)\r
     //*************************************************************\r
-       private void syncLinkedNotebook(LinkedNotebook book, int usn, int highSequence) {\r
-               \r
+       private void syncLinkedNotebook(Client linkedNoteStore, LinkedNotebook book, int usn, int highSequence, String token) {\r
+               if (ignoreLinkedNotebooks.contains(book.getGuid()))\r
+                       return;\r
                List<Note> dirtyNotes = conn.getNoteTable().getDirtyLinkedNotes();\r
                if (dirtyNoteGuids == null) \r
                        dirtyNoteGuids = new Vector<String>();\r
@@ -1850,41 +1893,59 @@ public class SyncRunner extends QObject implements Runnable {
                boolean fullSync = false;\r
                if (usn == 0)\r
                        fullSync = true;\r
-               while (usn < highSequence) {\r
+               boolean syncError = false;\r
+               while (usn < highSequence && !syncError) {\r
+                       refreshNeeded = true;\r
                        try {\r
                                SyncChunk chunk = \r
-                                       noteStore.getLinkedNotebookSyncChunk(authToken, book, usn, 10, fullSync);\r
+                                       linkedNoteStore.getLinkedNotebookSyncChunk(token, book, usn, 10, fullSync);\r
+                               \r
+                               // Expunge notes\r
+                               syncExpungedNotes(chunk);\r
 \r
-                               if (!ignoreLinkedNotebooks.contains(book.getGuid()))\r
-                                       syncRemoteNotes(chunk.getNotes(), fullSync, linkedAuthResult.getAuthenticationToken());\r
-                               findNewLinkedTags(chunk.getNotes(), linkedAuthResult.getAuthenticationToken());\r
+                               syncRemoteNotes(linkedNoteStore, chunk.getNotes(), fullSync, linkedAuthResult.getAuthenticationToken());\r
+                               findNewLinkedTags(linkedNoteStore, chunk.getNotes(), linkedAuthResult.getAuthenticationToken());\r
+                               // Sync resources\r
                                for (int i=0; i<chunk.getResourcesSize(); i++) {\r
-                                       syncRemoteResource(chunk.getResources().get(i), linkedAuthResult.getAuthenticationToken());\r
+                                       syncRemoteResource(linkedNoteStore, chunk.getResources().get(i), linkedAuthResult.getAuthenticationToken());\r
                                }\r
-                               syncRemoteLinkedNotebooks(chunk.getNotebooks(), false, book);\r
-                               SharedNotebook s = noteStore.getSharedNotebookByAuth(linkedAuthResult.getAuthenticationToken());\r
-                               syncLinkedTags(chunk.getTags(), s.getNotebookGuid());\r
-                               \r
+                               syncRemoteLinkedNotebooks(linkedNoteStore, chunk.getNotebooks(), false, book);\r
+//                             SharedNotebook s = linkedNoteStore.getSharedNotebookByAuth(linkedAuthResult.getAuthenticationToken());\r
+//                             syncLinkedTags(chunk.getTags(), s.getNotebookGuid());\r
+                               syncLinkedTags(chunk.getTags(), book.getGuid());\r
                                \r
-                               // Expunge records\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
                                for (int i=0; i<chunk.getExpungedLinkedNotebooksSize(); i++) {\r
                                        conn.getLinkedNotebookTable().expungeNotebook(chunk.getExpungedLinkedNotebooks().get(i), false);\r
                                }\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
-                               // TODO Auto-generated catch block\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, e.getMessage());\r
                        } catch (EDAMSystemException e) {\r
-                               // TODO Auto-generated catch block\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, e.getMessage());\r
                        } catch (EDAMNotFoundException e) {\r
-                               // TODO Auto-generated catch block\r
-                               e.printStackTrace();\r
+                               syncError = true;\r
+                               status.message.emit(tr("EDAM NotFoundException synchronizing linked notbook.  See the log for datails."));\r
+                               e.printStackTrace();   /// DELETE OLD NOTEBOOKS HERE\r
+                               logger.log(logger.LOW, e.getMessage());\r
                        } catch (TException e) {\r
-                               // TODO Auto-generated catch block\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, e.getMessage());\r
                        }\r
                }\r
        }\r
@@ -1900,14 +1961,18 @@ public class SyncRunner extends QObject implements Runnable {
        }\r
        \r
        // Sync notebooks from a linked notebook\r
-       private void syncRemoteLinkedNotebooks(List<Notebook> notebooks, boolean readOnly, LinkedNotebook linked) {\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
-                                       SharedNotebook s = noteStore.getSharedNotebookByAuth(linkedAuthResult.getAuthenticationToken());\r
-                                       conn.getLinkedNotebookTable().setNotebookGuid(s.getShareKey(), s.getNotebookGuid());\r
-                                       readOnly = !s.isNotebookModifiable();\r
+                                       if (!linkedAuthResult.getAuthenticationToken().equals("")) {\r
+                                               SharedNotebook s = noteStore.getSharedNotebookByAuth(linkedAuthResult.getAuthenticationToken());\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
@@ -1930,7 +1995,7 @@ public class SyncRunner extends QObject implements Runnable {
                logger.log(logger.EXTREME, "Leaving SyncRunner.syncRemoteNotebooks");\r
        }\r
 \r
-       private void findNewLinkedTags(List<Note> newNotes, String token) {\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
@@ -1943,16 +2008,12 @@ public class SyncRunner extends QObject implements Runnable {
                                                newTag = noteStore.getTag(token, tag);\r
                                                conn.getTagTable().addTag(newTag, false);\r
                                        } catch (EDAMUserException e) {\r
-                                               // TODO Auto-generated catch block\r
                                                e.printStackTrace();\r
                                        } catch (EDAMSystemException e) {\r
-                                               // TODO Auto-generated catch block\r
                                                e.printStackTrace();\r
                                        } catch (EDAMNotFoundException e) {\r
-                                               // TODO Auto-generated catch block\r
                                                e.printStackTrace();\r
                                        } catch (TException e) {\r
-                                               // TODO Auto-generated catch block\r
                                                e.printStackTrace();\r
                                        }\r
                                        \r
@@ -1962,11 +2023,11 @@ public class SyncRunner extends QObject implements Runnable {
        }\r
 \r
        // Synchronize changes locally done to linked notes\r
-       private void syncLocalLinkedNoteChanges(LinkedNotebook book) {\r
+       private void syncLocalLinkedNoteChanges(Client noteStore, LinkedNotebook book) {\r
                String notebookGuid = conn.getLinkedNotebookTable().getNotebookGuid(book.getGuid());\r
                List<Note> notes = conn.getNoteTable().getDirtyLinked(notebookGuid);\r
                for (int i=0; i<notes.size(); i++) {\r
-                       syncLocalNote(notes.get(i), linkedAuthResult.getAuthenticationToken());\r
+                       syncLocalNote(noteStore, notes.get(i), linkedAuthResult.getAuthenticationToken());\r
                }\r
        }\r
 \r