OSDN Git Service

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