OSDN Git Service

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