OSDN Git Service

Add shared notebook editing & syncing logic.
[neighbornote/NeighborNote.git] / src / cx / fbn / nevernote / threads / SyncRunner.java
1 /*\r
2  * This file is part of NeverNote \r
3  * Copyright 2009 Randy Baumgarte\r
4  * \r
5  * This file may be licensed under the terms of of the\r
6  * GNU General Public License Version 2 (the ``GPL'').\r
7  *\r
8  * Software distributed under the License is distributed\r
9  * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either\r
10  * express or implied. See the GPL for the specific language\r
11  * governing rights and limitations.\r
12  *\r
13  * You should have received a copy of the GPL along with this\r
14  * program. If not, go to http://www.gnu.org/licenses/gpl.html\r
15  * or write to the Free Software Foundation, Inc.,\r
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
17  *\r
18 */\r
19 package cx.fbn.nevernote.threads;\r
20 \r
21 import java.io.BufferedOutputStream;\r
22 import java.io.File;\r
23 import java.io.FileOutputStream;\r
24 import java.io.IOException;\r
25 import java.io.InputStream;\r
26 import java.io.UnsupportedEncodingException;\r
27 import java.net.UnknownHostException;\r
28 import java.util.ArrayList;\r
29 import java.util.Calendar;\r
30 import java.util.Date;\r
31 import java.util.GregorianCalendar;\r
32 import java.util.List;\r
33 import java.util.Vector;\r
34 import java.util.concurrent.LinkedBlockingQueue;\r
35 \r
36 import org.apache.http.HttpEntity;\r
37 import org.apache.http.HttpResponse;\r
38 import org.apache.http.NameValuePair;\r
39 import org.apache.http.client.ClientProtocolException;\r
40 import org.apache.http.client.HttpClient;\r
41 import org.apache.http.client.entity.UrlEncodedFormEntity;\r
42 import org.apache.http.client.methods.HttpPost;\r
43 import org.apache.http.impl.client.DefaultHttpClient;\r
44 import org.apache.http.message.BasicNameValuePair;\r
45 import org.apache.http.protocol.HTTP;\r
46 import org.apache.thrift.TException;\r
47 import org.apache.thrift.protocol.TBinaryProtocol;\r
48 import org.apache.thrift.transport.THttpClient;\r
49 import org.apache.thrift.transport.TTransportException;\r
50 \r
51 import com.evernote.edam.error.EDAMNotFoundException;\r
52 import com.evernote.edam.error.EDAMSystemException;\r
53 import com.evernote.edam.error.EDAMUserException;\r
54 import com.evernote.edam.notestore.NoteStore;\r
55 import com.evernote.edam.notestore.SyncChunk;\r
56 import com.evernote.edam.notestore.SyncState;\r
57 import com.evernote.edam.type.Data;\r
58 import com.evernote.edam.type.LinkedNotebook;\r
59 import com.evernote.edam.type.Note;\r
60 import com.evernote.edam.type.Notebook;\r
61 import com.evernote.edam.type.Resource;\r
62 import com.evernote.edam.type.SavedSearch;\r
63 import com.evernote.edam.type.SharedNotebook;\r
64 import com.evernote.edam.type.Tag;\r
65 import com.evernote.edam.type.User;\r
66 import com.evernote.edam.userstore.AuthenticationResult;\r
67 import com.evernote.edam.userstore.UserStore;\r
68 import com.trolltech.qt.core.QByteArray;\r
69 import com.trolltech.qt.core.QFile;\r
70 import com.trolltech.qt.core.QIODevice.OpenModeFlag;\r
71 import com.trolltech.qt.core.QObject;\r
72 import com.trolltech.qt.gui.QMessageBox;\r
73 \r
74 import cx.fbn.nevernote.signals.NoteIndexSignal;\r
75 import cx.fbn.nevernote.signals.NoteResourceSignal;\r
76 import cx.fbn.nevernote.signals.NoteSignal;\r
77 import cx.fbn.nevernote.signals.NotebookSignal;\r
78 import cx.fbn.nevernote.signals.SavedSearchSignal;\r
79 import cx.fbn.nevernote.signals.StatusSignal;\r
80 import cx.fbn.nevernote.signals.SyncSignal;\r
81 import cx.fbn.nevernote.signals.TagSignal;\r
82 import cx.fbn.nevernote.sql.DatabaseConnection;\r
83 import cx.fbn.nevernote.sql.DeletedItemRecord;\r
84 import cx.fbn.nevernote.utilities.ApplicationLogger;\r
85 \r
86 public class SyncRunner extends QObject implements Runnable {\r
87         \r
88         private final ApplicationLogger logger;\r
89                 private DatabaseConnection              conn;\r
90                 private boolean                                 idle;\r
91                 public boolean                                  error;\r
92                 public volatile boolean                 isConnected;\r
93                 public volatile boolean                 keepRunning;\r
94                 public volatile String                  authToken;\r
95                 private long                                    evernoteUpdateCount;\r
96                 \r
97                 public volatile NoteStore.Client                noteStore;\r
98                 private UserStore.Client                                userStore;\r
99                 \r
100                 public volatile StatusSignal                    status;\r
101                 public volatile TagSignal                               tagSignal;\r
102                 public volatile NotebookSignal                  notebookSignal;\r
103                 public volatile NoteIndexSignal                 noteIndexSignal;\r
104                 public volatile NoteSignal                              noteSignal;\r
105                 public volatile SavedSearchSignal               searchSignal;\r
106                 public volatile NoteResourceSignal              resourceSignal;\r
107                 public volatile SyncSignal                              syncSignal;\r
108                 public volatile boolean                                 authRefreshNeeded;\r
109                 public volatile boolean                                 syncNeeded;\r
110                 public volatile boolean                                 disableUploads;\r
111                 public volatile boolean                                 syncDeletedContent;\r
112                 private volatile Vector<String>                 dirtyNoteGuids;\r
113                 \r
114             public volatile String username = ""; \r
115             public volatile String password = ""; \r
116                 public volatile String userStoreUrl;\r
117             private final static String consumerKey = "baumgarte"; \r
118             private final static String consumerSecret = "eb8b5740e17cb55f";\r
119             public String noteStoreUrlBase;\r
120             private THttpClient userStoreTrans;\r
121             private TBinaryProtocol userStoreProt;\r
122             private AuthenticationResult authResult;\r
123             private AuthenticationResult linkedAuthResult;\r
124             private User user; \r
125             private long authTimeRemaining;\r
126             public long authRefreshTime;\r
127             public long failedRefreshes = 0;\r
128             public  THttpClient noteStoreTrans;\r
129             public TBinaryProtocol noteStoreProt;\r
130             public String noteStoreUrl;\r
131             public long sequenceDate;\r
132             public int updateSequenceNumber;\r
133             private boolean refreshNeeded;\r
134             private volatile LinkedBlockingQueue<String> workQueue;\r
135 //              private static int MAX_EMPTY_QUEUE_COUNT = 1;\r
136                 private static int MAX_QUEUED_WAITING = 1000;\r
137                 String dbuid;\r
138                 String dburl;\r
139                 String dbpswd;\r
140                 String dbcpswd;\r
141         \r
142                 \r
143                 \r
144         public SyncRunner(String logname, String u, String uid, String pswd, String cpswd) {\r
145                 logger = new ApplicationLogger(logname);\r
146                 \r
147                 noteSignal = new NoteSignal();\r
148                 status = new StatusSignal();\r
149                 tagSignal = new TagSignal();\r
150                 notebookSignal = new NotebookSignal();\r
151                 noteIndexSignal = new NoteIndexSignal();\r
152                 noteSignal = new NoteSignal();\r
153                 searchSignal = new SavedSearchSignal();\r
154                 syncSignal = new SyncSignal();\r
155                 resourceSignal = new NoteResourceSignal();\r
156                 dbuid = uid;\r
157                 dburl = u;\r
158                 dbpswd = pswd;\r
159                 dbcpswd = cpswd;\r
160 //              this.setAutoDelete(false);\r
161                 \r
162                 isConnected = false;\r
163                 syncNeeded = false;\r
164                 authRefreshNeeded = false;\r
165                 keepRunning = true;\r
166                 idle = true;\r
167                 noteStore = null;\r
168                 userStore = null;\r
169                 authToken = null;\r
170                 disableUploads = false;\r
171 //              setAutoDelete(false);\r
172                 workQueue=new LinkedBlockingQueue<String>(MAX_QUEUED_WAITING);\r
173         }\r
174         @Override\r
175         public void run() {\r
176                 try {\r
177                         logger.log(logger.EXTREME, "Starting thread");\r
178                         conn = new DatabaseConnection(logger, dburl, dbuid, dbpswd, dbcpswd);\r
179                         while(keepRunning) {\r
180                                 String work = workQueue.take();\r
181                                 logger.log(logger.EXTREME, "Work found: " +work);\r
182                                 if (work.equalsIgnoreCase("stop"))\r
183                                         return;\r
184                                 idle=false;\r
185                                 error=false;\r
186                                 if (authRefreshNeeded == true) {\r
187                                         logger.log(logger.EXTREME, "Refreshing connection");\r
188                                         refreshConnection();\r
189                                 }\r
190                                 if (syncNeeded) {\r
191                                         logger.log(logger.EXTREME, "SyncNeeded is true");\r
192                                         refreshNeeded=false;\r
193                                         sequenceDate = conn.getSyncTable().getLastSequenceDate();\r
194                                         updateSequenceNumber = conn.getSyncTable().getUpdateSequenceNumber();\r
195                                         try {\r
196                                                 logger.log(logger.EXTREME, "Beginning sync");\r
197                                                 evernoteSync();\r
198                                                 logger.log(logger.EXTREME, "Sync finished");\r
199                                         } catch (UnknownHostException e) {\r
200                                                 status.message.emit(e.getMessage());\r
201                                         }\r
202                                 }\r
203                                 dirtyNoteGuids = null;\r
204                                 idle=true;\r
205                                 logger.log(logger.EXTREME, "Signaling refresh finished.  refreshNeeded=" +refreshNeeded);\r
206                                 syncSignal.finished.emit(refreshNeeded);\r
207                         }\r
208                 }       \r
209                 catch (InterruptedException e1) {\r
210                         e1.printStackTrace();\r
211                 }\r
212                 conn.dbShutdown();\r
213         }\r
214 \r
215         \r
216         public DatabaseConnection getConnection() {\r
217                 return conn;\r
218         }\r
219 \r
220         public boolean isIdle() {\r
221                 return idle;\r
222         }\r
223 \r
224 \r
225         public void setConnected(boolean c) {\r
226                 isConnected = c;\r
227         }\r
228         public void setKeepRunning(boolean r) {\r
229                 logger.log(logger.EXTREME, "Setting keepRunning=" +r);\r
230                 keepRunning = r;\r
231         }\r
232         public void setNoteStore(NoteStore.Client c) {\r
233                 logger.log(logger.EXTREME, "Setting NoteStore in sync thread");\r
234                 noteStore = c;\r
235         }\r
236         public void setUserStore(UserStore.Client c) {\r
237                 logger.log(logger.EXTREME, "Setting UserStore in sync thread");\r
238                 userStore = c;\r
239         }\r
240 \r
241         public void setEvernoteUpdateCount(long s) {\r
242                 logger.log(logger.EXTREME, "Setting Update Count in sync thread");\r
243                 evernoteUpdateCount = s;\r
244         }\r
245         \r
246         //***************************************************************\r
247     //***************************************************************\r
248     //** These functions deal with Evernote communications\r
249     //***************************************************************\r
250     //***************************************************************\r
251         // Synchronize changes with Evernote\r
252         @SuppressWarnings("unused")\r
253         private void evernoteSync() throws java.net.UnknownHostException {\r
254                 logger.log(logger.HIGH, "Entering SyncRunner.evernoteSync");\r
255 \r
256                 if (isConnected && keepRunning) {\r
257                         error = false;\r
258                         logger.log(logger.EXTREME, "Synchronizing with Evernote");\r
259                         status.message.emit(tr("Synchronizing with Evernote"));\r
260                         \r
261                         // Get user information\r
262                         try {\r
263                                 logger.log(logger.EXTREME, "getting user from userstore");\r
264                                 User user = userStore.getUser(authToken);\r
265                                 logger.log(logger.EXTREME, "Saving user information");\r
266                                 syncSignal.saveUserInformation.emit(user);\r
267                         } catch (EDAMUserException e1) {\r
268                                 e1.printStackTrace();\r
269                                 status.message.emit(tr("User exception getting user account information.  Aborting sync and disconnecting"));\r
270                                 syncSignal.errorDisconnect.emit();\r
271                                 enDisconnect();\r
272                                 return;\r
273                         } catch (EDAMSystemException e1) {\r
274                                 e1.printStackTrace();\r
275                                 status.message.emit(tr("System error user account information.  Aborting sync and disconnecting!"));\r
276                                 syncSignal.errorDisconnect.emit();\r
277                                 enDisconnect();\r
278                                 return;\r
279                         } catch (TException e1) {\r
280                                 e1.printStackTrace();\r
281                                 syncSignal.errorDisconnect.emit();\r
282                                 status.message.emit(tr("Transaction error getting user account information.  Aborting sync and disconnecting!"));\r
283                                 enDisconnect();\r
284                                 return;\r
285                         }\r
286                         \r
287                         // Get sync state\r
288                         SyncState syncState = null;\r
289                         try {   \r
290                                 logger.log(logger.EXTREME, "Getting sync state");\r
291                                 syncState = noteStore.getSyncState(authToken);  \r
292                                 syncSignal.saveUploadAmount.emit(syncState.getUploaded());\r
293                                 syncSignal.saveEvernoteUpdateCount.emit(syncState.getUpdateCount());\r
294                                 evernoteUpdateCount = syncState.getUpdateCount();\r
295                         } catch (EDAMUserException e) {\r
296                                 e.printStackTrace();\r
297                                 status.message.emit(tr("Error getting sync state! Aborting sync and disconnecting!"));\r
298                                 syncSignal.errorDisconnect.emit();\r
299                                 enDisconnect();\r
300                                 return;\r
301                         } catch (EDAMSystemException e) {\r
302                                 e.printStackTrace();\r
303                                 status.message.emit(tr("Error getting sync state! Aborting sync and disconnecting!"));\r
304                                 syncSignal.errorDisconnect.emit();\r
305                                 enDisconnect();\r
306                                 return;\r
307                         } catch (TException e) {\r
308                                 e.printStackTrace();\r
309                                 status.message.emit(tr("Error getting sync state! Aborting sync and disconnecting!"));\r
310                                 syncSignal.errorDisconnect.emit();\r
311                                 enDisconnect();\r
312                                 return;\r
313                         }\r
314                         \r
315                         if (syncState == null) {\r
316                                 logger.log(logger.EXTREME, "Sync State is null");\r
317                                 status.message.emit(tr("Syncronization Error!"));\r
318                                 return;\r
319                         }\r
320 \r
321                         // Determine what to do. \r
322                         // If we need to do a full sync.\r
323                         logger.log(logger.LOW, "Full Sequence Before: " +syncState.getFullSyncBefore());\r
324                         logger.log(logger.LOW, "Last Sequence Date: " +sequenceDate);\r
325                         if (syncState.getFullSyncBefore() > sequenceDate) {\r
326                                 logger.log(logger.EXTREME, "Full sequence date has expired");\r
327                                 sequenceDate = 0;\r
328                                 conn.getSyncTable().setLastSequenceDate(0);\r
329                                 updateSequenceNumber = 0;\r
330                                 conn.getSyncTable().setUpdateSequenceNumber(0);\r
331                         }\r
332                         // Check for "special" sync instructions\r
333                         String syncLinked = conn.getSyncTable().getRecord("FullLinkedNotebookSync");\r
334                         String syncShared = conn.getSyncTable().getRecord("FullLinkedNotebookSync");\r
335                         String syncNotebooks = conn.getSyncTable().getRecord("FullNotebookSync");\r
336                         String syncInkNoteImages = conn.getSyncTable().getRecord("FullInkNoteImageSync");\r
337                         if (syncLinked != null) {\r
338                                 downloadAllLinkedNotebooks();\r
339                         }\r
340                         if (syncShared != null) {\r
341                                 downloadAllSharedNotebooks();\r
342                         }\r
343                         if (syncNotebooks != null) {\r
344                                 downloadAllNotebooks();\r
345                         }\r
346                         \r
347                         if (syncInkNoteImages != null) {\r
348                                 List<String> guids = conn.getNoteTable().noteResourceTable.findInkNotes();\r
349                                 for (int i=0; i<guids.size(); i++) {\r
350                                         downloadInkNoteImage(guids.get(i), authToken);\r
351                                 }\r
352                                 conn.getSyncTable().deleteRecord("FullInkNoteImageSync");\r
353                         }\r
354                         \r
355                         // If there are remote changes\r
356                         logger.log(logger.LOW, "Update Count: " +syncState.getUpdateCount());\r
357                         logger.log(logger.LOW, "Last Update Count: " +updateSequenceNumber);\r
358                         \r
359                         if (syncState.getUpdateCount() > updateSequenceNumber) {\r
360                                 logger.log(logger.EXTREME, "Refresh needed is true");\r
361                                 refreshNeeded = true;\r
362                                 logger.log(logger.EXTREME, "Downloading changes");\r
363                                 syncRemoteToLocal();\r
364                         }\r
365                         \r
366                         //*****************************************\r
367                         //* Sync linked/shared notebooks \r
368                         //*****************************************\r
369                         syncLinkedNotebooks();\r
370                         \r
371                         if (!disableUploads) {\r
372                                 logger.log(logger.EXTREME, "Uploading changes");\r
373                                 // Synchronize remote changes\r
374                                 if (!error)\r
375                                         syncExpunged();\r
376                                 if (!error)\r
377                                         syncLocalTags();\r
378                                 if (!error)\r
379                                         syncLocalNotebooks();\r
380                                 if (!error)\r
381                                         syncLocalLinkedNotebooks();\r
382                                 if (!error) \r
383                                         syncDeletedNotes();\r
384                                 if (!error)\r
385                                         syncLocalNotes();\r
386                                 if (!error)\r
387                                         syncLocalSavedSearches();\r
388                         }\r
389                         \r
390                         //*****************************************\r
391                         //* End of synchronization\r
392                         //*****************************************\r
393                         if (refreshNeeded)\r
394                                 syncSignal.refreshLists.emit();\r
395                         \r
396                         if (!error) {\r
397                                 logger.log(logger.EXTREME, "Sync completed.  Errors=" +error);\r
398                                 if (!disableUploads) \r
399                                         status.message.emit(tr("Synchronizing complete"));\r
400                                 else\r
401                                         status.message.emit(tr("Download syncronization complete.  Uploads have been disabled."));\r
402                                 \r
403                                 logger.log(logger.EXTREME, "Saving sync time");\r
404                                 if (syncState.getCurrentTime() > sequenceDate)\r
405                                         sequenceDate = syncState.getCurrentTime();\r
406                                 if (syncState.getUpdateCount() > updateSequenceNumber)\r
407                                         updateSequenceNumber = syncState.getUpdateCount();\r
408                                 conn.getSyncTable().setLastSequenceDate(sequenceDate);\r
409                                 conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);\r
410                         }\r
411                 }\r
412                 logger.log(logger.HIGH, "Leaving SyncRunner.evernoteSync");\r
413         }\r
414         \r
415         // Sync deleted items with Evernote\r
416         private void syncExpunged() {\r
417                 logger.log(logger.HIGH, "Entering SyncRunner.syncExpunged");\r
418                 \r
419                 List<DeletedItemRecord> expunged = conn.getDeletedTable().getAllDeleted();\r
420                 boolean error = false;\r
421                 for (int i=0; i<expunged.size() && keepRunning; i++) {\r
422                         \r
423                         if (authRefreshNeeded)\r
424                                 refreshConnection();\r
425 \r
426                         try {\r
427                                 if (expunged.get(i).type.equalsIgnoreCase("TAG")) {\r
428                                         logger.log(logger.EXTREME, "Tag expunged");\r
429                                         updateSequenceNumber = noteStore.expungeTag(authToken, expunged.get(i).guid);\r
430                                         conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);\r
431                                         \r
432                                 }\r
433                                 if      (expunged.get(i).type.equalsIgnoreCase("NOTEBOOK")) {\r
434                                         logger.log(logger.EXTREME, "Notebook expunged");\r
435                                         updateSequenceNumber = noteStore.expungeNotebook(authToken, expunged.get(i).guid);\r
436                                         conn.getSyncTable().setLastSequenceDate(sequenceDate);\r
437                                 }\r
438                                 if (expunged.get(i).type.equalsIgnoreCase("NOTE")) {\r
439                                         logger.log(logger.EXTREME, "Note expunged");\r
440                                         updateSequenceNumber = noteStore.deleteNote(authToken, expunged.get(i).guid);\r
441                                         conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);\r
442                                 }\r
443                                 if (expunged.get(i).type.equalsIgnoreCase("SAVEDSEARCH")) {\r
444                                         logger.log(logger.EXTREME, "saved search expunged");\r
445                                         updateSequenceNumber = noteStore.expungeSearch(authToken, expunged.get(i).guid);\r
446                                         conn.getSyncTable().setLastSequenceDate(sequenceDate);\r
447                                 }\r
448                         } catch (EDAMUserException e) {\r
449                                 logger.log(logger.LOW, "EDAM User Excepton in syncExpunged: " +expunged.get(i).guid);\r
450                                 logger.log(logger.LOW, e.getStackTrace());\r
451                                 error = true;\r
452                         } catch (EDAMSystemException e) {\r
453                                 logger.log(logger.LOW, "EDAM System Excepton in syncExpunged: "+expunged.get(i).guid);\r
454                                 logger.log(logger.LOW, e.getStackTrace());\r
455                                 error=true;\r
456                         } catch (EDAMNotFoundException e) {\r
457                                 logger.log(logger.LOW, "EDAM Not Found Excepton in syncExpunged: "+expunged.get(i).guid);\r
458 //                              logger.log(logger.LOW, e.getStackTrace());\r
459                                 //error=true;\r
460                         } catch (TException e) {\r
461                                 logger.log(logger.LOW, "EDAM TExcepton in syncExpunged: "+expunged.get(i).guid);\r
462                                 logger.log(logger.LOW, e.getStackTrace());\r
463                                 error=true;\r
464                         }\r
465                 }\r
466                 if (!error)\r
467                         conn.getDeletedTable().expungeAllDeletedRecords();\r
468                 \r
469                 logger.log(logger.HIGH, "Leaving SyncRunner.syncExpunged");\r
470 \r
471         }\r
472         private void syncDeletedNotes() {\r
473                 if (syncDeletedContent)\r
474                         return;\r
475                 logger.log(logger.HIGH, "Entering SyncRunner.syncDeletedNotes");\r
476                 status.message.emit(tr("Synchronizing deleted notes."));\r
477 \r
478                 List<Note> notes = conn.getNoteTable().getDirty();\r
479                 // Sync the local notebooks with Evernote's\r
480                 for (int i=0; i<notes.size() && keepRunning; i++) {\r
481                         \r
482                         if (authRefreshNeeded)\r
483                                 refreshConnection();\r
484                         \r
485                         Note enNote = notes.get(i);\r
486                         try {\r
487                                 if (enNote.getUpdateSequenceNum() > 0 && (enNote.isActive() == false || enNote.getDeleted() > 0)) {\r
488                                         if (syncDeletedContent) {\r
489                                                 logger.log(logger.EXTREME, "Deleted note found & synch content selected");\r
490                                                 Note delNote = conn.getNoteTable().getNote(enNote.getGuid(), true, true, true, true, true);\r
491                                                 delNote = getNoteContent(delNote);\r
492                                                 delNote = noteStore.updateNote(authToken, delNote);\r
493                                                 enNote.setUpdateSequenceNum(delNote.getUpdateSequenceNum());\r
494                                                 conn.getNoteTable().updateNoteSequence(enNote.getGuid(), enNote.getUpdateSequenceNum());\r
495                                         } else {\r
496                                                 logger.log(logger.EXTREME, "Deleted note found & sync content not selected");\r
497                                                 int usn = noteStore.deleteNote(authToken, enNote.getGuid());\r
498                                                 enNote.setUpdateSequenceNum(usn);\r
499                                                 conn.getNoteTable().updateNoteSequence(enNote.getGuid(), enNote.getUpdateSequenceNum());                                                \r
500                                         }\r
501                                         logger.log(logger.EXTREME, "Resetting deleted dirty flag");\r
502                                         conn.getNoteTable().resetDirtyFlag(enNote.getGuid());\r
503                                         updateSequenceNumber = enNote.getUpdateSequenceNum();\r
504                                         logger.log(logger.EXTREME, "Saving sequence number");\r
505                                         conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);\r
506                                 }                               \r
507                         } catch (EDAMUserException e) {\r
508                                 //logger.log(logger.LOW, "*** EDAM User Excepton syncLocalNotes "+e);\r
509                                 //status.message.emit("Error sending local note: " +e.getParameter());\r
510                                 //logger.log(logger.LOW, e.toString()); \r
511                                 //error = true;\r
512                         } catch (EDAMSystemException e) {\r
513                                 logger.log(logger.LOW, "*** EDAM System Excepton syncLocalNotes "+e);\r
514                                 status.message.emit(tr("Error: ") +e);\r
515                                 logger.log(logger.LOW, e.toString());           \r
516                                 error = true;\r
517                         } catch (EDAMNotFoundException e) {\r
518                                 //logger.log(logger.LOW, "*** EDAM Not Found Excepton syncLocalNotes " +e);\r
519                                 //status.message.emit("Error deleting local note: " +e +" - Continuing");\r
520                                 //logger.log(logger.LOW, e.toString());         \r
521                                 //error = true;\r
522                         } catch (TException e) {\r
523                                 logger.log(logger.LOW, "*** EDAM TExcepton syncLocalNotes "+e);\r
524                                 status.message.emit(tr("Error sending local note: ") +e);\r
525                                 logger.log(logger.LOW, e.toString());   \r
526                                 error = true;\r
527                         }               \r
528                 }\r
529         }\r
530         // Sync notes with Evernote\r
531         private void syncLocalNotes() {\r
532                 logger.log(logger.HIGH, "Entering SyncRunner.syncNotes");\r
533                 status.message.emit(tr("Sending local notes."));\r
534 \r
535                 List<Note> notes = conn.getNoteTable().getDirty();\r
536                 // Sync the local notebooks with Evernote's\r
537                 for (int i=0; i<notes.size() && keepRunning; i++) {\r
538                         syncLocalNote(notes.get(i), authToken);\r
539                 }\r
540                 logger.log(logger.HIGH, "Entering SyncRunner.syncNotes");\r
541 \r
542         }\r
543         // Sync notes with Evernote\r
544         private void syncLocalNote(Note enNote, String token) {\r
545                 logger.log(logger.HIGH, "Entering SyncRunner.syncNotes");\r
546                 status.message.emit(tr("Sending local notes."));\r
547 \r
548                 if (authRefreshNeeded)\r
549                         refreshConnection();\r
550                         \r
551                 if (enNote.isActive()) {\r
552                         try {\r
553                                 logger.log(logger.EXTREME, "Active dirty note found - non new");\r
554                                 if (enNote.getUpdateSequenceNum() > 0) {\r
555                                         enNote = getNoteContent(enNote);\r
556                                         logger.log(logger.MEDIUM, "Updating note : "+ enNote.getGuid() +" <title>" +enNote.getTitle()+"</title>");\r
557                                         enNote = noteStore.updateNote(token, enNote);\r
558                                 } else { \r
559                                         logger.log(logger.EXTREME, "Active dirty found - new note");\r
560                                         logger.log(logger.MEDIUM, "Creating note : "+ enNote.getGuid() +" <title>" +enNote.getTitle()+"</title>");\r
561                                         String oldGuid = enNote.getGuid();\r
562                                         enNote = getNoteContent(enNote);\r
563                                         enNote = noteStore.createNote(token, enNote);\r
564                                         noteSignal.guidChanged.emit(oldGuid, enNote.getGuid());\r
565                                         conn.getNoteTable().updateNoteGuid(oldGuid, enNote.getGuid());\r
566                                 }\r
567                                 updateSequenceNumber = enNote.getUpdateSequenceNum();\r
568                                 logger.log(logger.EXTREME, "Saving note");\r
569                                 conn.getNoteTable().updateNoteSequence(enNote.getGuid(), enNote.getUpdateSequenceNum());\r
570                                 List<Resource> rl = enNote.getResources();\r
571                                 logger.log(logger.EXTREME, "Getting note resources");\r
572                                 for (int j=0; j<enNote.getResourcesSize() && keepRunning; j++) {\r
573                                         Resource newRes = rl.get(j);\r
574                                         Data d = newRes.getData();\r
575                                         if (d!=null) {  \r
576                                                 logger.log(logger.EXTREME, "Calculating resource hash");\r
577                                                 String hash = byteArrayToHexString(d.getBodyHash());\r
578                                                 logger.log(logger.EXTREME, "updating resources by hash");\r
579                                                 String oldGuid = conn.getNoteTable().noteResourceTable.getNoteResourceGuidByHashHex(enNote.getGuid(), hash);\r
580                                                 conn.getNoteTable().updateNoteResourceGuidbyHash(enNote.getGuid(), newRes.getGuid(), hash);\r
581                                                 resourceSignal.resourceGuidChanged.emit(enNote.getGuid(), oldGuid, newRes.getGuid());\r
582                                         }\r
583                                 }\r
584                                 logger.log(logger.EXTREME, "Resetting note dirty flag");\r
585                                 conn.getNoteTable().resetDirtyFlag(enNote.getGuid());\r
586                                 updateSequenceNumber = enNote.getUpdateSequenceNum();\r
587                                 logger.log(logger.EXTREME, "Emitting note sequence number change");\r
588                                 conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);\r
589 \r
590                         } catch (EDAMUserException e) {\r
591                                 logger.log(logger.LOW, "*** EDAM User Excepton syncLocalNotes "+e);\r
592                                 status.message.emit(tr("Error sending local note: ")     +e.getParameter());\r
593                                 logger.log(logger.LOW, e.toString());   \r
594                                 error = true;\r
595                         } catch (EDAMSystemException e) {\r
596                                 logger.log(logger.LOW, "*** EDAM System Excepton syncLocalNotes "+e);\r
597                                 status.message.emit(tr("Error: ") +e);\r
598                                 logger.log(logger.LOW, e.toString());           \r
599                                 error = true;\r
600                         } catch (EDAMNotFoundException e) {\r
601                                 logger.log(logger.LOW, "*** EDAM Not Found Excepton syncLocalNotes " +e);\r
602                                 status.message.emit(tr("Error sending local note: ") +e);\r
603                                 logger.log(logger.LOW, e.toString());   \r
604                                 error = true;\r
605                         } catch (TException e) {\r
606                                 logger.log(logger.LOW, "*** EDAM TExcepton syncLocalNotes "+e);\r
607                                 status.message.emit(tr("Error sending local note: ") +e);\r
608                                 logger.log(logger.LOW, e.toString());   \r
609                                 error = true;\r
610                         }\r
611                 }\r
612                 logger.log(logger.HIGH, "Leaving SyncRunner.syncLocalNote");\r
613 \r
614         }\r
615 \r
616         // Sync Notebooks with Evernote\r
617         private void syncLocalNotebooks() {\r
618                 logger.log(logger.HIGH, "Entering SyncRunner.syncLocalNotebooks");\r
619                 \r
620                 status.message.emit(tr("Sending local notebooks."));\r
621                 List<Notebook> remoteList = new ArrayList<Notebook>();\r
622                 try {\r
623                         logger.log(logger.EXTREME, "Getting remote notebooks to compare with local");\r
624                         remoteList = noteStore.listNotebooks(authToken);\r
625                 } catch (EDAMUserException e1) {\r
626                         logger.log(logger.LOW, "*** EDAM User Excepton syncLocalNotebooks getting remote Notebook List");\r
627                         status.message.emit(tr("Error: ") +e1);\r
628                         logger.log(logger.LOW, e1.toString());          \r
629                         error = true;\r
630                 } catch (EDAMSystemException e1) {\r
631                         logger.log(logger.LOW, "*** EDAM System Excepton syncLocalNotebooks getting remote Notebook List");\r
632                         status.message.emit(tr("Error: ") +e1);\r
633                         logger.log(logger.LOW, e1.toString());  \r
634                         error = true;\r
635                 } catch (TException e1) {\r
636                         logger.log(logger.LOW, "*** EDAM Transaction Excepton syncLocalNotebooks getting remote Notebook List");\r
637                         status.message.emit(tr("Error: ") +e1);\r
638                         logger.log(logger.LOW, e1.toString());  \r
639                         error = true;\r
640                 }\r
641                 logger.log(logger.EXTREME, "Getting local dirty notebooks");\r
642                 List<Notebook> notebooks = conn.getNotebookTable().getDirty();\r
643                 int sequence;\r
644                 // Sync the local notebooks with Evernote's\r
645                 for (int i=0; i<notebooks.size() && keepRunning; i++) {\r
646                         \r
647                         if (authRefreshNeeded)\r
648                                 refreshConnection();\r
649                         \r
650                         Notebook enNotebook = notebooks.get(i);\r
651                         try {\r
652                                 if (enNotebook.getUpdateSequenceNum() > 0) {\r
653                                         logger.log(logger.EXTREME, "Existing notebook is dirty");\r
654                                         sequence = noteStore.updateNotebook(authToken, enNotebook);\r
655                                 } else {\r
656                                         logger.log(logger.EXTREME, "New dirty notebook found");\r
657                                         String oldGuid = enNotebook.getGuid();\r
658                                         boolean found = false;\r
659                                         \r
660                                         // Look for a notebook with the same name.  If one is found, we don't need \r
661                                         // to create another one\r
662                                         logger.log(logger.EXTREME, "Looking for matching notebook name");\r
663                                         for (int k=0; k<remoteList.size() && !found && keepRunning; k++) {\r
664                                                 if (remoteList.get(k).getName().equalsIgnoreCase(enNotebook.getName())) {\r
665                                                         enNotebook = remoteList.get(k);\r
666                                                         logger.log(logger.EXTREME, "Matching notebook found");\r
667                                                         found = true;\r
668                                                 }\r
669                                         }\r
670                                         if (!found)\r
671                                                 enNotebook = noteStore.createNotebook(authToken, enNotebook);\r
672                                         \r
673                                         logger.log(logger.EXTREME, "Updating notebook in database");\r
674                                         conn.getNotebookTable().updateNotebookGuid(oldGuid, enNotebook.getGuid());\r
675                                         sequence = enNotebook.getUpdateSequenceNum();\r
676                                 }\r
677                                 logger.log(logger.EXTREME, "Updating notebook sequence in database");\r
678                                 conn.getNotebookTable().updateNotebookSequence(enNotebook.getGuid(), sequence);\r
679                                 logger.log(logger.EXTREME, "Resetting dirty flag in notebook");\r
680                                 conn.getNotebookTable().resetDirtyFlag(enNotebook.getGuid());\r
681                                 updateSequenceNumber = sequence;\r
682                                 logger.log(logger.EXTREME, "Emitting sequence number to main thread");\r
683                                 conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);\r
684                         } catch (EDAMUserException e) {\r
685                                 logger.log(logger.LOW, "*** EDAM User Excepton syncLocalNotebooks");\r
686                                 logger.log(logger.LOW, e.toString());   \r
687                                 error = true;\r
688                         } catch (EDAMSystemException e) {\r
689                                 logger.log(logger.LOW, "*** EDAM System Excepton syncLocalNotebooks");\r
690                                 logger.log(logger.LOW, e.toString());           \r
691                                 error = true;\r
692                         } catch (EDAMNotFoundException e) {\r
693                                 logger.log(logger.LOW, "*** EDAM Not Found Excepton syncLocalNotebooks");\r
694                                 logger.log(logger.LOW, e.toString());           \r
695                                 error = true;\r
696                         } catch (TException e) {\r
697                                 logger.log(logger.LOW, "*** EDAM TExcepton syncLocalNotebooks");\r
698                                 logger.log(logger.LOW, e.toString());   \r
699                                 error = true;\r
700                         }               \r
701                 }\r
702                 logger.log(logger.HIGH, "Leaving SyncRunner.syncLocalNotebooks");\r
703 \r
704         }\r
705         // Sync Tags with Evernote\r
706         private void syncLocalTags() {\r
707                 logger.log(logger.HIGH, "Entering SyncRunner.syncLocalTags");\r
708                 List<Tag> remoteList = new ArrayList<Tag>();\r
709                 status.message.emit(tr("Sending local tags."));\r
710                 \r
711                 try {\r
712                         logger.log(logger.EXTREME, "Getting remote tags to compare names with the local tags");\r
713                         remoteList = noteStore.listTags(authToken);\r
714                 } catch (EDAMUserException e1) {\r
715                         logger.log(logger.LOW, "*** EDAM User Excepton syncLocalTags getting remote Tag List");\r
716                         status.message.emit(tr("Error: ") +e1);\r
717                         logger.log(logger.LOW, e1.toString());  \r
718                         error = true;\r
719                 } catch (EDAMSystemException e1) {\r
720                         logger.log(logger.LOW, "*** EDAM System Excepton syncLocalTags getting remote Tag List");\r
721                         status.message.emit(tr("Error: ") +e1);\r
722                         logger.log(logger.LOW, e1.toString());          \r
723                         error = true;\r
724                 } catch (TException e1) {\r
725                         logger.log(logger.LOW, "*** EDAM Transaction Excepton syncLocalTags getting remote Tag List");\r
726                         status.message.emit(tr("Error: ") +e1);\r
727                         logger.log(logger.LOW, e1.toString());  \r
728                         error = true;\r
729                 }               \r
730                 \r
731                 int sequence;\r
732                 \r
733                 Tag enTag = findNextTag();\r
734                 while(enTag!=null) {\r
735                         if (authRefreshNeeded)\r
736                                 refreshConnection();\r
737 \r
738                         try {\r
739                                 if (enTag.getUpdateSequenceNum() > 0) {\r
740                                         logger.log(logger.EXTREME, "Updating tag");\r
741                                         sequence = noteStore.updateTag(authToken, enTag);\r
742                                 } else {\r
743                                         \r
744                                         // Look for a tag with the same name.  If one is found, we don't need \r
745                                         // to create another one\r
746                                         logger.log(logger.EXTREME, "New tag.  Comparing with remote names");\r
747                                         boolean found = false;\r
748                                         String oldGuid = enTag.getGuid();\r
749                                         for (int k=0; k<remoteList.size() && !found && keepRunning; k++) {\r
750                                                 if (remoteList.get(k).getName().equalsIgnoreCase(enTag.getName())) {\r
751                                                         conn.getTagTable().updateTagGuid(enTag.getGuid(), remoteList.get(k).getGuid());\r
752                                                         enTag = remoteList.get(k);\r
753                                                         logger.log(logger.EXTREME, "Matching tag name found");\r
754                                                         found = true;\r
755                                                 }\r
756                                         }\r
757                                         if (!found)\r
758                                                 enTag = noteStore.createTag(authToken, enTag);\r
759                                         else\r
760                                                 enTag.setUpdateSequenceNum(noteStore.updateTag(authToken,enTag));\r
761                                         sequence = enTag.getUpdateSequenceNum();\r
762                                         if (!oldGuid.equals(enTag.getGuid())) {\r
763                                                 logger.log(logger.EXTREME, "Updating tag guid");\r
764                                                 conn.getTagTable().updateTagGuid(oldGuid, enTag.getGuid());\r
765                                         }\r
766                                 }\r
767                                 logger.log(logger.EXTREME, "Updating tag sequence number");\r
768                                 conn.getTagTable().updateTagSequence(enTag.getGuid(), sequence);\r
769                                 logger.log(logger.EXTREME, "Resetting tag dirty flag");\r
770                                 conn.getTagTable().resetDirtyFlag(enTag.getGuid());\r
771                                 logger.log(logger.EXTREME, "Emitting sequence number to the main thread.");\r
772                                 updateSequenceNumber = sequence;\r
773                                 conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);\r
774                         } catch (EDAMUserException e) {\r
775                                 logger.log(logger.LOW, "*** EDAM User Excepton syncLocalTags");\r
776                                 logger.log(logger.LOW, e.toString());           \r
777                                 error = true;\r
778                         } catch (EDAMSystemException e) {\r
779                                 logger.log(logger.LOW, "** EDAM System Excepton syncLocalTags");\r
780                                 logger.log(logger.LOW, e.toString());   \r
781                                 error = true;\r
782                         } catch (EDAMNotFoundException e) {\r
783                                 logger.log(logger.LOW, "*** EDAM Not Found Excepton syncLocalTags");\r
784                                 logger.log(logger.LOW, e.toString());   \r
785                                 error = true;\r
786                         } catch (TException e) {\r
787                                 logger.log(logger.LOW, "*** EDAM TExcepton syncLocalTags");\r
788                                 logger.log(logger.LOW, e.toString());           \r
789                                 error = true;\r
790                         }       \r
791                         \r
792                         // Find the next tag\r
793                         logger.log(logger.EXTREME, "Finding next tag");\r
794                         enTag = findNextTag();\r
795                 }\r
796                 logger.log(logger.HIGH, "Leaving SyncRunner.syncLocalTags");\r
797         }\r
798         private void syncLocalLinkedNotebooks() {\r
799                 logger.log(logger.HIGH, "Entering SyncRunner.syncLocalLinkedNotebooks");\r
800                 \r
801                 List<String> list = conn.getLinkedNotebookTable().getDirtyGuids();\r
802                 for (int i=0; i<list.size(); i++) {\r
803                         LinkedNotebook book = conn.getLinkedNotebookTable().getNotebook(list.get(i));\r
804                         try {\r
805                                 noteStore.updateLinkedNotebook(authToken, book);\r
806                         } catch (EDAMUserException e) {\r
807                                 logger.log(logger.LOW, "*** EDAM User Excepton syncLocalLinkedNotebooks");\r
808                                 status.message.emit(tr("Error: ") +e);\r
809                                 logger.log(logger.LOW, e.toString());           \r
810                                 error = true;\r
811                                 e.printStackTrace();\r
812                         } catch (EDAMNotFoundException e) {\r
813                                 logger.log(logger.LOW, "*** EDAM Not Found Excepton syncLocalLinkedNotebooks");\r
814                                 status.message.emit(tr("Error: ") +e);\r
815                                 logger.log(logger.LOW, e.toString());           \r
816                                 error = true;\r
817                                 e.printStackTrace();\r
818                         } catch (EDAMSystemException e) {\r
819                                 logger.log(logger.LOW, "*** EDAM System Excepton syncLocalLinkedNotebooks");\r
820                                 status.message.emit(tr("Error: ") +e);\r
821                                 logger.log(logger.LOW, e.toString());           \r
822                                 error = true;\r
823                                 e.printStackTrace();\r
824                         } catch (TException e) {\r
825                                 logger.log(logger.LOW, "*** EDAM TExcepton syncLocalLinkedNotebooks");\r
826                                 status.message.emit(tr("Error: ") +e);\r
827                                 logger.log(logger.LOW, e.toString());           \r
828                                 error = true;\r
829                                 e.printStackTrace();\r
830                         }\r
831                 }\r
832                 logger.log(logger.HIGH, "Leaving SyncRunner.syncLocalLinkedNotebooks");\r
833         }\r
834         // Sync Saved Searches with Evernote\r
835         private void syncLocalSavedSearches() {\r
836                 logger.log(logger.HIGH, "Entering SyncRunner.syncLocalSavedSearches");\r
837                 List<SavedSearch> remoteList = new ArrayList<SavedSearch>();\r
838                 status.message.emit(tr("Sending saved searches."));\r
839         \r
840                 logger.log(logger.EXTREME, "Getting saved searches to compare with local");\r
841                 try {\r
842                         remoteList = noteStore.listSearches(authToken);\r
843                 } catch (EDAMUserException e1) {\r
844                         logger.log(logger.LOW, "*** EDAM User Excepton syncLocalTags getting remote saved search List");\r
845                         status.message.emit(tr("Error: ") +e1);\r
846                         logger.log(logger.LOW, e1.toString());  \r
847                         error = true;\r
848                 } catch (EDAMSystemException e1) {\r
849                         logger.log(logger.LOW, "*** EDAM System Excepton syncLocalTags getting remote saved search List");\r
850                         status.message.emit(tr("Error: ") +e1);\r
851                         logger.log(logger.LOW, e1.toString());          \r
852                         error = true;\r
853                 } catch (TException e1) {\r
854                         logger.log(logger.LOW, "*** EDAM Transaction Excepton syncLocalTags getting remote saved search List");\r
855                         status.message.emit(tr("Error: ") +e1);\r
856                         logger.log(logger.LOW, e1.toString());  \r
857                         error = true;\r
858                 }               \r
859                 \r
860                 List<SavedSearch> searches = conn.getSavedSearchTable().getDirty();\r
861                 int sequence;\r
862                 // Sync the local notebooks with Evernote's\r
863                 logger.log(logger.EXTREME, "Beginning to send saved searches");\r
864                 for (int i=0; i<searches.size() &&  keepRunning; i++) {\r
865                         \r
866                         if (authRefreshNeeded)\r
867                                 refreshConnection();\r
868                         \r
869                         SavedSearch enSearch = searches.get(i);\r
870                         try {\r
871                                 if (enSearch.getUpdateSequenceNum() > 0) \r
872                                         sequence = noteStore.updateSearch(authToken, enSearch);\r
873                                 else {\r
874                                         logger.log(logger.EXTREME, "New saved search found.");\r
875                                         // Look for a tag with the same name.  If one is found, we don't need \r
876                                         // to create another one\r
877                                         boolean found = false;\r
878                                         logger.log(logger.EXTREME, "Matching remote saved search names with local");\r
879                                         for (int k=0; k<remoteList.size() && !found && keepRunning; k++) {\r
880                                                 if (remoteList.get(k).getName().equalsIgnoreCase(enSearch.getName())) {\r
881                                                         enSearch = remoteList.get(k);\r
882                                                         found = true;\r
883                                                         logger.log(logger.EXTREME, "Matching saved search found");\r
884                                                         sequence = enSearch.getUpdateSequenceNum();\r
885                                                 }\r
886                                         }\r
887 \r
888                                         String oldGuid = enSearch.getGuid();\r
889                                         if (!found)\r
890                                                 enSearch = noteStore.createSearch(authToken, enSearch);\r
891                                         sequence = enSearch.getUpdateSequenceNum();\r
892                                         logger.log(logger.EXTREME, "Updating tag guid in local database");\r
893                                         conn.getTagTable().updateTagGuid(oldGuid, enSearch.getGuid());\r
894                                 }\r
895                                 logger.log(logger.EXTREME, "Updating tag sequence in local database");\r
896                                 conn.getSavedSearchTable().updateSavedSearchSequence(enSearch.getGuid(), sequence);\r
897                                 logger.log(logger.EXTREME, "Resetting tag dirty flag");\r
898                                 conn.getSavedSearchTable().resetDirtyFlag(enSearch.getGuid());\r
899                                 logger.log(logger.EXTREME, "Emitting sequence number to the main thread.");\r
900                                 updateSequenceNumber = sequence;\r
901                                 conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);\r
902                         } catch (EDAMUserException e) {\r
903                                 logger.log(logger.LOW, "*** EDAM User Excepton syncLocalTags");\r
904                                 logger.log(logger.LOW, e.toString());   \r
905                                 error = true;\r
906                         } catch (EDAMSystemException e) {\r
907                                 logger.log(logger.LOW, "** EDAM System Excepton syncLocalTags");\r
908                                 logger.log(logger.LOW, e.toString());   \r
909                                 error = true;\r
910                         } catch (EDAMNotFoundException e) {\r
911                                 logger.log(logger.LOW, "*** EDAM Not Found Excepton syncLocalTags");\r
912                                 logger.log(logger.LOW, e.toString());   \r
913                                 error = true;\r
914                         } catch (TException e) {\r
915                                 logger.log(logger.LOW, "*** EDAM TExcepton syncLocalTags");\r
916                                 logger.log(logger.LOW, e.toString());   \r
917                                 error = true;\r
918                         }               \r
919                 }\r
920                 logger.log(logger.HIGH, "Entering SyncRunner.syncLocalSavedSearches");\r
921         }       \r
922 \r
923         // Sync evernote changes with local database\r
924         private void syncRemoteToLocal() {\r
925                 logger.log(logger.HIGH, "Entering SyncRunner.syncRemoteToLocal");\r
926 \r
927                 List<Note> dirtyNotes = conn.getNoteTable().getDirty();\r
928                 dirtyNoteGuids = new Vector<String>();\r
929                 for (int i=0; i<dirtyNotes.size() && keepRunning; i++) {\r
930                         dirtyNoteGuids.add(dirtyNotes.get(i).getGuid());\r
931                 }\r
932                 \r
933                 int chunkSize = 10;\r
934                 SyncChunk chunk = null;\r
935                 boolean fullSync = false;\r
936                 boolean more = true;\r
937                 \r
938                 if (updateSequenceNumber == 0)\r
939                         fullSync = true;\r
940                 \r
941                 status.message.emit(tr("Downloading 0% complete."));\r
942                 \r
943                 while(more &&  keepRunning) {\r
944                         \r
945                         if (authRefreshNeeded)\r
946                                 refreshConnection();\r
947                         \r
948                         chunk = null;\r
949                         int sequence = updateSequenceNumber;\r
950                         try {\r
951                                 logger.log(logger.EXTREME, "Getting chunk from Evernote");\r
952                                 chunk = noteStore.getSyncChunk(authToken, sequence, chunkSize, fullSync);\r
953                         } catch (EDAMUserException e) {\r
954                                 error = true;\r
955                                 e.printStackTrace();\r
956                                 status.message.emit(e.getMessage());\r
957                         } catch (EDAMSystemException e) {\r
958                                 error = true;\r
959                                 e.printStackTrace();\r
960                                 status.message.emit(e.getMessage());\r
961                         } catch (TException e) {\r
962                                 error = true;\r
963                                 e.printStackTrace();\r
964                                 status.message.emit(e.getMessage());\r
965                         } \r
966                         if (error || chunk == null) \r
967                                 return;\r
968                                 \r
969                 \r
970                         \r
971                         syncRemoteTags(chunk.getTags());\r
972                         syncRemoteSavedSearches(chunk.getSearches());\r
973                         syncRemoteNotebooks(chunk.getNotebooks());\r
974                         syncRemoteNotes(chunk.getNotes(), fullSync, authToken);\r
975                         syncRemoteResources(chunk.getResources());\r
976                         syncRemoteLinkedNotebooks(chunk.getLinkedNotebooks());\r
977                         syncExpungedNotes(chunk);\r
978                         \r
979                         \r
980                         // Check for more notes\r
981                         if (chunk.getChunkHighUSN() <= updateSequenceNumber) \r
982                                 more = false;\r
983                         if (error)\r
984                                 more = false;\r
985                         logger.log(logger.EXTREME, "More notes? " +more);\r
986 \r
987                         \r
988                         // Save the chunk sequence number\r
989                         if (!error && chunk.getChunkHighUSN() > 0) {\r
990                                 logger.log(logger.EXTREME, "emitting sequence number to main thread");\r
991                                 updateSequenceNumber = chunk.getChunkHighUSN();\r
992                                 conn.getSyncTable().setLastSequenceDate(chunk.getCurrentTime());\r
993                                 conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);\r
994                         }\r
995                         \r
996                         \r
997                         if (more) {\r
998                                 long pct = chunk.getChunkHighUSN() * 100;\r
999                                 conn.getSyncTable().setLastSequenceDate(chunk.getCurrentTime());\r
1000                                 pct = pct/evernoteUpdateCount;\r
1001                                 status.message.emit(tr("Downloading ") +new Long(pct).toString()+tr("% complete."));\r
1002                         }\r
1003                 }\r
1004 \r
1005                 logger.log(logger.HIGH, "Leaving SyncRunner.syncRemoteToLocal");\r
1006         }\r
1007         // Sync expunged notes\r
1008         private void syncExpungedNotes(SyncChunk chunk) {\r
1009                 // Do the local deletes\r
1010                 logger.log(logger.EXTREME, "Doing local deletes");\r
1011                 List<String> guid = chunk.getExpungedNotes();\r
1012                 if (guid != null) {\r
1013                         for (int i=0; i<guid.size() && keepRunning; i++) {\r
1014                                 String notebookGuid = "";\r
1015                                 Note localNote = conn.getNoteTable().getNote(guid.get(i), false, false, false, false, false);\r
1016                                 if (localNote != null) {\r
1017                                         conn.getNoteTable().updateNoteSequence(guid.get(i), 0);\r
1018                                         notebookGuid = localNote.getNotebookGuid();\r
1019                                 }\r
1020                                 if (!conn.getNotebookTable().isNotebookLocal(notebookGuid)) {\r
1021                                         logger.log(logger.EXTREME, "Expunging local note from database");\r
1022                                         conn.getNoteTable().expungeNote(guid.get(i), true, false);\r
1023                                 }\r
1024                         }\r
1025                 }\r
1026                 guid = chunk.getExpungedNotebooks();\r
1027                 if (guid != null)\r
1028                         for (int i=0; i<guid.size() && keepRunning; i++) {\r
1029                                 logger.log(logger.EXTREME, "Expunging local notebook from database");\r
1030                                 conn.getNotebookTable().expungeNotebook(guid.get(i), false);\r
1031                         }\r
1032                 guid = chunk.getExpungedTags();\r
1033                 if (guid != null)\r
1034                         for (int i=0; i<guid.size() && keepRunning; i++) {\r
1035                                 logger.log(logger.EXTREME, "Expunging tags from local database");\r
1036                                 conn.getTagTable().expungeTag(guid.get(i), false);\r
1037                         }\r
1038                 guid = chunk.getExpungedSearches();\r
1039                 if (guid != null) \r
1040                         for (int i=0; i<guid.size() && keepRunning; i++) {\r
1041                                 logger.log(logger.EXTREME, "Expunging saved search from local database");\r
1042                                 conn.getSavedSearchTable().expungeSavedSearch(guid.get(i), false);\r
1043                         }\r
1044                 guid = chunk.getExpungedLinkedNotebooks();\r
1045                 if (guid != null) \r
1046                         for (int i=0; i<guid.size() && keepRunning; i++) {\r
1047                                 logger.log(logger.EXTREME, "Expunging linked notebook from local database");\r
1048                                 conn.getLinkedNotebookTable().expungeNotebook(guid.get(i), false);\r
1049                         }\r
1050 \r
1051         }\r
1052         // Sync remote tags\r
1053         private void syncRemoteTags(List<Tag> tags) {\r
1054                 logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteTags");\r
1055                 if (tags != null) {\r
1056                         for (int i=0; i<tags.size() && keepRunning; i++) {\r
1057                                 String oldGuid;\r
1058                                 oldGuid = conn.getTagTable().findTagByName(tags.get(i).getName());\r
1059                                 if (oldGuid != null && !tags.get(i).getGuid().equalsIgnoreCase(oldGuid))\r
1060                                         conn.getTagTable().updateTagGuid(oldGuid, tags.get(i).getGuid());\r
1061                                 conn.getTagTable().syncTag(tags.get(i), false);\r
1062                         }\r
1063                 }\r
1064                 logger.log(logger.EXTREME, "Leaving SyncRunner.syncRemoteTags");\r
1065         }\r
1066         // Sync remote saved searches\r
1067         private void syncRemoteSavedSearches(List<SavedSearch> searches) {\r
1068                 logger.log(logger.EXTREME, "Entering SyncRunner.syncSavedSearches");\r
1069                 if (searches != null) {\r
1070                         for (int i=0; i<searches.size() && keepRunning; i++) {\r
1071                                 String oldGuid;\r
1072                                 oldGuid = conn.getSavedSearchTable().findSavedSearchByName(searches.get(i).getName());\r
1073                                 if (oldGuid != null && !searches.get(i).getGuid().equalsIgnoreCase(oldGuid))\r
1074                                         conn.getSavedSearchTable().updateSavedSearchGuid(oldGuid, searches.get(i).getGuid());\r
1075                                 conn.getSavedSearchTable().syncSavedSearch(searches.get(i), false);\r
1076                         }\r
1077                 }\r
1078                 logger.log(logger.EXTREME, "Leaving SyncRunner.syncSavedSearches");\r
1079         }\r
1080         // Sync remote linked notebooks\r
1081         private void syncRemoteLinkedNotebooks(List<LinkedNotebook> books) {\r
1082                 logger.log(logger.EXTREME, "Entering SyncRunner.syncLinkedNotebooks");\r
1083                 if (books != null) {\r
1084                         for (int i=0; i<books.size() && keepRunning; i++) {\r
1085                                 conn.getLinkedNotebookTable().updateNotebook(books.get(i), false); \r
1086                         }\r
1087                 }\r
1088                 logger.log(logger.EXTREME, "Leaving SyncRunner.syncLinkedNotebooks");\r
1089         }\r
1090         // Sync remote Notebooks 2\r
1091         private void syncRemoteNotebooks(List<Notebook> notebooks) {\r
1092                 logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteNotebooks");\r
1093                 if (notebooks != null) {\r
1094                         for (int i=0; i<notebooks.size() && keepRunning; i++) {\r
1095                                 String oldGuid;\r
1096                                 oldGuid = conn.getNotebookTable().findNotebookByName(notebooks.get(i).getName());\r
1097                                 if (oldGuid != null && !conn.getNotebookTable().isNotebookLocal(oldGuid) && !notebooks.get(i).getGuid().equalsIgnoreCase(oldGuid))\r
1098                                         conn.getNotebookTable().updateNotebookGuid(oldGuid, notebooks.get(i).getGuid());\r
1099                                 conn.getNotebookTable().syncNotebook(notebooks.get(i), false); \r
1100                                 \r
1101                                 // Synchronize shared notebook information\r
1102 //                              if (notebooks.get(i).getSharedNotebookIdsSize() > 0) {\r
1103 //                                      conn.getSharedNotebookTable().expungeNotebookByGuid(notebooks.get(i).getGuid(), false);\r
1104 //                                      for (int j=0; j<notebooks.get(i).getSharedNotebookIdsSize(); j++) {\r
1105 //                                              syncRemoteSharedNotebook(notebooks.get(i).getGuid(), notebooks.get(i).getSharedNotebookIds().get(j), authToken);\r
1106 //                                      }\r
1107 //                              }\r
1108                         }\r
1109                 }                       \r
1110                 logger.log(logger.EXTREME, "Leaving SyncRunner.syncRemoteNotebooks");\r
1111         }\r
1112         // Sync remote shared notebook\r
1113 //      private void syncRemoteSharedNotebook(String guid, Long id, String token) {\r
1114 //              List<SharedNotebook> books = noteStore.getSharedNotebookByAuth(authToken);\r
1115 //      }\r
1116         // Sync remote Resources\r
1117         private void syncRemoteResources(List<Resource> resource) {\r
1118                 logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteResources");\r
1119                 if (resource != null) {\r
1120                         for (int i=0; i<resource.size() && keepRunning; i++) {\r
1121                                 syncRemoteResource(resource.get(i), authToken);\r
1122                         }\r
1123                 }\r
1124                 logger.log(logger.EXTREME, "Leaving SyncRunner.syncRemoteResources");\r
1125         }\r
1126         // Sync remote resource\r
1127         private void syncRemoteResource(Resource resource, String authToken) {\r
1128                 // This is how the logic for this works.\r
1129                 // 1.) If the resource is not in the local database, we add it.\r
1130                 // 2.) If a copy of the resource is in the local database and the note isn't dirty, we update the local copy\r
1131                 // 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
1132                 //     is a conflict.  The note conflict should get a copy of the resource at that time.\r
1133                 \r
1134                 boolean saveNeeded = false;\r
1135                 /* #1 */                Resource r = getEvernoteResource(resource.getGuid(), true,true,true, authToken);\r
1136                                                 Resource l = conn.getNoteTable().noteResourceTable.getNoteResource(r.getGuid(), false);\r
1137                                                 if (l == null) {\r
1138                                                         saveNeeded = true;\r
1139                                                 } else {\r
1140                 /* #2 */                        boolean isNoteDirty = conn.getNoteTable().isNoteDirty(r.getNoteGuid());\r
1141                                                         if (!isNoteDirty)\r
1142                                                                 saveNeeded = true;\r
1143                                                         else {\r
1144                 /* #3 */                                String remoteHash = "";\r
1145                                                                 if (r != null && r.getData() != null && r.getData().getBodyHash() != null)\r
1146                                                                         remoteHash = byteArrayToHexString(r.getData().getBodyHash());\r
1147                                                                 String localHash = "";\r
1148                                                                 if (l != null && l.getData() != null && l.getData().getBodyHash() != null)\r
1149                                                                         remoteHash = byteArrayToHexString(l.getData().getBodyHash());\r
1150                                                 \r
1151                                                                 if (localHash.equalsIgnoreCase(remoteHash))\r
1152                                                                         saveNeeded = true;\r
1153                                                         }\r
1154                                                 }\r
1155                                                 \r
1156                                                 if (saveNeeded) \r
1157                                                         conn.getNoteTable().noteResourceTable.updateNoteResource(r, false);\r
1158                                                 if (r.getMime().equalsIgnoreCase("application/vnd.evernote.ink"))\r
1159                                                         downloadInkNoteImage(r.getGuid(), authToken);\r
1160 \r
1161         }\r
1162         // Sync remote notes\r
1163         private void syncRemoteNotes(List<Note> note, boolean fullSync, String token) {\r
1164                 logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteNotes");\r
1165                 if (note != null) {\r
1166                         for (int i=0; i<note.size() && keepRunning; i++) {\r
1167                                 Note n = getEvernoteNote(note.get(i).getGuid(), true, fullSync, true,true, token);\r
1168                                 syncRemoteNote(n, fullSync, token);\r
1169                         }\r
1170                 }\r
1171                 logger.log(logger.EXTREME, "Leaving SyncRunner.syncRemoteNotes");\r
1172         }\r
1173         private void syncRemoteNote(Note n, boolean fullSync, String token) {\r
1174                 if (n!=null) {\r
1175                         \r
1176                         // Basically, this is how the sync logic for a note works.\r
1177                         // If the remote note has changed and the local has not, we\r
1178                         // accept the change.\r
1179                         // If both the local & remote have changed but the sequence\r
1180                         // numbers are the same, we don't accept the change.  This\r
1181                         // seems to happen when attachments are indexed by the server.\r
1182                         // If both the local & remote have changed and the sequence numbers\r
1183                         // are different we move the local copy to a local notebook (making sure\r
1184                         // to copy all resources) and we accept the new one.                    \r
1185                         boolean conflictingNote = true;\r
1186                         logger.log(logger.EXTREME, "Checking for duplicate note " +n.getGuid());\r
1187                         if (dirtyNoteGuids != null && dirtyNoteGuids.contains(n.getGuid())) { \r
1188                                 logger.log(logger.EXTREME, "Conflict check beginning");\r
1189                                 conflictingNote = checkForConflict(n);\r
1190                                 logger.log(logger.EXTREME, "Conflict check results " +conflictingNote);\r
1191                                 if (conflictingNote)\r
1192                                         moveConflictingNote(n.getGuid());\r
1193                         }\r
1194                         if (conflictingNote || fullSync) {\r
1195                                 logger.log(logger.EXTREME, "Saving Note");\r
1196                                 conn.getNoteTable().syncNote(n, false);\r
1197                                 noteSignal.noteChanged.emit(n.getGuid(), null);   // Signal to ivalidate note cache\r
1198                                 noteSignal.noteDownloaded.emit(n, true);                // Signal to add note to index\r
1199                                         logger.log(logger.EXTREME, "Note Saved");\r
1200                                 if (fullSync && n.getResources() != null) {\r
1201                                         for (int q=0; q<n.getResources().size() && keepRunning; q++) {\r
1202                                                 logger.log(logger.EXTREME, "Getting note resources.");\r
1203                                                 conn.getNoteTable().noteResourceTable.updateNoteResource(n.getResources().get(q), false);\r
1204                                                 if (n.getResources().get(q).getMime().equalsIgnoreCase("application/vnd.evernote.ink"))\r
1205                                                         downloadInkNoteImage(n.getResources().get(q).getGuid(), token);\r
1206                                         }\r
1207                                 }\r
1208                         }\r
1209                 }\r
1210         }\r
1211         private Note getEvernoteNote(String guid, boolean withContent, boolean withResourceData, boolean withResourceRecognition, boolean withResourceAlternateData, String token) { \r
1212                 Note n = null;\r
1213                 try {\r
1214                         logger.log(logger.EXTREME, "Retrieving note " +guid);\r
1215                         n = noteStore.getNote(token, guid, withContent, withResourceData, withResourceRecognition, withResourceAlternateData);\r
1216                         logger.log(logger.EXTREME, "Note " +guid +" has been retrieved.");\r
1217                 } catch (EDAMUserException e) {\r
1218                         logger.log(logger.LOW, "*** EDAM User Excepton getEvernoteNote");\r
1219                         logger.log(logger.LOW, e.toString());   \r
1220                         error = true;\r
1221                         e.printStackTrace();\r
1222                 } catch (EDAMSystemException e) {\r
1223                         logger.log(logger.LOW, "*** EDAM System Excepton getEvernoteNote");\r
1224                         logger.log(logger.LOW, e.toString());   \r
1225                         error = true;\r
1226                         e.printStackTrace();\r
1227                 } catch (EDAMNotFoundException e) {\r
1228                         logger.log(logger.LOW, "*** EDAM Not Found Excepton getEvernoteNote");\r
1229                         logger.log(logger.LOW, e.toString());   \r
1230                         error = true;\r
1231                         e.printStackTrace();\r
1232                 } catch (TException e) {\r
1233                         logger.log(logger.LOW, "*** EDAM TExcepton getEvernoteNote");\r
1234                         logger.log(logger.LOW, e.toString());   \r
1235                         error = true;\r
1236                         e.printStackTrace();\r
1237                 }\r
1238                 return n;\r
1239         }\r
1240         private Resource getEvernoteResource(String guid, boolean withData, boolean withRecognition, boolean withAttributes, String token) { \r
1241                 Resource n = null;\r
1242                 try {\r
1243                         logger.log(logger.EXTREME, "Retrieving resource " +guid);\r
1244                         n = noteStore.getResource(token, guid, withData, withRecognition, withAttributes, withAttributes);\r
1245                         logger.log(logger.EXTREME, "Resource " +guid +" has been retrieved.");\r
1246                 } catch (EDAMUserException e) {\r
1247                         logger.log(logger.LOW, "*** EDAM User Excepton getEvernoteNote");\r
1248                         logger.log(logger.LOW, e.toString());   \r
1249                         error = true;\r
1250                         e.printStackTrace();\r
1251                 } catch (EDAMSystemException e) {\r
1252                         logger.log(logger.LOW, "*** EDAM System Excepton getEvernoteNote");\r
1253                         logger.log(logger.LOW, e.toString());   \r
1254                         error = true;\r
1255                         e.printStackTrace();\r
1256                 } catch (EDAMNotFoundException e) {\r
1257                         logger.log(logger.LOW, "*** EDAM Not Found Excepton getEvernoteNote");\r
1258                         logger.log(logger.LOW, e.toString());   \r
1259                         error = true;\r
1260                         e.printStackTrace();\r
1261                 } catch (TException e) {\r
1262                         logger.log(logger.LOW, "*** EDAM TExcepton getEvernoteNote");\r
1263                         logger.log(logger.LOW, e.toString());   \r
1264                         error = true;\r
1265                         e.printStackTrace();\r
1266                 }\r
1267                 return n;\r
1268         }\r
1269 \r
1270         \r
1271         private boolean checkForConflict(Note n) {\r
1272                 logger.log(logger.EXTREME, "Checking note sequence number  " +n.getGuid());\r
1273                 Note oldNote = conn.getNoteTable().getNote(n.getGuid(), false, false, false, false, false);\r
1274                 logger.log(logger.EXTREME, "Local/Remote sequence numbers: " +oldNote.getUpdateSequenceNum()+"/"+n.getUpdateSequenceNum());\r
1275                 if (oldNote.getUpdateSequenceNum() == n.getUpdateSequenceNum())\r
1276                         return false;\r
1277                 return true;\r
1278         }\r
1279         \r
1280         private void moveConflictingNote(String guid) {\r
1281                 logger.log(logger.EXTREME, "Conflicting change found for note " +guid);\r
1282                 List<Notebook> books = conn.getNotebookTable().getAllLocal();\r
1283                 String notebookGuid = null;\r
1284                 for (int i=0; i<books.size() && keepRunning; i++) {\r
1285                         if (books.get(i).getName().equalsIgnoreCase("Conflicting Changes (local)") ||\r
1286                                         books.get(i).getName().equalsIgnoreCase("Conflicting Changes")) {\r
1287                                 notebookGuid = books.get(i).getGuid();\r
1288                                 i=books.size();\r
1289                         }\r
1290                 }\r
1291                 \r
1292                 if (notebookGuid == null) {\r
1293                         logger.log(logger.EXTREME, "Building conflicting change notebook " +guid);\r
1294                         Calendar currentTime = new GregorianCalendar();\r
1295                         Long l = new Long(currentTime.getTimeInMillis());\r
1296                         long prevTime = l;\r
1297                         while (prevTime==l) {\r
1298                                 currentTime = new GregorianCalendar();\r
1299                                 l=currentTime.getTimeInMillis();\r
1300                         }\r
1301                         String randint = new String(Long.toString(l));\r
1302                 \r
1303                         Notebook newBook = new Notebook();\r
1304                         newBook.setUpdateSequenceNum(0);\r
1305                         newBook.setGuid(randint);\r
1306                         newBook.setName("Conflicting Changes");\r
1307                         newBook.setServiceCreated(new Date().getTime());\r
1308                         newBook.setServiceUpdated(new Date().getTime());\r
1309                         newBook.setDefaultNotebook(false);\r
1310                         newBook.setPublished(false);\r
1311                         \r
1312                         conn.getNotebookTable().addNotebook(newBook, false, true);\r
1313                         notebookGuid = newBook.getGuid();\r
1314                 }\r
1315                 \r
1316                 // Now that we have a good notebook guid, we need to move the conflicting note\r
1317                 // to the local notebook\r
1318                 logger.log(logger.EXTREME, "Moving conflicting note " +guid);\r
1319                 Calendar currentTime = new GregorianCalendar();\r
1320                 Long l = new Long(currentTime.getTimeInMillis());\r
1321                 long prevTime = l;\r
1322                 while (prevTime==l) {\r
1323                         currentTime = new GregorianCalendar();\r
1324                         l = currentTime.getTimeInMillis();\r
1325                 }\r
1326                 String newGuid = new String(Long.toString(l));\r
1327                                         \r
1328                 Note oldNote = conn.getNoteTable().getNote(guid, true, true, false, false, false);\r
1329                 for (int i=0; i<oldNote.getResources().size() && keepRunning; i++) {\r
1330                         l = new Long(currentTime.getTimeInMillis());\r
1331                         String newResG = new String(Long.toString(l));\r
1332                         String oldResG = oldNote.getResources().get(i).getGuid();\r
1333                         conn.getNoteTable().noteResourceTable.resetUpdateSequenceNumber(oldResG, true);\r
1334                         conn.getNoteTable().noteResourceTable.updateNoteResourceGuid(oldResG, newResG, true);\r
1335                 }\r
1336                 \r
1337                 conn.getNoteTable().resetNoteSequence(guid);\r
1338                 conn.getNoteTable().updateNoteGuid(guid, newGuid);\r
1339                 conn.getNoteTable().updateNoteNotebook(newGuid, notebookGuid, true);\r
1340                 \r
1341                 \r
1342                 noteSignal.guidChanged.emit(guid,newGuid);\r
1343         }\r
1344         \r
1345 \r
1346 \r
1347         \r
1348         //******************************************************\r
1349         //******************************************************\r
1350         //** Utility Functions\r
1351         //******************************************************\r
1352         //******************************************************\r
1353         // Convert a byte array to a hex string\r
1354         private static String byteArrayToHexString(byte data[]) {\r
1355                 StringBuffer buf = new StringBuffer();\r
1356             for (byte element : data) {\r
1357                 int halfbyte = (element >>> 4) & 0x0F;\r
1358                 int two_halfs = 0;\r
1359                 do {\r
1360                         if ((0 <= halfbyte) && (halfbyte <= 9))\r
1361                                buf.append((char) ('0' + halfbyte));\r
1362                            else\r
1363                                 buf.append((char) ('a' + (halfbyte - 10)));\r
1364                         halfbyte = element & 0x0F;\r
1365                 } while(two_halfs++ < 1);\r
1366             }\r
1367             return buf.toString();              \r
1368         }\r
1369 \r
1370         \r
1371         \r
1372         //*******************************************************\r
1373         //* Find dirty tags, which do not have newly created parents\r
1374         //*******************************************************\r
1375         private Tag findNextTag() {\r
1376                 logger.log(logger.HIGH, "Entering SyncRunner.findNextTag");\r
1377                 Tag nextTag = null;\r
1378                 List<Tag> tags = conn.getTagTable().getDirty();\r
1379                 \r
1380                 // Find the parent.  If the parent has a sequence > 0 then it is a good\r
1381                 // parent.\r
1382                 for (int i=0; i<tags.size() && keepRunning; i++) {\r
1383                         if (tags.get(i).getParentGuid() == null) {\r
1384                                 logger.log(logger.HIGH, "Leaving SyncRunner.findNextTag - tag found without parent");\r
1385                                 return tags.get(i);\r
1386                         }\r
1387                         Tag parentTag = conn.getTagTable().getTag(tags.get(i).getParentGuid());\r
1388                         if (parentTag.getUpdateSequenceNum() > 0) {\r
1389                                 logger.log(logger.HIGH, "Leaving SyncRunner.findNextTag - tag found");\r
1390                                 return tags.get(i);\r
1391                         }\r
1392                 }\r
1393                 \r
1394                 logger.log(logger.HIGH, "Leaving SyncRunner.findNextTag - no tags returned");\r
1395                 return nextTag;\r
1396         }\r
1397         \r
1398         \r
1399            // Connect to Evernote\r
1400     public boolean enConnect()  {\r
1401         try {\r
1402                         userStoreTrans = new THttpClient(userStoreUrl);\r
1403                 } catch (TTransportException e) {\r
1404                         QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, "Transport Excepton", e.getLocalizedMessage());\r
1405                         mb.exec();\r
1406                         e.printStackTrace();\r
1407                 }\r
1408                 userStoreProt = new TBinaryProtocol(userStoreTrans);\r
1409             userStore = new UserStore.Client(userStoreProt, userStoreProt);\r
1410             syncSignal.saveUserStore.emit(userStore);\r
1411             try {\r
1412                         authResult = userStore.authenticate(username, password, consumerKey, consumerSecret);\r
1413                 } catch (EDAMUserException e) {\r
1414                         QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, "Error", "Incorrect username/password");\r
1415                         mb.exec();\r
1416                         isConnected = false;\r
1417                         return false;\r
1418                 } catch (EDAMSystemException e) {\r
1419                         QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, "EDAM System Excepton", e.getLocalizedMessage());\r
1420                         mb.exec();\r
1421                         e.printStackTrace();\r
1422                         isConnected = false;\r
1423                 } catch (TException e) {\r
1424                         QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, "Transport Excepton", e.getLocalizedMessage());\r
1425                         mb.exec();\r
1426                         e.printStackTrace();\r
1427                         isConnected = false;\r
1428                 }\r
1429                 \r
1430             boolean versionOk = false;\r
1431                 try {\r
1432                         versionOk = userStore.checkVersion("NeverNote", \r
1433                     com.evernote.edam.userstore.Constants.EDAM_VERSION_MAJOR, \r
1434                       com.evernote.edam.userstore.Constants.EDAM_VERSION_MINOR);\r
1435                 } catch (TException e) {\r
1436                         e.printStackTrace();\r
1437                         isConnected = false;\r
1438                 } \r
1439             if (!versionOk) { \r
1440                 System.err.println("Incomatible EDAM client protocol version"); \r
1441                 isConnected = false;\r
1442             }\r
1443             if (authResult != null) {\r
1444                 user = authResult.getUser(); \r
1445                 authToken = authResult.getAuthenticationToken(); \r
1446                 noteStoreUrl = noteStoreUrlBase + user.getShardId();\r
1447                 syncSignal.saveAuthToken.emit(authToken);\r
1448                 syncSignal.saveNoteStore.emit(noteStore);\r
1449                 \r
1450          \r
1451                 try {\r
1452                         noteStoreTrans = new THttpClient(noteStoreUrl);\r
1453                 } catch (TTransportException e) {\r
1454                         QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, "Transport Excepton", e.getLocalizedMessage());\r
1455                         mb.exec();\r
1456                         e.printStackTrace();\r
1457                         isConnected = false;\r
1458                 } \r
1459                 noteStoreProt = new TBinaryProtocol(noteStoreTrans);\r
1460                 noteStore = \r
1461                         new NoteStore.Client(noteStoreProt, noteStoreProt); \r
1462                 isConnected = true;\r
1463                 authTimeRemaining = authResult.getExpiration() - authResult.getCurrentTime();\r
1464                 authRefreshTime = authTimeRemaining / 2;\r
1465             }\r
1466             \r
1467                 // Get user information\r
1468                 try {\r
1469                         User user = userStore.getUser(authToken);\r
1470                         syncSignal.saveUserInformation.emit(user);\r
1471                 } catch (EDAMUserException e1) {\r
1472                         e1.printStackTrace();\r
1473                 } catch (EDAMSystemException e1) {\r
1474                         e1.printStackTrace();\r
1475                 } catch (TException e1) {\r
1476                         e1.printStackTrace();\r
1477                 }\r
1478             \r
1479             return isConnected;\r
1480     }\r
1481         // Disconnect from the database                         \r
1482     public void enDisconnect() {\r
1483         isConnected = false;\r
1484     }\r
1485     // Refresh the connection\r
1486     private synchronized void refreshConnection() {\r
1487                 logger.log(logger.EXTREME, "Entering SyncRunner.refreshConnection()");\r
1488 //        Calendar cal = Calendar.getInstance();\r
1489                 \r
1490         // If we are not connected let's get out of here\r
1491         if (!isConnected)\r
1492                 return;\r
1493         \r
1494                 // If we fail too many times, then let's give up.\r
1495                 if (failedRefreshes >=5) {\r
1496                         logger.log(logger.EXTREME, "Refresh attempts have failed.  Disconnecting.");\r
1497                         isConnected = false;\r
1498                         return;\r
1499                 }\r
1500         \r
1501                 // If this is the first time through, then we need to set this\r
1502 //              if (authRefreshTime == 0 || cal.getTimeInMillis() > authRefreshTime) \r
1503 //                      authRefreshTime = cal.getTimeInMillis();\r
1504                 \r
1505  //             // Default to checking again in 5 min.  This in case we fail.\r
1506  //             authRefreshTime = authRefreshTime +(5*60*1000);     \r
1507 \r
1508                 // Try to get a new token\r
1509                 AuthenticationResult newAuth = null; \r
1510                 logger.log(logger.EXTREME, "Beginning to try authentication refresh");\r
1511         try {\r
1512                 if (userStore != null && authToken != null) \r
1513                         newAuth = userStore.refreshAuthentication(authToken); \r
1514                 else\r
1515                         return;\r
1516                 logger.log(logger.EXTREME, "UserStore.refreshAuthentication has succeeded.");\r
1517                 } catch (EDAMUserException e) {\r
1518                         e.printStackTrace();\r
1519                         syncSignal.authRefreshComplete.emit(false);\r
1520                         failedRefreshes++;\r
1521                         return;\r
1522                 } catch (EDAMSystemException e) {\r
1523                         e.printStackTrace();\r
1524                         syncSignal.authRefreshComplete.emit(false);\r
1525                         failedRefreshes++;\r
1526                         return;         \r
1527                 } catch (TException e) { \r
1528                         e.printStackTrace();\r
1529                         syncSignal.authRefreshComplete.emit(false);\r
1530                         failedRefreshes++;\r
1531                         return;\r
1532                 }\r
1533                 \r
1534                 // If we didn't get a good auth, then we've failed\r
1535                 if (newAuth == null) {\r
1536                         failedRefreshes++;\r
1537                         logger.log(logger.EXTREME, "Authentication failure #" +failedRefreshes);\r
1538                         syncSignal.authRefreshComplete.emit(false);\r
1539                         return;\r
1540                 }\r
1541                 \r
1542                 // We got a good token.  Now we need to setup the time to renew it.\r
1543                 logger.log(logger.EXTREME, "Saving authentication tokens");\r
1544                 authResult = newAuth;\r
1545                 authToken = new String(newAuth.getAuthenticationToken());\r
1546 //              authTimeRemaining = authResult.getExpiration() - authResult.getCurrentTime();\r
1547 //              authRefreshTime = cal.getTimeInMillis() + (authTimeRemaining/4);        \r
1548                 failedRefreshes=0;\r
1549                 syncSignal.authRefreshComplete.emit(true);\r
1550                 authRefreshNeeded = false;\r
1551                         \r
1552                 // This should never happen, but if it does we consider this a faild attempt.\r
1553 //              if (authTimeRemaining <= 0) {\r
1554 //                      failedRefreshes++;\r
1555 //                      syncSignal.authRefreshComplete.emit(false);\r
1556 //              }\r
1557     }\r
1558     \r
1559         public synchronized boolean addWork(String request) {\r
1560                 if (workQueue.offer(request))\r
1561                         return true;\r
1562                 return false;\r
1563         }\r
1564     \r
1565     private Note getNoteContent(Note n) {\r
1566         n.setContent(conn.getNoteTable().getNoteContentBinary(n.getGuid()));\r
1567         return n;\r
1568     }\r
1569 \r
1570 \r
1571 \r
1572     //*********************************************************\r
1573     //* Special download instructions.  Used for DB upgrades\r
1574     //*********************************************************\r
1575     private void downloadAllSharedNotebooks() {\r
1576         try {\r
1577                         List<SharedNotebook> books = noteStore.listSharedNotebooks(authToken);\r
1578                         logger.log(logger.LOW, "Shared notebooks found = " +books.size());\r
1579                         for (int i=0; i<books.size(); i++) {\r
1580                                 conn.getSharedNotebookTable().updateNotebook(books.get(i), false);\r
1581                         }\r
1582                         conn.getSyncTable().deleteRecord("FullSharedNotebookSync");\r
1583                 } catch (EDAMUserException e1) {\r
1584                         e1.printStackTrace();\r
1585                         status.message.emit(tr("User exception Listing shared notebooks."));\r
1586                         logger.log(logger.LOW, e1.getMessage());\r
1587                         return;\r
1588                 } catch (EDAMSystemException e1) {\r
1589                         e1.printStackTrace();\r
1590                         status.message.emit(tr("System exception Listing shared notebooks."));\r
1591                         logger.log(logger.LOW, e1.getMessage());\r
1592                         return;\r
1593                 } catch (TException e1) {\r
1594                         e1.printStackTrace();\r
1595                         status.message.emit(tr("Transaction exception Listing shared notebooks."));\r
1596                         logger.log(logger.LOW, e1.getMessage());\r
1597                         return;\r
1598                 } catch (EDAMNotFoundException e1) {\r
1599                         e1.printStackTrace();\r
1600                         status.message.emit(tr("EDAM Not Found exception Listing shared notebooks."));\r
1601                         logger.log(logger.LOW, e1.getMessage());\r
1602                 }\r
1603     }\r
1604     private void downloadAllNotebooks() {\r
1605         try {\r
1606                         List<Notebook> books = noteStore.listNotebooks(authToken);\r
1607                         logger.log(logger.LOW, "Shared notebooks found = " +books.size());\r
1608                         for (int i=0; i<books.size(); i++) {\r
1609                                 conn.getNotebookTable().updateNotebook(books.get(i), false);\r
1610                         }\r
1611                         conn.getSyncTable().deleteRecord("FullNotebookSync");\r
1612                 } catch (EDAMUserException e1) {\r
1613                         e1.printStackTrace();\r
1614                         status.message.emit(tr("User exception Listing notebooks."));\r
1615                         logger.log(logger.LOW, e1.getMessage());\r
1616                         return;\r
1617                 } catch (EDAMSystemException e1) {\r
1618                         e1.printStackTrace();\r
1619                         status.message.emit(tr("System exception Listing notebooks."));\r
1620                         logger.log(logger.LOW, e1.getMessage());\r
1621                         return;\r
1622                 } catch (TException e1) {\r
1623                         e1.printStackTrace();\r
1624                         status.message.emit(tr("Transaction exception Listing notebooks."));\r
1625                         logger.log(logger.LOW, e1.getMessage());\r
1626                         return;\r
1627                 }\r
1628     }\r
1629     private void downloadAllLinkedNotebooks() {\r
1630         try {\r
1631                         List<LinkedNotebook> books = noteStore.listLinkedNotebooks(authToken);\r
1632                         logger.log(logger.LOW, "Linked notebooks found = " +books.size());\r
1633                         for (int i=0; i<books.size(); i++) {\r
1634                                 conn.getLinkedNotebookTable().updateNotebook(books.get(i), false);\r
1635                         }\r
1636                         conn.getSyncTable().deleteRecord("FullLinkedNotebookSync");\r
1637                 } catch (EDAMUserException e1) {\r
1638                         e1.printStackTrace();\r
1639                         status.message.emit(tr("User exception Listing linked notebooks."));\r
1640                         logger.log(logger.LOW, e1.getMessage());\r
1641                         return;\r
1642                 } catch (EDAMSystemException e1) {\r
1643                         e1.printStackTrace();\r
1644                         status.message.emit(tr("System exception Listing linked notebooks."));\r
1645                         logger.log(logger.LOW, e1.getMessage());\r
1646                         return;\r
1647                 } catch (TException e1) {\r
1648                         e1.printStackTrace();\r
1649                         status.message.emit(tr("Transaction exception Listing lineked notebooks."));\r
1650                         logger.log(logger.LOW, e1.getMessage());\r
1651                         return;\r
1652                 } catch (EDAMNotFoundException e1) {\r
1653                         e1.printStackTrace();\r
1654                         status.message.emit(tr("EDAM Not Found exception Listing linked notebooks."));\r
1655                         logger.log(logger.LOW, e1.getMessage());\r
1656                 }\r
1657     }\r
1658 \r
1659     \r
1660     private void downloadInkNoteImage(String guid, String authToken) {\r
1661                 String urlBase = noteStoreUrl.replace("/edam/note/", "/shard/") + "/res/"+guid+".ink?slice=";\r
1662 //              urlBase = "https://www.evernote.com/shard/s1/res/52b567a9-54ae-4a08-afc5-d5bae275b2a8.ink?slice=";\r
1663                 Integer slice = 1;\r
1664                 Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(guid, false);\r
1665                 conn.getInkImagesTable().expungeImage(r.getGuid());\r
1666                 int sliceCount = 1+((r.getHeight()-1)/480);\r
1667                 HttpClient http = new DefaultHttpClient();\r
1668         for (int i=0; i<sliceCount; i++) {\r
1669                 String url = urlBase + slice.toString();\r
1670                 HttpPost post = new HttpPost(url);\r
1671                 post.getParams().setParameter("auth", authToken);\r
1672                 List <NameValuePair> nvps = new ArrayList <NameValuePair>();\r
1673             nvps.add(new BasicNameValuePair("auth", authToken));\r
1674 \r
1675             try {\r
1676                                 post.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));\r
1677                         } catch (UnsupportedEncodingException e1) {\r
1678                                 // TODO Auto-generated catch block\r
1679                                 e1.printStackTrace();\r
1680                         }\r
1681                 try {\r
1682                         HttpResponse response = http.execute(post);\r
1683                         HttpEntity resEntity = response.getEntity();\r
1684                         InputStream is = resEntity.getContent();\r
1685                         QByteArray data = writeToFile(is);\r
1686                         conn.getInkImagesTable().saveImage(guid, slice, data);\r
1687                         } catch (ClientProtocolException e) {\r
1688                                 e.printStackTrace();\r
1689                         } catch (IOException e) {\r
1690                                 e.printStackTrace();\r
1691                         }\r
1692 \r
1693                         slice++;\r
1694         }\r
1695         http.getConnectionManager().shutdown(); \r
1696                 noteSignal.noteChanged.emit(r.getNoteGuid(), null);   // Signal to ivalidate note cache\r
1697     }\r
1698     \r
1699     \r
1700     public QByteArray writeToFile(InputStream iStream) throws IOException {\r
1701 \r
1702             File temp = File.createTempFile("nn-inknote-temp", ".png");\r
1703 \r
1704             // Save InputStream to the file.\r
1705             BufferedOutputStream fOut = null;\r
1706             try {\r
1707               fOut = new BufferedOutputStream(new FileOutputStream(temp));\r
1708               byte[] buffer = new byte[32 * 1024];\r
1709               int bytesRead = 0;\r
1710               while ((bytesRead = iStream.read(buffer)) != -1) {\r
1711                 fOut.write(buffer, 0, bytesRead);\r
1712               }\r
1713             }\r
1714             finally {\r
1715                 iStream.close();\r
1716                 fOut.close();\r
1717             }\r
1718             QFile tempFile = new QFile(temp.getAbsoluteFile().toString());\r
1719             tempFile.open(OpenModeFlag.ReadOnly);\r
1720             QByteArray data = tempFile.readAll();\r
1721             tempFile.close();\r
1722             tempFile.remove();\r
1723             return data;\r
1724     }\r
1725     \r
1726     \r
1727         //******************************************\r
1728         //* Begin syncing shared notebooks \r
1729         //******************************************\r
1730     private void syncLinkedNotebooks() {\r
1731         logger.log(logger.MEDIUM, "Authenticating Shared Notebooks");\r
1732         status.message.emit(tr("Synchronizing shared notebooks."));\r
1733         List<LinkedNotebook> books = conn.getLinkedNotebookTable().getAll();\r
1734         for (int i=0; i<books.size(); i++) {\r
1735                 try {\r
1736                         long lastSyncDate = conn.getLinkedNotebookTable().getLastSequenceDate(books.get(i).getGuid());\r
1737                         int lastSequenceNumber = conn.getLinkedNotebookTable().getLastSequenceNumber(books.get(i).getGuid());\r
1738                         linkedAuthResult = noteStore.authenticateToSharedNotebook(books.get(i).getShareKey(), authToken);\r
1739                         SyncState linkedSyncState = \r
1740                                 noteStore.getLinkedNotebookSyncState(linkedAuthResult.getAuthenticationToken(), books.get(i));\r
1741                         if (linkedSyncState.getUpdateCount() > lastSequenceNumber) {\r
1742                                 if (lastSyncDate < linkedSyncState.getFullSyncBefore()) {\r
1743                                         lastSequenceNumber = 0;\r
1744                                 }\r
1745                                         syncLinkedNotebook(books.get(i), lastSequenceNumber, linkedSyncState.getUpdateCount());\r
1746                         }\r
1747                         \r
1748                         // Synchronize local changes\r
1749                         syncLocalLinkedNoteChanges(books.get(i));\r
1750                                 \r
1751                 } catch (EDAMUserException e) {\r
1752                         // TODO Auto-generated catch block\r
1753                         e.printStackTrace();\r
1754                 } catch (EDAMNotFoundException e) {\r
1755                         status.message.emit(tr("Error synchronizing \" " +\r
1756                                         books.get(i).getShareName()+"\". Please verify you still have access to that shared notebook."));\r
1757                         error = true;\r
1758                         e.printStackTrace();\r
1759                 } catch (EDAMSystemException e) {\r
1760                         // TODO Auto-generated catch block\r
1761                         e.printStackTrace();\r
1762                 } catch (TException e) {\r
1763                         // TODO Auto-generated catch block\r
1764                         e.printStackTrace();\r
1765                 }\r
1766         }\r
1767         \r
1768         // Cleanup tags\r
1769         conn.getTagTable().removeUnusedLinkedTags();\r
1770         conn.getTagTable().cleanupTags();\r
1771         tagSignal.listChanged.emit();\r
1772         }\r
1773 \r
1774     \r
1775     //**************************************************************\r
1776     //* Linked notebook contents (from someone else's account)\r
1777     //*************************************************************\r
1778         private void syncLinkedNotebook(LinkedNotebook book, int usn, int highSequence) {\r
1779                 boolean fullSync = false;\r
1780                 if (usn == 0)\r
1781                         fullSync = true;\r
1782                 while (usn < highSequence) {\r
1783                         try {\r
1784                                 SyncChunk chunk = \r
1785                                         noteStore.getLinkedNotebookSyncChunk(authToken, book, usn, 10, fullSync);\r
1786 //                                      noteStore.getLinkedNotebookSyncChunk(linkedAuthResult.getAuthenticationToken(), book, usn, 10, fullSync);\r
1787 \r
1788                                 syncRemoteNotes(chunk.getNotes(), fullSync, linkedAuthResult.getAuthenticationToken());\r
1789                                 findNewLinkedTags(chunk.getNotes(), linkedAuthResult.getAuthenticationToken());\r
1790                                 for (int i=0; i<chunk.getResourcesSize(); i++) {\r
1791                                         syncRemoteResource(chunk.getResources().get(i), linkedAuthResult.getAuthenticationToken());\r
1792                                 }\r
1793                                 syncRemoteLinkedNotebooks(chunk.getNotebooks(), false, book);\r
1794 //                              String notebookGuid = conn.getLinkedNotebookTable().getNotebookGuid(book.getGuid());\r
1795                                 SharedNotebook s = noteStore.getSharedNotebookByAuth(linkedAuthResult.getAuthenticationToken());\r
1796                                 syncLinkedTags(chunk.getTags(), s.getNotebookGuid());\r
1797                                 \r
1798                                 \r
1799                                 // Expunge records\r
1800                                 for (int i=0; i<chunk.getExpungedLinkedNotebooksSize(); i++) {\r
1801                                         conn.getLinkedNotebookTable().expungeNotebook(chunk.getExpungedLinkedNotebooks().get(i), false);\r
1802                                 }\r
1803                                 usn = chunk.getChunkHighUSN();\r
1804                                 conn.getLinkedNotebookTable().setLastSequenceDate(book.getGuid(),chunk.getCurrentTime());\r
1805                                 conn.getLinkedNotebookTable().setLastSequenceNumber(book.getGuid(),chunk.getChunkHighUSN());\r
1806                         } catch (EDAMUserException e) {\r
1807                                 // TODO Auto-generated catch block\r
1808                                 e.printStackTrace();\r
1809                         } catch (EDAMSystemException e) {\r
1810                                 // TODO Auto-generated catch block\r
1811                                 e.printStackTrace();\r
1812                         } catch (EDAMNotFoundException e) {\r
1813                                 // TODO Auto-generated catch block\r
1814                                 e.printStackTrace();\r
1815                         } catch (TException e) {\r
1816                                 // TODO Auto-generated catch block\r
1817                                 e.printStackTrace();\r
1818                         }\r
1819                 }\r
1820         }\r
1821         // Sync remote tags\r
1822         private void syncLinkedTags(List<Tag> tags, String notebookGuid) {\r
1823                 logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteTags");\r
1824                 if (tags != null) {\r
1825                         for (int i=0; i<tags.size() && keepRunning; i++) {\r
1826                                 conn.getTagTable().syncLinkedTag(tags.get(i), notebookGuid, false);\r
1827                         }\r
1828                 }\r
1829                 logger.log(logger.EXTREME, "Leaving SyncRunner.syncRemoteTags");\r
1830         }\r
1831         \r
1832         // Sync notebooks from a linked notebook\r
1833         private void syncRemoteLinkedNotebooks(List<Notebook> notebooks, boolean readOnly, LinkedNotebook linked) {\r
1834                 logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteNotebooks");\r
1835                 if (notebooks != null) {\r
1836                         for (int i=0; i<notebooks.size() && keepRunning; i++) {\r
1837                                 try {\r
1838                                         SharedNotebook s = noteStore.getSharedNotebookByAuth(linkedAuthResult.getAuthenticationToken());\r
1839                                         conn.getLinkedNotebookTable().setNotebookGuid(s.getShareKey(), s.getNotebookGuid());\r
1840                                         readOnly = !s.isNotebookModifiable();\r
1841                                         notebooks.get(i).setName(linked.getShareName());\r
1842                                         notebooks.get(i).setDefaultNotebook(false);\r
1843                                         conn.getNotebookTable().syncLinkedNotebook(notebooks.get(i), false, readOnly); \r
1844                                 } catch (EDAMUserException e) {\r
1845                                         readOnly = true;\r
1846                                         e.printStackTrace();\r
1847                                 } catch (EDAMNotFoundException e) {\r
1848                                         readOnly = true;\r
1849                                         e.printStackTrace();\r
1850                                 } catch (EDAMSystemException e) {\r
1851                                         readOnly = true;\r
1852                                         e.printStackTrace();\r
1853                                 } catch (TException e) {\r
1854                                         readOnly = true;\r
1855                                         e.printStackTrace();\r
1856                                 }\r
1857 \r
1858                         }\r
1859                 }                       \r
1860                 logger.log(logger.EXTREME, "Leaving SyncRunner.syncRemoteNotebooks");\r
1861         }\r
1862 \r
1863         private void findNewLinkedTags(List<Note> newNotes, String token) {\r
1864                 if (newNotes == null)\r
1865                         return;\r
1866                 for (int i=0; i<newNotes.size(); i++) {\r
1867                         Note n = newNotes.get(i);\r
1868                         for (int j=0; j<n.getTagGuidsSize(); j++) {\r
1869                                 String tag = n.getTagGuids().get(j);\r
1870                                 if (!conn.getTagTable().exists(tag)) {\r
1871                                         Tag newTag;\r
1872                                         try {\r
1873                                                 newTag = noteStore.getTag(token, tag);\r
1874                                                 conn.getTagTable().addTag(newTag, false);\r
1875                                         } catch (EDAMUserException e) {\r
1876                                                 // TODO Auto-generated catch block\r
1877                                                 e.printStackTrace();\r
1878                                         } catch (EDAMSystemException e) {\r
1879                                                 // TODO Auto-generated catch block\r
1880                                                 e.printStackTrace();\r
1881                                         } catch (EDAMNotFoundException e) {\r
1882                                                 // TODO Auto-generated catch block\r
1883                                                 e.printStackTrace();\r
1884                                         } catch (TException e) {\r
1885                                                 // TODO Auto-generated catch block\r
1886                                                 e.printStackTrace();\r
1887                                         }\r
1888                                         \r
1889                                 }\r
1890                         }\r
1891                 }\r
1892         }\r
1893 \r
1894         // Synchronize changes locally done to linked notes\r
1895         private void syncLocalLinkedNoteChanges(LinkedNotebook book) {\r
1896                 String notebookGuid = conn.getLinkedNotebookTable().getNotebookGuid(book.getGuid());\r
1897                 List<Note> notes = conn.getNoteTable().getDirtyLinked(notebookGuid);\r
1898                 for (int i=0; i<notes.size(); i++) {\r
1899                         syncLocalNote(notes.get(i), linkedAuthResult.getAuthenticationToken());\r
1900                 }\r
1901         }\r
1902 \r
1903 }\r