2 * This file is part of NixNote
\r
3 * Copyright 2009 Randy Baumgarte
\r
5 * This file may be licensed under the terms of of the
\r
6 * GNU General Public License Version 2 (the ``GPL'').
\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
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
19 package cx.fbn.nevernote.threads;
\r
21 import java.io.BufferedOutputStream;
\r
22 import java.io.File;
\r
23 import java.io.FileOutputStream;
\r
24 import java.io.IOException;
\r
25 import java.io.InputStream;
\r
26 import java.io.UnsupportedEncodingException;
\r
27 import java.net.UnknownHostException;
\r
28 import java.util.ArrayList;
\r
29 import java.util.Calendar;
\r
30 import java.util.Date;
\r
31 import java.util.GregorianCalendar;
\r
32 import java.util.HashMap;
\r
33 import java.util.List;
\r
34 import java.util.TreeSet;
\r
35 import java.util.concurrent.LinkedBlockingQueue;
\r
37 import org.apache.http.HttpEntity;
\r
38 import org.apache.http.HttpResponse;
\r
39 import org.apache.http.NameValuePair;
\r
40 import org.apache.http.client.ClientProtocolException;
\r
41 import org.apache.http.client.HttpClient;
\r
42 import org.apache.http.client.entity.UrlEncodedFormEntity;
\r
43 import org.apache.http.client.methods.HttpPost;
\r
44 import org.apache.http.impl.client.DefaultHttpClient;
\r
45 import org.apache.http.message.BasicNameValuePair;
\r
46 import org.apache.http.protocol.HTTP;
\r
47 import org.apache.thrift.TException;
\r
48 import org.apache.thrift.protocol.TBinaryProtocol;
\r
49 import org.apache.thrift.transport.THttpClient;
\r
50 import org.apache.thrift.transport.TTransportException;
\r
52 import com.evernote.edam.error.EDAMNotFoundException;
\r
53 import com.evernote.edam.error.EDAMSystemException;
\r
54 import com.evernote.edam.error.EDAMUserException;
\r
55 import com.evernote.edam.notestore.NoteStore;
\r
56 import com.evernote.edam.notestore.NoteStore.Client;
\r
57 import com.evernote.edam.notestore.SyncChunk;
\r
58 import com.evernote.edam.notestore.SyncState;
\r
59 import com.evernote.edam.type.Data;
\r
60 import com.evernote.edam.type.LinkedNotebook;
\r
61 import com.evernote.edam.type.Note;
\r
62 import com.evernote.edam.type.Notebook;
\r
63 import com.evernote.edam.type.Resource;
\r
64 import com.evernote.edam.type.SavedSearch;
\r
65 import com.evernote.edam.type.SharedNotebook;
\r
66 import com.evernote.edam.type.Tag;
\r
67 import com.evernote.edam.type.User;
\r
68 import com.evernote.edam.userstore.AuthenticationResult;
\r
69 import com.evernote.edam.userstore.UserStore;
\r
70 import com.trolltech.qt.core.QByteArray;
\r
71 import com.trolltech.qt.core.QFile;
\r
72 import com.trolltech.qt.core.QIODevice.OpenModeFlag;
\r
73 import com.trolltech.qt.core.QObject;
\r
74 import com.trolltech.qt.core.QTextCodec;
\r
75 import com.trolltech.qt.gui.QMessageBox;
\r
77 import cx.fbn.nevernote.signals.NoteIndexSignal;
\r
78 import cx.fbn.nevernote.signals.NoteResourceSignal;
\r
79 import cx.fbn.nevernote.signals.NoteSignal;
\r
80 import cx.fbn.nevernote.signals.NotebookSignal;
\r
81 import cx.fbn.nevernote.signals.SavedSearchSignal;
\r
82 import cx.fbn.nevernote.signals.StatusSignal;
\r
83 import cx.fbn.nevernote.signals.SyncSignal;
\r
84 import cx.fbn.nevernote.signals.TagSignal;
\r
85 import cx.fbn.nevernote.sql.DatabaseConnection;
\r
86 import cx.fbn.nevernote.sql.DeletedItemRecord;
\r
87 import cx.fbn.nevernote.utilities.ApplicationLogger;
\r
89 public class SyncRunner extends QObject implements Runnable {
\r
91 private final ApplicationLogger logger;
\r
92 private DatabaseConnection conn;
\r
93 private boolean idle;
\r
94 public boolean error;
\r
95 public volatile List<String> errorSharedNotebooks;
\r
96 public volatile HashMap<String,String> errorSharedNotebooksIgnored;
\r
97 public volatile boolean isConnected;
\r
98 public volatile boolean keepRunning;
\r
99 public volatile String authToken;
\r
100 private long evernoteUpdateCount;
\r
101 private final String userAgent = "NixNote/" + System.getProperty("os.name")
\r
102 +"/"+System.getProperty("java.vendor") + "/"
\r
103 + System.getProperty("java.version") +";";
\r
105 public volatile NoteStore.Client localNoteStore;
\r
106 private UserStore.Client userStore;
\r
108 public volatile StatusSignal status;
\r
109 public volatile TagSignal tagSignal;
\r
110 public volatile NotebookSignal notebookSignal;
\r
111 public volatile NoteIndexSignal noteIndexSignal;
\r
112 public volatile NoteSignal noteSignal;
\r
113 public volatile SavedSearchSignal searchSignal;
\r
114 public volatile NoteResourceSignal resourceSignal;
\r
115 public volatile SyncSignal syncSignal;
\r
116 public volatile boolean authRefreshNeeded;
\r
117 public volatile boolean syncNeeded;
\r
118 public volatile boolean disableUploads;
\r
119 public volatile boolean syncDeletedContent;
\r
120 private volatile List<String> dirtyNoteGuids;
\r
122 public volatile String username = "";
\r
123 public volatile String password = "";
\r
124 public volatile String userStoreUrl;
\r
125 // private final static String consumerKey = "baumgarte";
\r
126 // private final static String consumerSecret = "eb8b5740e17cb55f";
\r
127 public String noteStoreUrlBase;
\r
128 private THttpClient userStoreTrans;
\r
129 private TBinaryProtocol userStoreProt;
\r
130 //private AuthenticationResult authResult;
\r
131 private AuthenticationResult linkedAuthResult;
\r
132 private User user;
\r
133 // private long authTimeRemaining;
\r
134 public long authRefreshTime;
\r
135 public long failedRefreshes = 0;
\r
136 public THttpClient noteStoreTrans;
\r
137 public TBinaryProtocol noteStoreProt;
\r
138 public String noteStoreUrl;
\r
139 public long sequenceDate;
\r
140 public int updateSequenceNumber;
\r
141 private boolean refreshNeeded;
\r
142 private volatile LinkedBlockingQueue<String> workQueue;
\r
143 private static int MAX_QUEUED_WAITING = 1000;
\r
147 String resourceUrl;
\r
150 private final TreeSet<String> ignoreTags;
\r
151 private final TreeSet<String> ignoreNotebooks;
\r
152 private final TreeSet<String> ignoreLinkedNotebooks;
\r
153 private HashMap<String,String> badTagSync;
\r
157 public SyncRunner(String logname, String u, String i, String r, String uid, String pswd, String cpswd) {
\r
158 logger = new ApplicationLogger(logname);
\r
160 noteSignal = new NoteSignal();
\r
161 status = new StatusSignal();
\r
162 tagSignal = new TagSignal();
\r
163 notebookSignal = new NotebookSignal();
\r
164 noteIndexSignal = new NoteIndexSignal();
\r
165 noteSignal = new NoteSignal();
\r
166 searchSignal = new SavedSearchSignal();
\r
167 syncSignal = new SyncSignal();
\r
168 resourceSignal = new NoteResourceSignal();
\r
175 // this.setAutoDelete(false);
\r
177 isConnected = false;
\r
178 syncNeeded = false;
\r
179 authRefreshNeeded = false;
\r
180 keepRunning = true;
\r
182 disableUploads = false;
\r
183 ignoreTags = new TreeSet<String>();
\r
184 ignoreNotebooks = new TreeSet<String>();
\r
185 ignoreLinkedNotebooks = new TreeSet<String>();
\r
187 // setAutoDelete(false);
\r
188 workQueue=new LinkedBlockingQueue<String>(MAX_QUEUED_WAITING);
\r
191 public void run() {
\r
192 errorSharedNotebooks = new ArrayList<String>();
\r
193 errorSharedNotebooksIgnored = new HashMap<String,String>();
\r
195 logger.log(logger.EXTREME, "Starting thread");
\r
196 conn = new DatabaseConnection(logger, dburl, indexUrl, resourceUrl, dbuid, dbpswd, dbcpswd, 200);
\r
197 while(keepRunning) {
\r
198 logger.log(logger.EXTREME, "Blocking until work is found");
\r
199 String work = workQueue.take();
\r
200 logger.log(logger.LOW, "Dirty Notes Before Sync: " +new Integer(conn.getNoteTable().getDirtyCount()).toString());
\r
201 logger.log(logger.EXTREME, "Work found: " +work);
\r
202 if (work.equalsIgnoreCase("stop")) {
\r
206 conn.getNoteTable().dumpDirtyNotes(); // Debugging statement
\r
210 logger.log(logger.EXTREME, "SyncNeeded is true");
\r
211 refreshNeeded=false;
\r
212 sequenceDate = conn.getSyncTable().getLastSequenceDate();
\r
213 updateSequenceNumber = conn.getSyncTable().getUpdateSequenceNumber();
\r
215 logger.log(logger.EXTREME, "Beginning sync");
\r
216 evernoteSync(localNoteStore);
\r
217 logger.log(logger.EXTREME, "Sync finished");
\r
218 } catch (UnknownHostException e) {
\r
219 status.message.emit(e.getMessage());
\r
223 logger.log(logger.EXTREME, "Signaling refresh finished. refreshNeeded=" +refreshNeeded);
\r
224 syncSignal.finished.emit(refreshNeeded);
\r
226 syncSignal.errorDisconnect.emit();
\r
227 status.message.emit(tr("Error synchronizing - see log for details."));
\r
229 logger.log(logger.LOW, "Dirty Notes After Sync: " +new Integer(conn.getNoteTable().getDirtyCount()).toString());
\r
230 conn.getNoteTable().dumpDirtyNotes();
\r
231 logger.log(logger.LOW, "---");
\r
234 catch (InterruptedException e1) {
\r
235 e1.printStackTrace();
\r
241 public DatabaseConnection getConnection() {
\r
245 public boolean isIdle() {
\r
250 public void setConnected(boolean c) {
\r
253 public void setKeepRunning(boolean r) {
\r
254 logger.log(logger.EXTREME, "Setting keepRunning=" +r);
\r
257 public void setNoteStore(NoteStore.Client c) {
\r
258 logger.log(logger.EXTREME, "Setting NoteStore in sync thread");
\r
259 localNoteStore = c;
\r
261 public void setUserStore(UserStore.Client c) {
\r
262 logger.log(logger.EXTREME, "Setting UserStore in sync thread");
\r
266 public void setEvernoteUpdateCount(long s) {
\r
267 logger.log(logger.EXTREME, "Setting Update Count in sync thread");
\r
268 evernoteUpdateCount = s;
\r
271 //***************************************************************
\r
272 //***************************************************************
\r
273 //** These functions deal with Evernote communications
\r
274 //***************************************************************
\r
275 //***************************************************************
\r
276 // Synchronize changes with Evernote
\r
277 @SuppressWarnings("unused")
\r
278 private void evernoteSync(Client noteStore) throws java.net.UnknownHostException {
\r
279 logger.log(logger.HIGH, "Entering SyncRunner.evernoteSync");
\r
281 // Rebuild list of tags & notebooks to ignore
\r
282 ignoreNotebooks.clear();
\r
283 List<String> ignore = conn.getSyncTable().getIgnoreRecords("NOTEBOOK");
\r
284 for (int i=0; i<ignore.size(); i++)
\r
285 ignoreNotebooks.add(ignore.get(i));
\r
288 ignore = conn.getSyncTable().getIgnoreRecords("LINKEDNOTEBOOK");
\r
289 for (int i=0; i<ignore.size(); i++)
\r
290 ignoreLinkedNotebooks.add(ignore.get(i));
\r
292 ignoreTags.clear();
\r
293 ignore = conn.getSyncTable().getIgnoreRecords("TAG");
\r
294 for (int i=0; i<ignore.size(); i++)
\r
295 ignoreTags.add(ignore.get(i));
\r
297 // Make sure we are connected & should keep running
\r
298 if (isConnected && keepRunning) {
\r
300 logger.log(logger.EXTREME, "Synchronizing with Evernote");
\r
301 status.message.emit(tr("Synchronizing with Evernote"));
\r
303 // Get user information
\r
305 logger.log(logger.EXTREME, "getting user from userstore");
\r
306 User user = userStore.getUser(authToken);
\r
307 logger.log(logger.EXTREME, "Saving user information");
\r
308 syncSignal.saveUserInformation.emit(user);
\r
309 } catch (EDAMUserException e1) {
\r
310 e1.printStackTrace();
\r
311 status.message.emit(tr("User exception getting user account information. Aborting sync and disconnecting"));
\r
312 syncSignal.errorDisconnect.emit();
\r
316 } catch (EDAMSystemException e1) {
\r
317 e1.printStackTrace();
\r
318 status.message.emit(tr("System error user account information. Aborting sync and disconnecting!"));
\r
319 syncSignal.errorDisconnect.emit();
\r
323 } catch (TException e1) {
\r
324 e1.printStackTrace();
\r
325 syncSignal.errorDisconnect.emit();
\r
327 status.message.emit(tr("Transaction error getting user account information. Aborting sync and disconnecting!"));
\r
333 SyncState syncState = null;
\r
335 logger.log(logger.EXTREME, "Getting sync state");
\r
336 syncState = noteStore.getSyncState(authToken);
\r
337 syncSignal.saveUploadAmount.emit(syncState.getUploaded());
\r
338 syncSignal.saveEvernoteUpdateCount.emit(syncState.getUpdateCount());
\r
339 evernoteUpdateCount = syncState.getUpdateCount();
\r
340 } catch (EDAMUserException e) {
\r
341 e.printStackTrace();
\r
342 status.message.emit(tr("Error getting sync state! Aborting sync and disconnecting!"));
\r
343 syncSignal.errorDisconnect.emit();
\r
346 } catch (EDAMSystemException e) {
\r
347 e.printStackTrace();
\r
348 status.message.emit(tr("Error getting sync state! Aborting sync and disconnecting!"));
\r
349 syncSignal.errorDisconnect.emit();
\r
352 } catch (TException e) {
\r
353 e.printStackTrace();
\r
354 status.message.emit(tr("Error getting sync state! Aborting sync and disconnecting!"));
\r
355 syncSignal.errorDisconnect.emit();
\r
360 if (syncState == null) {
\r
361 logger.log(logger.EXTREME, "Sync State is null");
\r
362 status.message.emit(tr("Syncronization Error!"));
\r
366 // Determine what to do.
\r
367 // If we need to do a full sync.
\r
368 logger.log(logger.LOW, "Full Sequence Before: " +syncState.getFullSyncBefore());
\r
369 logger.log(logger.LOW, "Last Sequence Date: " +sequenceDate);
\r
370 logger.log(logger.LOW, "Var Last Sequence Number: " +updateSequenceNumber);
\r
371 logger.log(logger.LOW, "DB Last Sequence Number: " + conn.getSyncTable().getUpdateSequenceNumber());
\r
372 if (syncState.getFullSyncBefore() > sequenceDate) {
\r
373 logger.log(logger.EXTREME, "Full sequence date has expired");
\r
375 conn.getSyncTable().setLastSequenceDate(0);
\r
376 updateSequenceNumber = 0;
\r
377 conn.getSyncTable().setUpdateSequenceNumber(0);
\r
379 // Check for "special" sync instructions
\r
380 String syncLinked = conn.getSyncTable().getRecord("FullLinkedNotebookSync");
\r
381 String syncShared = conn.getSyncTable().getRecord("FullSharedNotebookSync");
\r
382 String syncNotebooks = conn.getSyncTable().getRecord("FullNotebookSync");
\r
383 String syncInkNoteImages = conn.getSyncTable().getRecord("FullInkNoteImageSync");
\r
384 if (syncLinked != null) {
\r
385 downloadAllLinkedNotebooks(localNoteStore);
\r
387 if (syncShared != null) {
\r
388 downloadAllSharedNotebooks(localNoteStore);
\r
390 if (syncNotebooks != null) {
\r
391 downloadAllNotebooks(localNoteStore);
\r
394 if (syncInkNoteImages != null) {
\r
395 List<String> guids = conn.getNoteTable().noteResourceTable.findInkNotes();
\r
396 for (int i=0; i<guids.size(); i++) {
\r
397 downloadInkNoteImage(guids.get(i), authToken);
\r
399 conn.getSyncTable().deleteRecord("FullInkNoteImageSync");
\r
402 // If there are remote changes
\r
403 logger.log(logger.LOW, "Update Count: " +syncState.getUpdateCount());
\r
404 logger.log(logger.LOW, "Last Update Count: " +updateSequenceNumber);
\r
406 if (syncState.getUpdateCount() > updateSequenceNumber) {
\r
407 logger.log(logger.EXTREME, "Refresh needed is true");
\r
408 refreshNeeded = true;
\r
409 logger.log(logger.EXTREME, "Downloading changes");
\r
410 syncRemoteToLocal(localNoteStore);
\r
413 //*****************************************
\r
414 //* Sync linked/shared notebooks
\r
415 //*****************************************
\r
416 //syncLinkedNotebooks();
\r
417 //conn.getNoteTable().getDirty();
\r
418 //disableUploads = true; /// DELETE THIS LINE!!!!
\r
419 if (!disableUploads) {
\r
420 logger.log(logger.EXTREME, "Uploading changes");
\r
421 // Synchronize remote changes
\r
423 syncExpunged(localNoteStore);
\r
425 syncLocalTags(localNoteStore);
\r
427 syncLocalNotebooks(localNoteStore);
\r
429 syncLocalLinkedNotebooks(localNoteStore);
\r
431 syncDeletedNotes(localNoteStore);
\r
435 syncLocalSavedSearches(localNoteStore);
\r
438 status.message.emit(tr("Cleaning up"));
\r
439 List<String> notes = conn.getNoteTable().expungeIgnoreSynchronizedNotes(conn.getSyncTable().getIgnoreRecords("NOTEBOOK"),
\r
440 conn.getSyncTable().getIgnoreRecords("TAG"), conn.getSyncTable().getIgnoreRecords("LINKEDNOTEBOOK"));
\r
441 if (notes.size() > 0)
\r
442 syncSignal.refreshLists.emit();
\r
444 //*****************************************
\r
445 //* End of synchronization
\r
446 //*****************************************
\r
448 syncSignal.refreshLists.emit();
\r
451 logger.log(logger.LOW, "Sync completed. Errors=" +error);
\r
452 if (!disableUploads)
\r
453 status.message.emit(tr("Synchronizing complete"));
\r
455 status.message.emit(tr("Download syncronization complete. Uploads have been disabled."));
\r
457 logger.log(logger.EXTREME, "Saving sync time");
\r
458 if (syncState.getCurrentTime() > sequenceDate)
\r
459 sequenceDate = syncState.getCurrentTime();
\r
460 if (syncState.getUpdateCount() > updateSequenceNumber)
\r
461 updateSequenceNumber = syncState.getUpdateCount();
\r
462 conn.getSyncTable().setLastSequenceDate(sequenceDate);
\r
463 conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);
\r
466 logger.log(logger.HIGH, "Leaving SyncRunner.evernoteSync");
\r
469 // Sync deleted items with Evernote
\r
470 private void syncExpunged(Client noteStore) {
\r
471 logger.log(logger.HIGH, "Entering SyncRunner.syncExpunged");
\r
473 List<DeletedItemRecord> expunged = conn.getDeletedTable().getAllDeleted();
\r
474 boolean error = false;
\r
475 for (int i=0; i<expunged.size() && keepRunning; i++) {
\r
477 // if (authRefreshNeeded)
\r
478 // if (!refreshConnection())
\r
482 if (expunged.get(i).type.equalsIgnoreCase("TAG")) {
\r
483 logger.log(logger.EXTREME, "Tag expunged");
\r
484 conn.getDeletedTable().expungeDeletedItem(expunged.get(i).guid, "TAG");
\r
485 updateSequenceNumber = noteStore.expungeTag(authToken, expunged.get(i).guid);
\r
486 conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);
\r
487 conn.getSyncTable().setLastSequenceDate(sequenceDate);
\r
488 conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);
\r
490 if (expunged.get(i).type.equalsIgnoreCase("NOTEBOOK")) {
\r
491 logger.log(logger.EXTREME, "Notebook expunged");
\r
492 conn.getDeletedTable().expungeDeletedItem(expunged.get(i).guid, "NOTEBOOK");
\r
493 updateSequenceNumber = noteStore.expungeNotebook(authToken, expunged.get(i).guid);
\r
494 conn.getSyncTable().setLastSequenceDate(sequenceDate);
\r
495 conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);
\r
497 if (expunged.get(i).type.equalsIgnoreCase("NOTE")) {
\r
498 logger.log(logger.EXTREME, "Note expunged");
\r
499 conn.getDeletedTable().expungeDeletedItem(expunged.get(i).guid, "NOTE");
\r
500 updateSequenceNumber = noteStore.deleteNote(authToken, expunged.get(i).guid);
\r
501 refreshNeeded = true;
\r
502 conn.getSyncTable().setLastSequenceDate(sequenceDate);
\r
503 conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);
\r
505 if (expunged.get(i).type.equalsIgnoreCase("SAVEDSEARCH")) {
\r
506 logger.log(logger.EXTREME, "saved search expunged");
\r
507 conn.getDeletedTable().expungeDeletedItem(expunged.get(i).guid, "SAVEDSEARCH");
\r
508 updateSequenceNumber = noteStore.expungeSearch(authToken, expunged.get(i).guid);
\r
509 conn.getSyncTable().setLastSequenceDate(sequenceDate);
\r
510 conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);
\r
512 } catch (EDAMUserException e) {
\r
513 logger.log(logger.LOW, "EDAM User Excepton in syncExpunged: " +expunged.get(i).guid); // This can happen if we try to delete a deleted note
\r
514 } catch (EDAMSystemException e) {
\r
515 logger.log(logger.LOW, "EDAM System Excepton in syncExpunged: "+expunged.get(i).guid);
\r
516 logger.log(logger.LOW, e.getStackTrace());
\r
518 } catch (EDAMNotFoundException e) {
\r
519 logger.log(logger.LOW, "EDAM Not Found Excepton in syncExpunged: "+expunged.get(i).guid);
\r
520 } catch (TException e) {
\r
521 logger.log(logger.LOW, "EDAM TExcepton in syncExpunged: "+expunged.get(i).guid);
\r
522 logger.log(logger.LOW, e.getStackTrace());
\r
527 conn.getDeletedTable().expungeAllDeletedRecords();
\r
529 logger.log(logger.HIGH, "Leaving SyncRunner.syncExpunged");
\r
532 private void syncDeletedNotes(Client noteStore) {
\r
533 if (syncDeletedContent)
\r
535 logger.log(logger.HIGH, "Entering SyncRunner.syncDeletedNotes");
\r
536 status.message.emit(tr("Synchronizing deleted notes."));
\r
538 List<Note> notes = conn.getNoteTable().getDirty();
\r
539 // Sync the local notebooks with Evernote's
\r
540 for (int i=0; i<notes.size() && keepRunning; i++) {
\r
542 // if (authRefreshNeeded)
\r
543 // if (!refreshConnection())
\r
546 Note enNote = notes.get(i);
\r
548 if (enNote.getUpdateSequenceNum() > 0 && (enNote.isActive() == false || enNote.getDeleted() > 0)) {
\r
549 // Check that the note is valid.
\r
550 if (enNote.isActive() == true || enNote.getDeleted() == 0) {
\r
551 conn.getNoteTable().deleteNote(enNote.getGuid());
\r
552 enNote = conn.getNoteTable().getNote(enNote.getGuid(), false, false, false, false, false);
\r
554 if (syncDeletedContent) {
\r
555 logger.log(logger.EXTREME, "Deleted note found & synch content selected");
\r
556 Note delNote = conn.getNoteTable().getNote(enNote.getGuid(), true, true, true, true, true);
\r
557 delNote = getNoteContent(delNote);
\r
558 delNote = noteStore.updateNote(authToken, delNote);
\r
559 enNote.setUpdateSequenceNum(delNote.getUpdateSequenceNum());
\r
560 conn.getNoteTable().updateNoteSequence(enNote.getGuid(), enNote.getUpdateSequenceNum());
\r
562 logger.log(logger.EXTREME, "Deleted note found & sync content not selected");
\r
563 int usn = noteStore.deleteNote(authToken, enNote.getGuid());
\r
564 enNote.setUpdateSequenceNum(usn);
\r
565 conn.getNoteTable().updateNoteSequence(enNote.getGuid(), enNote.getUpdateSequenceNum());
\r
567 logger.log(logger.EXTREME, "Resetting deleted dirty flag");
\r
568 conn.getNoteTable().resetDirtyFlag(enNote.getGuid());
\r
569 updateSequenceNumber = enNote.getUpdateSequenceNum();
\r
570 logger.log(logger.EXTREME, "Saving sequence number");
\r
571 conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);
\r
573 } catch (EDAMUserException e) {
\r
574 logger.log(logger.LOW, "*** EDAM User Excepton syncLocalNotes "+e);
\r
575 //status.message.emit("Error sending local note: " +e.getParameter());
\r
576 //logger.log(logger.LOW, e.toString());
\r
578 } catch (EDAMSystemException e) {
\r
579 logger.log(logger.LOW, "*** EDAM System Excepton syncLocalNotes "+e);
\r
580 status.message.emit(tr("Error: ") +e);
\r
581 logger.log(logger.LOW, e.toString());
\r
583 } catch (EDAMNotFoundException e) {
\r
584 logger.log(logger.LOW, "*** EDAM Not Found Excepton syncLocalNotes " +e);
\r
585 //status.message.emit("Error deleting local note: " +e +" - Continuing");
\r
586 //logger.log(logger.LOW, e.toString());
\r
588 } catch (TException e) {
\r
589 logger.log(logger.LOW, "*** EDAM TExcepton syncLocalNotes "+e);
\r
590 status.message.emit(tr("Error sending local note: ") +e);
\r
591 logger.log(logger.LOW, e.toString());
\r
596 // Sync notes with Evernote
\r
597 private void syncLocalNotes() {
\r
598 logger.log(logger.HIGH, "Entering SyncRunner.syncNotes");
\r
599 logger.log(logger.LOW, "Dirty local notes found: " +new Integer(conn.getNoteTable().getDirtyCount()).toString());
\r
600 status.message.emit(tr("Sending local notes."));
\r
602 List<Note> notes = conn.getNoteTable().getDirty();
\r
603 // Sync the local notebooks with Evernote's
\r
604 for (int i=0; i<notes.size() && keepRunning; i++) {
\r
605 syncLocalNote(localNoteStore, notes.get(i), authToken);
\r
607 logger.log(logger.HIGH, "Leaving SyncRunner.syncNotes");
\r
610 // Sync notes with Evernote
\r
611 private void syncLocalNote(Client noteStore, Note enNote, String token) {
\r
612 logger.log(logger.HIGH, "Entering SyncRunner.syncNotes");
\r
613 status.message.emit(tr("Sending local notes."));
\r
615 if (enNote.isActive()) {
\r
617 if (enNote.getUpdateSequenceNum() > 0) {
\r
618 logger.log(logger.EXTREME, "Active dirty note found - non new - " +enNote.getGuid());
\r
619 logger.log(logger.EXTREME, "Fetching note content");
\r
620 enNote = getNoteContent(enNote);
\r
621 logger.log(logger.MEDIUM, "Updating note : "+ enNote.getGuid() +" <title>" +enNote.getTitle()+"</title>");
\r
622 enNote = noteStore.updateNote(token, enNote);
\r
624 logger.log(logger.EXTREME, "Active dirty found - new note " +enNote.getGuid());
\r
625 String oldGuid = enNote.getGuid();
\r
626 logger.log(logger.MEDIUM, "Fetching note content");
\r
627 enNote = getNoteContent(enNote);
\r
628 logger.log(logger.MEDIUM, "Creating note : "+ enNote.getGuid() +" <title>" +enNote.getTitle()+"</title>");
\r
629 enNote = noteStore.createNote(token, enNote);
\r
630 logger.log(logger.MEDIUM, "New note Guid : "+ enNote.getGuid() +" <title>" +enNote.getTitle()+"</title>");
\r
631 noteSignal.guidChanged.emit(oldGuid, enNote.getGuid());
\r
632 conn.getNoteTable().updateNoteGuid(oldGuid, enNote.getGuid());
\r
634 updateSequenceNumber = enNote.getUpdateSequenceNum();
\r
635 logger.log(logger.EXTREME, "Saving note");
\r
636 conn.getNoteTable().updateNoteSequence(enNote.getGuid(), enNote.getUpdateSequenceNum());
\r
637 List<Resource> rl = enNote.getResources();
\r
638 logger.log(logger.EXTREME, "Getting note resources");
\r
639 for (int j=0; j<enNote.getResourcesSize() && keepRunning; j++) {
\r
640 Resource newRes = rl.get(j);
\r
641 Data d = newRes.getData();
\r
643 logger.log(logger.EXTREME, "Calculating resource hash");
\r
644 String hash = byteArrayToHexString(d.getBodyHash());
\r
645 logger.log(logger.EXTREME, "updating resources by hash");
\r
646 String oldGuid = conn.getNoteTable().noteResourceTable.getNoteResourceGuidByHashHex(enNote.getGuid(), hash);
\r
647 conn.getNoteTable().updateNoteResourceGuidbyHash(enNote.getGuid(), newRes.getGuid(), hash);
\r
648 resourceSignal.resourceGuidChanged.emit(enNote.getGuid(), oldGuid, newRes.getGuid());
\r
651 logger.log(logger.EXTREME, "Resetting note dirty flag");
\r
652 conn.getNoteTable().resetDirtyFlag(enNote.getGuid());
\r
653 updateSequenceNumber = enNote.getUpdateSequenceNum();
\r
654 logger.log(logger.EXTREME, "Emitting note sequence number change");
\r
655 conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);
\r
657 } catch (EDAMUserException e) {
\r
658 logger.log(logger.LOW, "*** EDAM User Excepton syncLocalNotes "+e);
\r
659 status.message.emit(tr("Error sending local note: ") +e.getParameter());
\r
660 logger.log(logger.LOW, e.toString());
\r
662 } catch (EDAMSystemException e) {
\r
663 logger.log(logger.LOW, "*** EDAM System Excepton syncLocalNotes "+e);
\r
664 status.message.emit(tr("Error: ") +e);
\r
665 logger.log(logger.LOW, e.toString());
\r
667 } catch (EDAMNotFoundException e) {
\r
668 logger.log(logger.LOW, "*** EDAM Not Found Excepton syncLocalNotes " +e);
\r
669 status.message.emit(tr("Error sending local note: ") +e);
\r
670 logger.log(logger.LOW, e.toString());
\r
672 } catch (TException e) {
\r
673 logger.log(logger.LOW, "*** EDAM TExcepton syncLocalNotes "+e);
\r
674 status.message.emit(tr("Error sending local note: ") +e);
\r
675 logger.log(logger.LOW, e.toString());
\r
679 logger.log(logger.HIGH, "Leaving SyncRunner.syncLocalNote");
\r
683 // Sync Notebooks with Evernote
\r
684 private void syncLocalNotebooks(Client noteStore) {
\r
685 logger.log(logger.HIGH, "Entering SyncRunner.syncLocalNotebooks");
\r
687 status.message.emit(tr("Sending local notebooks."));
\r
688 List<Notebook> remoteList = new ArrayList<Notebook>();
\r
690 logger.log(logger.EXTREME, "Getting remote notebooks to compare with local");
\r
691 remoteList = noteStore.listNotebooks(authToken);
\r
692 } catch (EDAMUserException e1) {
\r
693 logger.log(logger.LOW, "*** EDAM User Excepton syncLocalNotebooks getting remote Notebook List");
\r
694 status.message.emit(tr("Error: ") +e1);
\r
695 logger.log(logger.LOW, e1.toString());
\r
697 } catch (EDAMSystemException e1) {
\r
698 logger.log(logger.LOW, "*** EDAM System Excepton syncLocalNotebooks getting remote Notebook List");
\r
699 status.message.emit(tr("Error: ") +e1);
\r
700 logger.log(logger.LOW, e1.toString());
\r
702 } catch (TException e1) {
\r
703 logger.log(logger.LOW, "*** EDAM Transaction Excepton syncLocalNotebooks getting remote Notebook List");
\r
704 status.message.emit(tr("Error: ") +e1);
\r
705 logger.log(logger.LOW, e1.toString());
\r
708 logger.log(logger.EXTREME, "Getting local dirty notebooks");
\r
709 List<Notebook> notebooks = conn.getNotebookTable().getDirty();
\r
711 // Sync the local notebooks with Evernote's
\r
712 for (int i=0; i<notebooks.size() && keepRunning; i++) {
\r
714 // if (authRefreshNeeded)
\r
715 // if (!refreshConnection())
\r
718 Notebook enNotebook = notebooks.get(i);
\r
720 if (enNotebook.getUpdateSequenceNum() > 0) {
\r
721 logger.log(logger.EXTREME, "Existing notebook is dirty");
\r
722 sequence = noteStore.updateNotebook(authToken, enNotebook);
\r
724 logger.log(logger.EXTREME, "New dirty notebook found");
\r
725 String oldGuid = enNotebook.getGuid();
\r
726 boolean found = false;
\r
728 // Look for a notebook with the same name. If one is found, we don't need
\r
729 // to create another one
\r
730 logger.log(logger.EXTREME, "Looking for matching notebook name");
\r
731 for (int k=0; k<remoteList.size() && !found && keepRunning; k++) {
\r
732 if (remoteList.get(k).getName().equalsIgnoreCase(enNotebook.getName())) {
\r
733 enNotebook = remoteList.get(k);
\r
734 logger.log(logger.EXTREME, "Matching notebook found");
\r
739 enNotebook = noteStore.createNotebook(authToken, enNotebook);
\r
741 logger.log(logger.EXTREME, "Updating notebook in database");
\r
742 conn.getNotebookTable().updateNotebookGuid(oldGuid, enNotebook.getGuid());
\r
743 sequence = enNotebook.getUpdateSequenceNum();
\r
745 logger.log(logger.EXTREME, "Updating notebook sequence in database");
\r
746 conn.getNotebookTable().updateNotebookSequence(enNotebook.getGuid(), sequence);
\r
747 logger.log(logger.EXTREME, "Resetting dirty flag in notebook");
\r
748 conn.getNotebookTable().resetDirtyFlag(enNotebook.getGuid());
\r
749 updateSequenceNumber = sequence;
\r
750 logger.log(logger.EXTREME, "Emitting sequence number to main thread");
\r
751 conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);
\r
752 } catch (EDAMUserException e) {
\r
753 logger.log(logger.LOW, "*** EDAM User Excepton syncLocalNotebooks");
\r
754 logger.log(logger.LOW, e.toString() + ": Stack : " +enNotebook.getStack());
\r
756 } catch (EDAMSystemException e) {
\r
757 logger.log(logger.LOW, "*** EDAM System Excepton syncLocalNotebooks");
\r
758 logger.log(logger.LOW, e.toString());
\r
760 } catch (EDAMNotFoundException e) {
\r
761 logger.log(logger.LOW, "*** EDAM Not Found Excepton syncLocalNotebooks");
\r
762 logger.log(logger.LOW, e.toString());
\r
764 } catch (TException e) {
\r
765 logger.log(logger.LOW, "*** EDAM TExcepton syncLocalNotebooks");
\r
766 logger.log(logger.LOW, e.toString());
\r
770 logger.log(logger.HIGH, "Leaving SyncRunner.syncLocalNotebooks");
\r
773 // Sync Tags with Evernote
\r
774 private void syncLocalTags(Client noteStore) {
\r
775 logger.log(logger.HIGH, "Entering SyncRunner.syncLocalTags");
\r
776 List<Tag> remoteList = new ArrayList<Tag>();
\r
777 status.message.emit(tr("Sending local tags."));
\r
780 logger.log(logger.EXTREME, "Getting remote tags to compare names with the local tags");
\r
781 remoteList = noteStore.listTags(authToken);
\r
782 } catch (EDAMUserException e1) {
\r
783 logger.log(logger.LOW, "*** EDAM User Excepton syncLocalTags getting remote Tag List");
\r
784 status.message.emit(tr("Error: ") +e1);
\r
785 logger.log(logger.LOW, e1.toString());
\r
787 } catch (EDAMSystemException e1) {
\r
788 logger.log(logger.LOW, "*** EDAM System Excepton syncLocalTags getting remote Tag List");
\r
789 status.message.emit(tr("Error: ") +e1);
\r
790 logger.log(logger.LOW, e1.toString());
\r
792 } catch (TException e1) {
\r
793 logger.log(logger.LOW, "*** EDAM Transaction Excepton syncLocalTags getting remote Tag List");
\r
794 status.message.emit(tr("Error: ") +e1);
\r
795 logger.log(logger.LOW, e1.toString());
\r
801 if (badTagSync == null)
\r
802 badTagSync = new HashMap<String,String>();
\r
804 badTagSync.clear();
\r
806 Tag enTag = findNextTag();
\r
808 // This is a hack. Sometimes this function goes flookey and goes into a
\r
809 // perpetual loop. This causes NeverNote to flood Evernote's servers.
\r
810 // This is a safety valve to prevent unlimited loops.
\r
811 int maxCount = conn.getTagTable().getDirty().size()+10;
\r
814 while(enTag!=null && loopCount < maxCount) {
\r
816 // if (authRefreshNeeded)
\r
817 // if (!refreshConnection())
\r
821 if (enTag.getUpdateSequenceNum() > 0) {
\r
822 logger.log(logger.EXTREME, "Updating tag");
\r
823 sequence = noteStore.updateTag(authToken, enTag);
\r
826 // Look for a tag with the same name. If one is found, we don't need
\r
827 // to create another one
\r
828 logger.log(logger.EXTREME, "New tag. Comparing with remote names");
\r
829 boolean found = false;
\r
830 String oldGuid = enTag.getGuid();
\r
831 for (int k=0; k<remoteList.size() && !found && keepRunning; k++) {
\r
832 if (remoteList.get(k).getName().equalsIgnoreCase(enTag.getName())) {
\r
833 conn.getTagTable().updateTagGuid(enTag.getGuid(), remoteList.get(k).getGuid());
\r
834 enTag = remoteList.get(k);
\r
835 logger.log(logger.EXTREME, "Matching tag name found");
\r
840 enTag = noteStore.createTag(authToken, enTag);
\r
842 enTag.setUpdateSequenceNum(noteStore.updateTag(authToken,enTag));
\r
843 sequence = enTag.getUpdateSequenceNum();
\r
844 if (!oldGuid.equals(enTag.getGuid())) {
\r
845 logger.log(logger.EXTREME, "Updating tag guid");
\r
846 conn.getTagTable().updateTagGuid(oldGuid, enTag.getGuid());
\r
849 logger.log(logger.EXTREME, "Updating tag sequence number");
\r
850 conn.getTagTable().updateTagSequence(enTag.getGuid(), sequence);
\r
851 logger.log(logger.EXTREME, "Resetting tag dirty flag");
\r
852 conn.getTagTable().resetDirtyFlag(enTag.getGuid());
\r
853 logger.log(logger.EXTREME, "Emitting sequence number to the main thread.");
\r
854 updateSequenceNumber = sequence;
\r
855 conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);
\r
856 } catch (EDAMUserException e) {
\r
857 logger.log(logger.LOW, "*** EDAM User Excepton syncLocalTags: " +enTag.getName());
\r
858 logger.log(logger.LOW, e.toString());
\r
859 badTagSync.put(enTag.getGuid(),null);
\r
861 } catch (EDAMSystemException e) {
\r
862 logger.log(logger.LOW, "** EDAM System Excepton syncLocalTags: " +enTag.getName());
\r
863 logger.log(logger.LOW, e.toString());
\r
864 badTagSync.put(enTag.getGuid(),null);
\r
866 } catch (EDAMNotFoundException e) {
\r
867 logger.log(logger.LOW, "*** EDAM Not Found Excepton syncLocalTags: " +enTag.getName());
\r
868 logger.log(logger.LOW, e.toString());
\r
869 badTagSync.put(enTag.getGuid(),null);
\r
871 } catch (TException e) {
\r
872 logger.log(logger.LOW, "*** EDAM TExcepton syncLocalTags: " +enTag.getName());
\r
873 logger.log(logger.LOW, e.toString());
\r
874 badTagSync.put(enTag.getGuid(),null);
\r
878 // Find the next tag
\r
879 logger.log(logger.EXTREME, "Finding next tag");
\r
880 enTag = findNextTag();
\r
882 logger.log(logger.HIGH, "Leaving SyncRunner.syncLocalTags");
\r
884 private void syncLocalLinkedNotebooks(Client noteStore) {
\r
885 logger.log(logger.HIGH, "Entering SyncRunner.syncLocalLinkedNotebooks");
\r
887 List<String> list = conn.getLinkedNotebookTable().getDirtyGuids();
\r
888 for (int i=0; i<list.size(); i++) {
\r
889 LinkedNotebook book = conn.getLinkedNotebookTable().getNotebook(list.get(i));
\r
891 noteStore.updateLinkedNotebook(authToken, book);
\r
892 } catch (EDAMUserException e) {
\r
893 logger.log(logger.LOW, "*** EDAM User Excepton syncLocalLinkedNotebooks");
\r
894 status.message.emit(tr("Error: ") +e);
\r
895 logger.log(logger.LOW, e.toString());
\r
897 e.printStackTrace();
\r
898 } catch (EDAMNotFoundException e) {
\r
899 logger.log(logger.LOW, "*** EDAM Not Found Excepton syncLocalLinkedNotebooks");
\r
900 status.message.emit(tr("Error: ") +e);
\r
901 logger.log(logger.LOW, e.toString());
\r
903 e.printStackTrace();
\r
904 } catch (EDAMSystemException e) {
\r
905 logger.log(logger.LOW, "*** EDAM System Excepton syncLocalLinkedNotebooks");
\r
906 status.message.emit(tr("Error: ") +e);
\r
907 logger.log(logger.LOW, e.toString());
\r
909 e.printStackTrace();
\r
910 } catch (TException e) {
\r
911 logger.log(logger.LOW, "*** EDAM TExcepton syncLocalLinkedNotebooks");
\r
912 status.message.emit(tr("Error: ") +e);
\r
913 logger.log(logger.LOW, e.toString());
\r
915 e.printStackTrace();
\r
918 logger.log(logger.HIGH, "Leaving SyncRunner.syncLocalLinkedNotebooks");
\r
920 // Sync Saved Searches with Evernote
\r
921 private void syncLocalSavedSearches(Client noteStore) {
\r
922 logger.log(logger.HIGH, "Entering SyncRunner.syncLocalSavedSearches");
\r
923 List<SavedSearch> remoteList = new ArrayList<SavedSearch>();
\r
924 status.message.emit(tr("Sending saved searches."));
\r
926 logger.log(logger.EXTREME, "Getting saved searches to compare with local");
\r
928 remoteList = noteStore.listSearches(authToken);
\r
929 } catch (EDAMUserException e1) {
\r
930 logger.log(logger.LOW, "*** EDAM User Excepton syncLocalTags getting remote saved search List");
\r
931 status.message.emit(tr("Error: ") +e1);
\r
932 logger.log(logger.LOW, e1.toString());
\r
934 } catch (EDAMSystemException e1) {
\r
935 logger.log(logger.LOW, "*** EDAM System Excepton syncLocalTags getting remote saved search List");
\r
936 status.message.emit(tr("Error: ") +e1);
\r
937 logger.log(logger.LOW, e1.toString());
\r
939 } catch (TException e1) {
\r
940 logger.log(logger.LOW, "*** EDAM Transaction Excepton syncLocalTags getting remote saved search List");
\r
941 status.message.emit(tr("Error: ") +e1);
\r
942 logger.log(logger.LOW, e1.toString());
\r
946 List<SavedSearch> searches = conn.getSavedSearchTable().getDirty();
\r
948 // Sync the local notebooks with Evernote's
\r
949 logger.log(logger.EXTREME, "Beginning to send saved searches");
\r
950 for (int i=0; i<searches.size() && keepRunning; i++) {
\r
952 // if (authRefreshNeeded)
\r
953 // if (!refreshConnection())
\r
956 SavedSearch enSearch = searches.get(i);
\r
958 if (enSearch.getUpdateSequenceNum() > 0)
\r
959 sequence = noteStore.updateSearch(authToken, enSearch);
\r
961 logger.log(logger.EXTREME, "New saved search found.");
\r
962 // Look for a tag with the same name. If one is found, we don't need
\r
963 // to create another one
\r
964 boolean found = false;
\r
965 logger.log(logger.EXTREME, "Matching remote saved search names with local");
\r
966 for (int k=0; k<remoteList.size() && !found && keepRunning; k++) {
\r
967 if (remoteList.get(k).getName().equalsIgnoreCase(enSearch.getName())) {
\r
968 enSearch = remoteList.get(k);
\r
970 logger.log(logger.EXTREME, "Matching saved search found");
\r
971 sequence = enSearch.getUpdateSequenceNum();
\r
975 String oldGuid = enSearch.getGuid();
\r
977 enSearch = noteStore.createSearch(authToken, enSearch);
\r
978 sequence = enSearch.getUpdateSequenceNum();
\r
979 logger.log(logger.EXTREME, "Updating tag guid in local database");
\r
980 conn.getSavedSearchTable().updateSavedSearchGuid(oldGuid, enSearch.getGuid());
\r
982 logger.log(logger.EXTREME, "Updating tag sequence in local database");
\r
983 conn.getSavedSearchTable().updateSavedSearchSequence(enSearch.getGuid(), sequence);
\r
984 logger.log(logger.EXTREME, "Resetting tag dirty flag");
\r
985 conn.getSavedSearchTable().resetDirtyFlag(enSearch.getGuid());
\r
986 logger.log(logger.EXTREME, "Emitting sequence number to the main thread.");
\r
987 updateSequenceNumber = sequence;
\r
988 conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);
\r
989 } catch (EDAMUserException e) {
\r
990 logger.log(logger.LOW, "*** EDAM User Excepton syncLocalTags");
\r
991 logger.log(logger.LOW, e.toString());
\r
993 } catch (EDAMSystemException e) {
\r
994 logger.log(logger.LOW, "** EDAM System Excepton syncLocalTags");
\r
995 logger.log(logger.LOW, e.toString());
\r
997 } catch (EDAMNotFoundException e) {
\r
998 logger.log(logger.LOW, "*** EDAM Not Found Excepton syncLocalTags");
\r
999 logger.log(logger.LOW, e.toString());
\r
1001 } catch (TException e) {
\r
1002 logger.log(logger.LOW, "*** EDAM TExcepton syncLocalTags");
\r
1003 logger.log(logger.LOW, e.toString());
\r
1008 logger.log(logger.HIGH, "Entering SyncRunner.syncLocalSavedSearches");
\r
1011 // Sync evernote changes with local database
\r
1012 private void syncRemoteToLocal(Client noteStore) {
\r
1013 logger.log(logger.HIGH, "Entering SyncRunner.syncRemoteToLocal");
\r
1015 List<Note> dirtyNotes = conn.getNoteTable().getDirty();
\r
1016 dirtyNoteGuids = new ArrayList<String>();
\r
1017 for (int i=0; i<dirtyNotes.size() && keepRunning; i++) {
\r
1018 dirtyNoteGuids.add(dirtyNotes.get(i).getGuid());
\r
1021 int chunkSize = 10;
\r
1022 SyncChunk chunk = null;
\r
1023 boolean fullSync = false;
\r
1024 boolean more = true;
\r
1026 if (updateSequenceNumber == 0)
\r
1029 status.message.emit(tr("Downloading 0% complete."));
\r
1031 while(more && keepRunning) {
\r
1033 // if (authRefreshNeeded)
\r
1034 // if (!refreshConnection())
\r
1037 int sequence = updateSequenceNumber;
\r
1039 // conn.beginTransaction();
\r
1040 logger.log(logger.EXTREME, "Getting chunk from Evernote");
\r
1041 chunk = noteStore.getSyncChunk(authToken, sequence, chunkSize, fullSync);
\r
1042 logger.log(logger.LOW, "Chunk High Sequence: " +chunk.getChunkHighUSN());
\r
1043 } catch (EDAMUserException e) {
\r
1045 e.printStackTrace();
\r
1046 status.message.emit(e.getMessage());
\r
1047 } catch (EDAMSystemException e) {
\r
1049 e.printStackTrace();
\r
1050 status.message.emit(e.getMessage());
\r
1051 } catch (TException e) {
\r
1053 e.printStackTrace();
\r
1054 status.message.emit(e.getMessage());
\r
1056 if (error || chunk == null)
\r
1061 syncRemoteTags(chunk.getTags());
\r
1062 syncRemoteSavedSearches(chunk.getSearches());
\r
1063 syncRemoteNotebooks(chunk.getNotebooks());
\r
1064 syncRemoteNotes(noteStore, chunk.getNotes(), fullSync, authToken);
\r
1065 syncRemoteResources(noteStore, chunk.getResources());
\r
1066 syncRemoteLinkedNotebooks(chunk.getLinkedNotebooks());
\r
1068 // Signal about any updated notes to invalidate the cache
\r
1069 for (int i=0; i<chunk.getNotesSize(); i++)
\r
1070 noteSignal.noteChanged.emit(chunk.getNotes().get(i).getGuid(), null);
\r
1071 syncExpungedNotes(chunk);
\r
1074 // Check for more notes
\r
1075 if (chunk.getChunkHighUSN() <= updateSequenceNumber)
\r
1079 logger.log(logger.EXTREME, "More notes? " +more);
\r
1082 // Save the chunk sequence number
\r
1083 if (!error && chunk.getChunkHighUSN() > 0 && keepRunning) {
\r
1084 logger.log(logger.EXTREME, "emitting sequence number to main thread");
\r
1085 updateSequenceNumber = chunk.getChunkHighUSN();
\r
1086 conn.getSyncTable().setLastSequenceDate(chunk.getCurrentTime());
\r
1087 conn.getSyncTable().setUpdateSequenceNumber(updateSequenceNumber);
\r
1088 // conn.commitTransaction();
\r
1093 long pct = chunk.getChunkHighUSN() * 100;
\r
1094 conn.getSyncTable().setLastSequenceDate(chunk.getCurrentTime());
\r
1095 pct = pct/evernoteUpdateCount;
\r
1096 status.message.emit(tr("Downloading ") +new Long(pct).toString()+tr("% complete."));
\r
1098 // conn.commitTransaction();
\r
1100 logger.log(logger.HIGH, "Leaving SyncRunner.syncRemoteToLocal");
\r
1102 // Sync expunged notes
\r
1103 private void syncExpungedNotes(SyncChunk chunk) {
\r
1104 // Do the local deletes
\r
1105 logger.log(logger.EXTREME, "Doing local deletes");
\r
1106 List<String> guid = chunk.getExpungedNotes();
\r
1107 if (guid != null) {
\r
1108 for (int i=0; i<guid.size() && keepRunning; i++) {
\r
1109 String notebookGuid = "";
\r
1110 Note localNote = conn.getNoteTable().getNote(guid.get(i), false, false, false, false, false);
\r
1111 if (localNote != null) {
\r
1112 conn.getNoteTable().updateNoteSequence(guid.get(i), 0);
\r
1113 notebookGuid = localNote.getNotebookGuid();
\r
1115 // If the note is in a local notebook (which means we moved it) or if the
\r
1116 // note returned is null (which means it is already deleted or flagged expunged)
\r
1118 if (!conn.getNotebookTable().isNotebookLocal(notebookGuid) || localNote == null) {
\r
1119 logger.log(logger.EXTREME, "Expunging local note from database");
\r
1120 conn.getNoteTable().expungeNote(guid.get(i), true, false);
\r
1124 guid = chunk.getExpungedNotebooks();
\r
1126 for (int i=0; i<guid.size() && keepRunning; i++) {
\r
1127 logger.log(logger.EXTREME, "Expunging local notebook from database");
\r
1128 conn.getNotebookTable().expungeNotebook(guid.get(i), false);
\r
1130 guid = chunk.getExpungedTags();
\r
1132 for (int i=0; i<guid.size() && keepRunning; i++) {
\r
1133 logger.log(logger.EXTREME, "Expunging tags from local database");
\r
1134 conn.getTagTable().expungeTag(guid.get(i), false);
\r
1136 guid = chunk.getExpungedSearches();
\r
1137 if (guid != null)
\r
1138 for (int i=0; i<guid.size() && keepRunning; i++) {
\r
1139 logger.log(logger.EXTREME, "Expunging saved search from local database");
\r
1140 conn.getSavedSearchTable().expungeSavedSearch(guid.get(i), false);
\r
1142 guid = chunk.getExpungedLinkedNotebooks();
\r
1143 if (guid != null)
\r
1144 for (int i=0; i<guid.size() && keepRunning; i++) {
\r
1145 logger.log(logger.EXTREME, "Expunging linked notebook from local database");
\r
1146 conn.getLinkedNotebookTable().expungeNotebook(guid.get(i), false);
\r
1150 // Sync remote tags
\r
1151 private void syncRemoteTags(List<Tag> tags) {
\r
1152 logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteTags");
\r
1153 if (tags != null) {
\r
1154 for (int i=0; i<tags.size() && keepRunning; i++) {
\r
1156 oldGuid = conn.getTagTable().findTagByName(tags.get(i).getName());
\r
1157 if (oldGuid != null && !tags.get(i).getGuid().equalsIgnoreCase(oldGuid))
\r
1158 conn.getTagTable().updateTagGuid(oldGuid, tags.get(i).getGuid());
\r
1159 conn.getTagTable().syncTag(tags.get(i), false);
\r
1162 logger.log(logger.EXTREME, "Leaving SyncRunner.syncRemoteTags");
\r
1164 // Sync remote saved searches
\r
1165 private void syncRemoteSavedSearches(List<SavedSearch> searches) {
\r
1166 logger.log(logger.EXTREME, "Entering SyncRunner.syncSavedSearches");
\r
1167 if (searches != null) {
\r
1168 for (int i=0; i<searches.size() && keepRunning; i++) {
\r
1170 oldGuid = conn.getSavedSearchTable().findSavedSearchByName(searches.get(i).getName());
\r
1171 if (oldGuid != null && !searches.get(i).getGuid().equalsIgnoreCase(oldGuid))
\r
1172 conn.getSavedSearchTable().updateSavedSearchGuid(oldGuid, searches.get(i).getGuid());
\r
1173 conn.getSavedSearchTable().syncSavedSearch(searches.get(i), false);
\r
1176 logger.log(logger.EXTREME, "Leaving SyncRunner.syncSavedSearches");
\r
1178 // Sync remote linked notebooks
\r
1179 private void syncRemoteLinkedNotebooks(List<LinkedNotebook> books) {
\r
1180 logger.log(logger.EXTREME, "Entering SyncRunner.syncLinkedNotebooks");
\r
1181 if (books != null) {
\r
1182 for (int i=0; i<books.size() && keepRunning; i++) {
\r
1183 conn.getLinkedNotebookTable().updateNotebook(books.get(i), false);
\r
1186 logger.log(logger.EXTREME, "Leaving SyncRunner.syncLinkedNotebooks");
\r
1188 // Sync remote Notebooks 2
\r
1189 private void syncRemoteNotebooks(List<Notebook> notebooks) {
\r
1190 logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteNotebooks");
\r
1191 if (notebooks != null) {
\r
1192 for (int i=0; i<notebooks.size() && keepRunning; i++) {
\r
1194 oldGuid = conn.getNotebookTable().findNotebookByName(notebooks.get(i).getName());
\r
1195 if (oldGuid != null && !conn.getNotebookTable().isNotebookLocal(oldGuid) && !notebooks.get(i).getGuid().equalsIgnoreCase(oldGuid))
\r
1196 conn.getNotebookTable().updateNotebookGuid(oldGuid, notebooks.get(i).getGuid());
\r
1197 conn.getNotebookTable().syncNotebook(notebooks.get(i), false);
\r
1199 // Synchronize shared notebook information
\r
1200 // if (notebooks.get(i).getSharedNotebookIdsSize() > 0) {
\r
1201 // conn.getSharedNotebookTable().expungeNotebookByGuid(notebooks.get(i).getGuid(), false);
\r
1202 // for (int j=0; j<notebooks.get(i).getSharedNotebookIdsSize(); j++) {
\r
1203 // syncRemoteSharedNotebook(notebooks.get(i).getGuid(), notebooks.get(i).getSharedNotebookIds().get(j), authToken);
\r
1208 logger.log(logger.EXTREME, "Leaving SyncRunner.syncRemoteNotebooks");
\r
1210 // Sync remote shared notebook
\r
1211 // private void syncRemoteSharedNotebook(String guid, Long id, String token) {
\r
1212 // List<SharedNotebook> books = noteStore.getSharedNotebookByAuth(authToken);
\r
1214 // Sync remote Resources
\r
1215 private void syncRemoteResources(Client noteStore, List<Resource> resource) {
\r
1216 logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteResources");
\r
1217 if (resource != null) {
\r
1218 for (int i=0; i<resource.size() && keepRunning; i++) {
\r
1219 syncRemoteResource(noteStore, resource.get(i), authToken);
\r
1222 logger.log(logger.EXTREME, "Leaving SyncRunner.syncRemoteResources");
\r
1224 // Sync remote resource
\r
1225 private void syncRemoteResource(Client noteStore, Resource resource, String authToken) {
\r
1226 // This is how the logic for this works.
\r
1227 // 1.) If the resource is not in the local database, we add it.
\r
1228 // 2.) If a copy of the resource is in the local database and the note isn't dirty, we update the local copy
\r
1229 // 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
1230 // is a conflict. The note conflict should get a copy of the resource at that time.
\r
1232 Note n = conn.getNoteTable().getNote(resource.getNoteGuid(), false, false, false, false, false);
\r
1234 logger.log(logger.HIGH, "Resource for note " +n.getGuid() +" : " +n.getTitle());
\r
1236 boolean saveNeeded = false;
\r
1237 /* #1 */ Resource r = getEvernoteResource(noteStore, resource.getGuid(), true,true,true, authToken);
\r
1238 Resource l = conn.getNoteTable().noteResourceTable.getNoteResource(r.getGuid(), false);
\r
1240 logger.log(logger.HIGH, "Local resource not found");
\r
1241 saveNeeded = true;
\r
1243 /* #2 */ boolean isNoteDirty = conn.getNoteTable().isNoteDirty(r.getNoteGuid());
\r
1244 if (!isNoteDirty) {
\r
1245 logger.log(logger.HIGH, "Local resource found, but is not dirty");
\r
1246 saveNeeded = true;
\r
1248 /* #3 */ String remoteHash = "";
\r
1249 if (r != null && r.getData() != null && r.getData().getBodyHash() != null)
\r
1250 remoteHash = byteArrayToHexString(r.getData().getBodyHash());
\r
1251 String localHash = "";
\r
1252 if (l != null && l.getData() != null && l.getData().getBodyHash() != null)
\r
1253 remoteHash = byteArrayToHexString(l.getData().getBodyHash());
\r
1255 if (localHash.equalsIgnoreCase(remoteHash))
\r
1256 saveNeeded = true;
\r
1260 logger.log(logger.HIGH, "Resource save needed: " +saveNeeded);
\r
1262 conn.getNoteTable().noteResourceTable.updateNoteResource(r, false);
\r
1263 if (r.getMime().equalsIgnoreCase("application/vnd.evernote.ink"))
\r
1264 downloadInkNoteImage(r.getGuid(), authToken);
\r
1268 // Sync remote notes
\r
1269 private void syncRemoteNotes(Client noteStore, List<Note> note, boolean fullSync, String token) {
\r
1271 if (note != null) {
\r
1273 logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteNotes");
\r
1274 logger.log(logger.LOW, "Local Dirty Notes: ");
\r
1275 logger.log(logger.LOW, "Remote Dirty Notes:");
\r
1276 for (int i=0; i<note.size();i++) {
\r
1277 logger.log(logger.LOW, i +" : " +note.get(i).getGuid() + " : " +note.get(i).getTitle() );
\r
1279 logger.log(logger.LOW, "---");
\r
1281 for (int i=0; i<note.size() && keepRunning; i++) {
\r
1282 Note n = getEvernoteNote(noteStore, note.get(i).getGuid(), true, fullSync, true,true, token);
\r
1283 syncRemoteNote(n, fullSync, token);
\r
1286 logger.log(logger.EXTREME, "Leaving SyncRunner.syncRemoteNotes");
\r
1288 private void syncRemoteNote(Note n, boolean fullSync, String token) {
\r
1291 // Basically, this is how the sync logic for a note works.
\r
1292 // If the remote note has changed and the local has not, we
\r
1293 // accept the change.
\r
1294 // If both the local & remote have changed but the sequence
\r
1295 // numbers are the same, we don't accept the change. This
\r
1296 // seems to happen when attachments are indexed by the server.
\r
1297 // If both the local & remote have changed and the sequence numbers
\r
1298 // are different we move the local copy to a local notebook (making sure
\r
1299 // to copy all resources) and we accept the new one.
\r
1300 boolean conflictingNote = true;
\r
1301 logger.log(logger.EXTREME, "Checking for duplicate note " +n.getGuid() +" : " +n.getTitle());
\r
1302 if (dirtyNoteGuids != null && dirtyNoteGuids.contains(n.getGuid())) {
\r
1303 logger.log(logger.EXTREME, "Conflict check beginning");
\r
1304 conflictingNote = checkForConflict(n);
\r
1305 logger.log(logger.EXTREME, "Conflict check results " +conflictingNote);
\r
1306 if (conflictingNote)
\r
1307 moveConflictingNote(n.getGuid());
\r
1309 boolean ignoreNote = false;
\r
1310 if (ignoreNotebooks.contains(n.getNotebookGuid()))
\r
1311 ignoreNote = true;
\r
1312 for (int i=0; i<n.getTagGuidsSize(); i++) {
\r
1313 if (ignoreTags.contains(n.getTagGuids().get(i))) {
\r
1314 ignoreNote = true;
\r
1315 i=n.getTagGuidsSize();
\r
1319 if ((conflictingNote || fullSync) && !ignoreNote) {
\r
1320 logger.log(logger.EXTREME, "Saving Note");
\r
1321 conn.getNoteTable().syncNote(n);
\r
1322 // The following was commented out because it caused a race condition on the database where resources
\r
1323 // may be lost. We do the same thing elsewhere;.
\r
1324 // noteSignal.noteChanged.emit(n.getGuid(), null); // Signal to ivalidate note cache
\r
1325 noteSignal.noteDownloaded.emit(n, true); // Signal to add note to index
\r
1326 logger.log(logger.EXTREME, "Note Saved");
\r
1327 if (fullSync && n.getResources() != null) {
\r
1328 for (int q=0; q<n.getResources().size() && keepRunning; q++) {
\r
1329 logger.log(logger.EXTREME, "Getting note resources.");
\r
1330 conn.getNoteTable().noteResourceTable.updateNoteResource(n.getResources().get(q), false);
\r
1331 if (n.getResources().get(q).getMime().equalsIgnoreCase("application/vnd.evernote.ink"))
\r
1332 downloadInkNoteImage(n.getResources().get(q).getGuid(), token);
\r
1338 private Note getEvernoteNote(Client noteStore, String guid, boolean withContent, boolean withResourceData, boolean withResourceRecognition, boolean withResourceAlternateData, String token) {
\r
1341 logger.log(logger.EXTREME, "Retrieving note " +guid);
\r
1342 n = noteStore.getNote(token, guid, withContent, withResourceData, withResourceRecognition, withResourceAlternateData);
\r
1343 logger.log(logger.EXTREME, "Note " +guid +" has been retrieved.");
\r
1344 } catch (EDAMUserException e) {
\r
1345 logger.log(logger.LOW, "*** EDAM User Excepton getEvernoteNote");
\r
1346 logger.log(logger.LOW, e.toString());
\r
1348 e.printStackTrace();
\r
1349 } catch (EDAMSystemException e) {
\r
1350 logger.log(logger.LOW, "*** EDAM System Excepton getEvernoteNote");
\r
1351 logger.log(logger.LOW, e.toString());
\r
1353 e.printStackTrace();
\r
1354 } catch (EDAMNotFoundException e) {
\r
1355 logger.log(logger.LOW, "*** EDAM Not Found Excepton getEvernoteNote");
\r
1356 logger.log(logger.LOW, e.toString());
\r
1358 e.printStackTrace();
\r
1359 } catch (TException e) {
\r
1360 logger.log(logger.LOW, "*** EDAM TExcepton getEvernoteNote");
\r
1361 logger.log(logger.LOW, e.toString());
\r
1363 e.printStackTrace();
\r
1367 private Resource getEvernoteResource(Client noteStore, String guid, boolean withData, boolean withRecognition, boolean withAttributes, String token) {
\r
1368 Resource n = null;
\r
1370 logger.log(logger.EXTREME, "Retrieving resource " +guid);
\r
1371 n = noteStore.getResource(token, guid, withData, withRecognition, withAttributes, withAttributes);
\r
1372 logger.log(logger.EXTREME, "Resource " +guid +" has been retrieved.");
\r
1373 } catch (EDAMUserException e) {
\r
1374 logger.log(logger.LOW, "*** EDAM User Excepton getEvernoteNote");
\r
1375 logger.log(logger.LOW, e.toString());
\r
1377 e.printStackTrace();
\r
1378 } catch (EDAMSystemException e) {
\r
1379 logger.log(logger.LOW, "*** EDAM System Excepton getEvernoteNote");
\r
1380 logger.log(logger.LOW, e.toString());
\r
1382 e.printStackTrace();
\r
1383 } catch (EDAMNotFoundException e) {
\r
1384 logger.log(logger.LOW, "*** EDAM Not Found Excepton getEvernoteNote");
\r
1385 logger.log(logger.LOW, e.toString());
\r
1387 e.printStackTrace();
\r
1388 } catch (TException e) {
\r
1389 logger.log(logger.LOW, "*** EDAM TExcepton getEvernoteNote");
\r
1390 logger.log(logger.LOW, e.toString());
\r
1392 e.printStackTrace();
\r
1398 private boolean checkForConflict(Note n) {
\r
1399 logger.log(logger.EXTREME, "Checking note sequence number " +n.getGuid());
\r
1400 Note oldNote = conn.getNoteTable().getNote(n.getGuid(), false, false, false, false, false);
\r
1401 logger.log(logger.EXTREME, "Local/Remote sequence numbers: " +oldNote.getUpdateSequenceNum()+"/"+n.getUpdateSequenceNum());
\r
1402 logger.log(logger.LOW, "Remote Note Title:" +n.getTitle());
\r
1403 logger.log(logger.LOW, "Local Note Title:" +oldNote.getTitle());
\r
1404 if (oldNote.getUpdateSequenceNum() == n.getUpdateSequenceNum()) {
\r
1407 boolean oldIsDirty = conn.getNoteTable().isNoteDirty(n.getGuid());
\r
1413 private void moveConflictingNote(String guid) {
\r
1414 logger.log(logger.EXTREME, "Conflicting change found for note " +guid);
\r
1415 List<Notebook> books = conn.getNotebookTable().getAllLocal();
\r
1416 String notebookGuid = null;
\r
1417 for (int i=0; i<books.size() && keepRunning; i++) {
\r
1418 if (books.get(i).getName().equalsIgnoreCase("Conflicting Changes (local)") ||
\r
1419 books.get(i).getName().equalsIgnoreCase("Conflicting Changes")) {
\r
1420 notebookGuid = books.get(i).getGuid();
\r
1425 if (notebookGuid == null) {
\r
1426 logger.log(logger.EXTREME, "Building conflicting change notebook " +guid);
\r
1427 Calendar currentTime = new GregorianCalendar();
\r
1428 Long l = new Long(currentTime.getTimeInMillis());
\r
1429 long prevTime = l;
\r
1430 while (prevTime==l) {
\r
1431 currentTime = new GregorianCalendar();
\r
1432 l=currentTime.getTimeInMillis();
\r
1434 String randint = new String(Long.toString(l));
\r
1436 Notebook newBook = new Notebook();
\r
1437 newBook.setUpdateSequenceNum(0);
\r
1438 newBook.setGuid(randint);
\r
1439 newBook.setName("Conflicting Changes");
\r
1440 newBook.setServiceCreated(new Date().getTime());
\r
1441 newBook.setServiceUpdated(new Date().getTime());
\r
1442 newBook.setDefaultNotebook(false);
\r
1443 newBook.setPublished(false);
\r
1445 conn.getNotebookTable().addNotebook(newBook, false, true);
\r
1446 notebookSignal.listChanged.emit();
\r
1447 notebookGuid = newBook.getGuid();
\r
1448 refreshNeeded = true;
\r
1451 // Now that we have a good notebook guid, we need to move the conflicting note
\r
1452 // to the local notebook
\r
1453 logger.log(logger.EXTREME, "Moving conflicting note " +guid);
\r
1454 Calendar currentTime = new GregorianCalendar();
\r
1455 Long l = new Long(currentTime.getTimeInMillis());
\r
1456 long prevTime = l;
\r
1457 while (prevTime==l) {
\r
1458 currentTime = new GregorianCalendar();
\r
1459 l = currentTime.getTimeInMillis();
\r
1461 String newGuid = new String(Long.toString(l));
\r
1463 Note oldNote = conn.getNoteTable().getNote(guid, true, true, false, false, false);
\r
1464 for (int i=0; i<oldNote.getResources().size() && keepRunning; i++) {
\r
1465 l = new Long(currentTime.getTimeInMillis());
\r
1466 String newResG = new String(Long.toString(l));
\r
1467 String oldResG = oldNote.getResources().get(i).getGuid();
\r
1468 conn.getNoteTable().noteResourceTable.resetUpdateSequenceNumber(oldResG, true);
\r
1469 conn.getNoteTable().noteResourceTable.updateNoteResourceGuid(oldResG, newResG, true);
\r
1472 conn.getNoteTable().resetNoteSequence(guid);
\r
1473 conn.getNoteTable().updateNoteGuid(guid, newGuid);
\r
1474 conn.getNoteTable().updateNoteNotebook(newGuid, notebookGuid, true);
\r
1476 noteSignal.notebookChanged.emit(newGuid, notebookGuid);
\r
1477 refreshNeeded = true;
\r
1478 noteSignal.guidChanged.emit(guid,newGuid);
\r
1484 //******************************************************
\r
1485 //******************************************************
\r
1486 //** Utility Functions
\r
1487 //******************************************************
\r
1488 //******************************************************
\r
1489 // Convert a byte array to a hex string
\r
1490 private static String byteArrayToHexString(byte data[]) {
\r
1491 StringBuffer buf = new StringBuffer();
\r
1492 for (byte element : data) {
\r
1493 int halfbyte = (element >>> 4) & 0x0F;
\r
1494 int two_halfs = 0;
\r
1496 if ((0 <= halfbyte) && (halfbyte <= 9))
\r
1497 buf.append((char) ('0' + halfbyte));
\r
1499 buf.append((char) ('a' + (halfbyte - 10)));
\r
1500 halfbyte = element & 0x0F;
\r
1501 } while(two_halfs++ < 1);
\r
1503 return buf.toString();
\r
1508 //*******************************************************
\r
1509 //* Find dirty tags, which do not have newly created parents
\r
1510 //*******************************************************
\r
1511 private Tag findNextTag() {
\r
1512 logger.log(logger.HIGH, "Entering SyncRunner.findNextTag");
\r
1513 Tag nextTag = null;
\r
1514 List<Tag> tags = conn.getTagTable().getDirty();
\r
1516 // Find the parent. If the parent has a sequence > 0 then it is a good
\r
1518 for (int i=0; i<tags.size() && keepRunning; i++) {
\r
1519 if (!badTagSync.containsKey(tags.get(i).getGuid())) {
\r
1520 if (tags.get(i).getParentGuid() == null) {
\r
1521 logger.log(logger.HIGH, "Leaving SyncRunner.findNextTag - tag found without parent");
\r
1522 return tags.get(i);
\r
1524 Tag parentTag = conn.getTagTable().getTag(tags.get(i).getParentGuid());
\r
1525 if (parentTag.getUpdateSequenceNum() > 0) {
\r
1526 logger.log(logger.HIGH, "Leaving SyncRunner.findNextTag - tag found");
\r
1527 return tags.get(i);
\r
1532 logger.log(logger.HIGH, "Leaving SyncRunner.findNextTag - no tags returned");
\r
1537 // Connect to Evernote
\r
1538 public boolean enConnect() {
\r
1540 userStoreTrans = new THttpClient(userStoreUrl);
\r
1541 userStoreTrans.setCustomHeader("User-Agent", userAgent);
\r
1542 } catch (TTransportException e) {
\r
1543 QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, "Transport Excepton", e.getLocalizedMessage());
\r
1545 e.printStackTrace();
\r
1547 userStoreProt = new TBinaryProtocol(userStoreTrans);
\r
1548 userStore = new UserStore.Client(userStoreProt, userStoreProt);
\r
1549 syncSignal.saveUserStore.emit(userStore);
\r
1551 //authResult = userStore.authenticate(username, password, consumerKey, consumerSecret);
\r
1552 user = userStore.getUser(authToken);
\r
1553 } catch (EDAMUserException e) {
\r
1554 QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, "Error", "Invalid Authorization");
\r
1556 isConnected = false;
\r
1558 } catch (EDAMSystemException e) {
\r
1559 QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, "EDAM System Excepton", e.getLocalizedMessage());
\r
1561 e.printStackTrace();
\r
1562 isConnected = false;
\r
1563 } catch (TException e) {
\r
1564 QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, "Transport Excepton", e.getLocalizedMessage());
\r
1566 e.printStackTrace();
\r
1567 isConnected = false;
\r
1570 boolean versionOk = false;
\r
1572 versionOk = userStore.checkVersion("NixNote",
\r
1573 com.evernote.edam.userstore.Constants.EDAM_VERSION_MAJOR,
\r
1574 com.evernote.edam.userstore.Constants.EDAM_VERSION_MINOR);
\r
1575 } catch (TException e) {
\r
1576 e.printStackTrace();
\r
1577 isConnected = false;
\r
1579 if (!versionOk) {
\r
1580 System.err.println("Incomatible EDAM client protocol version");
\r
1581 isConnected = false;
\r
1583 //if (authResult != null) {
\r
1584 //user = authResult.getUser();
\r
1585 //authToken = authResult.getAuthenticationToken();
\r
1586 if (user == null || noteStoreUrlBase == null) {
\r
1587 logger.log(logger.LOW, "Error retrieving user information. Aborting.");
\r
1588 System.err.println("Error retrieving user information.");
\r
1589 isConnected = false;
\r
1590 QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, tr("Connection Error"), tr("Error retrieving user information. Synchronization not complete"));
\r
1595 noteStoreUrl = noteStoreUrlBase + user.getShardId();
\r
1596 syncSignal.saveAuthToken.emit(authToken);
\r
1597 syncSignal.saveNoteStore.emit(localNoteStore);
\r
1601 noteStoreTrans = new THttpClient(noteStoreUrl);
\r
1602 noteStoreTrans.setCustomHeader("User-Agent", userAgent);
\r
1603 } catch (TTransportException e) {
\r
1604 QMessageBox mb = new QMessageBox(QMessageBox.Icon.Critical, "Transport Excepton", e.getLocalizedMessage());
\r
1606 e.printStackTrace();
\r
1607 isConnected = false;
\r
1609 noteStoreProt = new TBinaryProtocol(noteStoreTrans);
\r
1611 new NoteStore.Client(noteStoreProt, noteStoreProt);
\r
1612 isConnected = true;
\r
1613 //authTimeRemaining = authResult.getExpiration() - authResult.getCurrentTime();
\r
1614 //authRefreshTime = authTimeRemaining / 2;
\r
1617 // Get user information
\r
1619 User user = userStore.getUser(authToken);
\r
1620 syncSignal.saveUserInformation.emit(user);
\r
1621 } catch (EDAMUserException e1) {
\r
1622 e1.printStackTrace();
\r
1623 } catch (EDAMSystemException e1) {
\r
1624 e1.printStackTrace();
\r
1625 } catch (TException e1) {
\r
1626 e1.printStackTrace();
\r
1629 return isConnected;
\r
1631 // Disconnect from the database
\r
1632 public void enDisconnect() {
\r
1633 isConnected = false;
\r
1637 // Refresh the connection
\r
1638 private synchronized boolean refreshConnection() {
\r
1640 logger.log(logger.EXTREME, "Entering SyncRunner.refreshConnection()");
\r
1641 // Calendar cal = Calendar.getInstance();
\r
1643 // If we are not connected let's get out of here
\r
1647 // If we fail too many times, then let's give up.
\r
1648 if (failedRefreshes >=5) {
\r
1649 logger.log(logger.EXTREME, "Refresh attempts have failed. Disconnecting.");
\r
1650 isConnected = false;
\r
1651 status.message.emit(tr("Unable to synchronize - Authentication failed"));
\r
1655 // If this is the first time through, then we need to set this
\r
1656 // if (authRefreshTime == 0 || cal.getTimeInMillis() > authRefreshTime)
\r
1657 // authRefreshTime = cal.getTimeInMillis();
\r
1659 // // Default to checking again in 5 min. This in case we fail.
\r
1660 // authRefreshTime = authRefreshTime +(5*60*1000);
\r
1662 // Try to get a new token
\r
1663 AuthenticationResult newAuth = null;
\r
1664 logger.log(logger.EXTREME, "Beginning to try authentication refresh");
\r
1666 if (userStore != null && authToken != null)
\r
1667 newAuth = userStore.refreshAuthentication(authToken);
\r
1670 logger.log(logger.EXTREME, "UserStore.refreshAuthentication has succeeded.");
\r
1671 } catch (EDAMUserException e) {
\r
1672 e.printStackTrace();
\r
1673 syncSignal.authRefreshComplete.emit(false);
\r
1674 failedRefreshes++;
\r
1676 } catch (EDAMSystemException e) {
\r
1677 e.printStackTrace();
\r
1678 syncSignal.authRefreshComplete.emit(false);
\r
1679 failedRefreshes++;
\r
1681 } catch (TException e) {
\r
1682 e.printStackTrace();
\r
1683 syncSignal.authRefreshComplete.emit(false);
\r
1684 failedRefreshes++;
\r
1688 // If we didn't get a good auth, then we've failed
\r
1689 if (newAuth == null) {
\r
1690 failedRefreshes++;
\r
1691 status.message.emit(tr("Unable to synchronize - Authentication failed"));
\r
1692 logger.log(logger.EXTREME, "Authentication failure #" +failedRefreshes);
\r
1693 status.message.emit(tr("Unable to synchronize - Authentication failed"));
\r
1694 syncSignal.authRefreshComplete.emit(false);
\r
1698 // We got a good token. Now we need to setup the time to renew it.
\r
1699 logger.log(logger.EXTREME, "Saving authentication tokens");
\r
1700 authResult = newAuth;
\r
1701 authToken = new String(newAuth.getAuthenticationToken());
\r
1702 // authTimeRemaining = authResult.getExpiration() - authResult.getCurrentTime();
\r
1703 // authRefreshTime = cal.getTimeInMillis() + (authTimeRemaining/4);
\r
1704 failedRefreshes=0;
\r
1705 syncSignal.authRefreshComplete.emit(true);
\r
1706 authRefreshNeeded = false;
\r
1708 // This should never happen, but if it does we consider this a faild attempt.
\r
1709 // if (authTimeRemaining <= 0) {
\r
1710 // failedRefreshes++;
\r
1711 // syncSignal.authRefreshComplete.emit(false);
\r
1719 public synchronized boolean addWork(String request) {
\r
1720 if (workQueue.offer(request))
\r
1725 private Note getNoteContent(Note n) {
\r
1726 QTextCodec codec = QTextCodec.codecForLocale();
\r
1727 codec = QTextCodec.codecForName("UTF-8");
\r
1728 n.setContent(codec.toUnicode(new QByteArray(n.getContent())));
\r
1734 //*********************************************************
\r
1735 //* Special download instructions. Used for DB upgrades
\r
1736 //*********************************************************
\r
1737 private void downloadAllSharedNotebooks(Client noteStore) {
\r
1739 List<SharedNotebook> books = noteStore.listSharedNotebooks(authToken);
\r
1740 logger.log(logger.LOW, "Shared notebooks found = " +books.size());
\r
1741 for (int i=0; i<books.size(); i++) {
\r
1742 conn.getSharedNotebookTable().updateNotebook(books.get(i), false);
\r
1744 conn.getSyncTable().deleteRecord("FullSharedNotebookSync");
\r
1745 } catch (EDAMUserException e1) {
\r
1746 e1.printStackTrace();
\r
1747 status.message.emit(tr("User exception Listing shared notebooks."));
\r
1748 logger.log(logger.LOW, e1.getMessage());
\r
1750 } catch (EDAMSystemException e1) {
\r
1751 e1.printStackTrace();
\r
1752 status.message.emit(tr("System exception Listing shared notebooks."));
\r
1753 logger.log(logger.LOW, e1.getMessage());
\r
1755 } catch (TException e1) {
\r
1756 e1.printStackTrace();
\r
1757 status.message.emit(tr("Transaction exception Listing shared notebooks."));
\r
1758 logger.log(logger.LOW, e1.getMessage());
\r
1760 } catch (EDAMNotFoundException e1) {
\r
1761 e1.printStackTrace();
\r
1762 status.message.emit(tr("EDAM Not Found exception Listing shared notebooks."));
\r
1763 logger.log(logger.LOW, e1.getMessage());
\r
1766 private void downloadAllNotebooks(Client noteStore) {
\r
1768 List<Notebook> books = noteStore.listNotebooks(authToken);
\r
1769 logger.log(logger.LOW, "Shared notebooks found = " +books.size());
\r
1770 for (int i=0; i<books.size(); i++) {
\r
1771 conn.getNotebookTable().updateNotebook(books.get(i), false);
\r
1773 conn.getSyncTable().deleteRecord("FullNotebookSync");
\r
1774 } catch (EDAMUserException e1) {
\r
1775 e1.printStackTrace();
\r
1776 status.message.emit(tr("User exception Listing notebooks."));
\r
1777 logger.log(logger.LOW, e1.getMessage());
\r
1779 } catch (EDAMSystemException e1) {
\r
1780 e1.printStackTrace();
\r
1781 status.message.emit(tr("System exception Listing notebooks."));
\r
1782 logger.log(logger.LOW, e1.getMessage());
\r
1784 } catch (TException e1) {
\r
1785 e1.printStackTrace();
\r
1786 status.message.emit(tr("Transaction exception Listing notebooks."));
\r
1787 logger.log(logger.LOW, e1.getMessage());
\r
1791 private void downloadAllLinkedNotebooks(Client noteStore) {
\r
1793 List<LinkedNotebook> books = noteStore.listLinkedNotebooks(authToken);
\r
1794 logger.log(logger.LOW, "Linked notebooks found = " +books.size());
\r
1795 for (int i=0; i<books.size(); i++) {
\r
1796 conn.getLinkedNotebookTable().updateNotebook(books.get(i), false);
\r
1798 conn.getSyncTable().deleteRecord("FullLinkedNotebookSync");
\r
1799 } catch (EDAMUserException e1) {
\r
1800 e1.printStackTrace();
\r
1801 status.message.emit(tr("User exception Listing linked notebooks."));
\r
1802 logger.log(logger.LOW, e1.getMessage());
\r
1804 } catch (EDAMSystemException e1) {
\r
1805 e1.printStackTrace();
\r
1806 status.message.emit(tr("System exception Listing linked notebooks."));
\r
1807 logger.log(logger.LOW, e1.getMessage());
\r
1809 } catch (TException e1) {
\r
1810 e1.printStackTrace();
\r
1811 status.message.emit(tr("Transaction exception Listing lineked notebooks."));
\r
1812 logger.log(logger.LOW, e1.getMessage());
\r
1814 } catch (EDAMNotFoundException e1) {
\r
1815 e1.printStackTrace();
\r
1816 status.message.emit(tr("EDAM Not Found exception Listing linked notebooks."));
\r
1817 logger.log(logger.LOW, e1.getMessage());
\r
1822 private void downloadInkNoteImage(String guid, String authToken) {
\r
1823 String urlBase = noteStoreUrl.replace("/edam/note/", "/shard/") + "/res/"+guid+".ink?slice=";
\r
1824 // urlBase = "https://www.evernote.com/shard/s1/res/52b567a9-54ae-4a08-afc5-d5bae275b2a8.ink?slice=";
\r
1825 Integer slice = 1;
\r
1826 Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(guid, false);
\r
1827 conn.getInkImagesTable().expungeImage(r.getGuid());
\r
1828 int sliceCount = 1+((r.getHeight()-1)/480);
\r
1829 HttpClient http = new DefaultHttpClient();
\r
1830 for (int i=0; i<sliceCount; i++) {
\r
1831 String url = urlBase + slice.toString();
\r
1832 HttpPost post = new HttpPost(url);
\r
1833 post.getParams().setParameter("auth", authToken);
\r
1834 List <NameValuePair> nvps = new ArrayList <NameValuePair>();
\r
1835 nvps.add(new BasicNameValuePair("auth", authToken));
\r
1838 post.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
\r
1839 } catch (UnsupportedEncodingException e1) {
\r
1840 e1.printStackTrace();
\r
1843 HttpResponse response = http.execute(post);
\r
1844 HttpEntity resEntity = response.getEntity();
\r
1845 InputStream is = resEntity.getContent();
\r
1846 QByteArray data = writeToFile(is);
\r
1847 conn.getInkImagesTable().saveImage(guid, slice, data);
\r
1848 } catch (ClientProtocolException e) {
\r
1849 e.printStackTrace();
\r
1850 } catch (IOException e) {
\r
1851 e.printStackTrace();
\r
1856 http.getConnectionManager().shutdown();
\r
1857 noteSignal.noteChanged.emit(r.getNoteGuid(), null); // Signal to ivalidate note cache
\r
1861 public QByteArray writeToFile(InputStream iStream) throws IOException {
\r
1863 File temp = File.createTempFile("nn-inknote-temp", ".png");
\r
1865 // Save InputStream to the file.
\r
1866 BufferedOutputStream fOut = null;
\r
1868 fOut = new BufferedOutputStream(new FileOutputStream(temp));
\r
1869 byte[] buffer = new byte[32 * 1024];
\r
1870 int bytesRead = 0;
\r
1871 while ((bytesRead = iStream.read(buffer)) != -1) {
\r
1872 fOut.write(buffer, 0, bytesRead);
\r
1879 QFile tempFile = new QFile(temp.getAbsoluteFile().toString());
\r
1880 tempFile.open(OpenModeFlag.ReadOnly);
\r
1881 QByteArray data = tempFile.readAll();
\r
1883 tempFile.remove();
\r
1888 //******************************************
\r
1889 //* Begin syncing shared notebooks
\r
1890 //******************************************
\r
1891 private void syncLinkedNotebooks() {
\r
1892 logger.log(logger.MEDIUM, "Authenticating linked Notebooks");
\r
1893 status.message.emit(tr("Synchronizing shared notebooks."));
\r
1894 List<LinkedNotebook> books = conn.getLinkedNotebookTable().getAll();
\r
1896 errorSharedNotebooks.clear();
\r
1898 for (int i=0; i<books.size(); i++) {
\r
1899 if (errorSharedNotebooksIgnored.containsKey(books.get(i).getGuid()))
\r
1902 logger.log(logger.EXTREME, "Checking notebook: " +books.get(i).getShareName());
\r
1903 long lastSyncDate = conn.getLinkedNotebookTable().getLastSequenceDate(books.get(i).getGuid());
\r
1904 int lastSequenceNumber = conn.getLinkedNotebookTable().getLastSequenceNumber(books.get(i).getGuid());
\r
1906 logger.log(logger.EXTREME, "Last Sequence Number on file: " +lastSequenceNumber);
\r
1908 // Authenticate to the owner's shard
\r
1909 String linkedNoteStoreUrl = noteStoreUrlBase + books.get(i).getShardId();
\r
1910 logger.log(logger.EXTREME, "linkedNoteStoreURL: " +linkedNoteStoreUrl);
\r
1911 THttpClient linkedNoteStoreTrans = new THttpClient(linkedNoteStoreUrl);
\r
1912 TBinaryProtocol linkedNoteStoreProt = new TBinaryProtocol(linkedNoteStoreTrans);
\r
1913 Client linkedNoteStore = new NoteStore.Client(linkedNoteStoreProt, linkedNoteStoreProt);
\r
1915 linkedAuthResult = null;
\r
1916 if (books.get(i).getShareKey() != null) {
\r
1917 logger.log(logger.EXTREME, "Share Key Not Null: " +books.get(i).getShareKey());
\r
1918 linkedAuthResult = linkedNoteStore.authenticateToSharedNotebook(books.get(i).getShareKey(), authToken);
\r
1919 logger.log(logger.EXTREME, "Authentication Token" +linkedAuthResult.getAuthenticationToken());
\r
1921 logger.log(logger.EXTREME, "Share key is null");
\r
1922 linkedAuthResult = new AuthenticationResult();
\r
1923 linkedAuthResult.setAuthenticationToken("");
\r
1925 SyncState linkedSyncState =
\r
1926 linkedNoteStore.getLinkedNotebookSyncState(linkedAuthResult.getAuthenticationToken(), books.get(i));
\r
1927 if (linkedSyncState.getUpdateCount() > lastSequenceNumber) {
\r
1928 logger.log(logger.EXTREME, "Remote changes found");
\r
1929 if (lastSyncDate < linkedSyncState.getFullSyncBefore()) {
\r
1930 lastSequenceNumber = 0;
\r
1932 logger.log(logger.EXTREME, "Calling syncLinkedNotebook for " +books.get(i).getShareName());
\r
1933 syncLinkedNotebook(linkedNoteStore, books.get(i),
\r
1934 lastSequenceNumber, linkedSyncState.getUpdateCount(), authToken);
\r
1937 // Synchronize local changes
\r
1938 syncLocalLinkedNoteChanges(linkedNoteStore, books.get(i));
\r
1940 } catch (EDAMUserException e) {
\r
1941 e.printStackTrace();
\r
1942 } catch (EDAMNotFoundException e) {
\r
1943 status.message.emit(tr("Error synchronizing \" " +
\r
1944 books.get(i).getShareName()+"\". Please verify you still have access to that shared notebook."));
\r
1945 errorSharedNotebooks.add(books.get(i).getGuid());
\r
1946 errorSharedNotebooksIgnored.put(books.get(i).getGuid(), books.get(i).getGuid());
\r
1947 logger.log(logger.LOW, "Error synchronizing shared notebook. EDAMNotFound: "+e.getMessage());
\r
1948 logger.log(logger.LOW, e.getStackTrace());
\r
1950 e.printStackTrace();
\r
1951 } catch (EDAMSystemException e) {
\r
1953 logger.log(logger.LOW, "System error authenticating against shared notebook. "+
\r
1954 "Key: "+books.get(i).getShareKey() +" Error:" +e.getMessage());
\r
1955 e.printStackTrace();
\r
1956 } catch (TException e) {
\r
1958 e.printStackTrace();
\r
1963 conn.getTagTable().removeUnusedLinkedTags();
\r
1964 conn.getTagTable().cleanupTags();
\r
1965 tagSignal.listChanged.emit();
\r
1970 //**************************************************************
\r
1971 //* Linked notebook contents (from someone else's account)
\r
1972 //*************************************************************
\r
1973 private void syncLinkedNotebook(Client linkedNoteStore, LinkedNotebook book, int usn, int highSequence, String token) {
\r
1974 logger.log(logger.EXTREME, "Entering syncLinkedNotebook");
\r
1975 if (ignoreLinkedNotebooks.contains(book.getGuid()))
\r
1977 List<Note> dirtyNotes = conn.getNoteTable().getDirtyLinkedNotes();
\r
1978 if (dirtyNoteGuids == null)
\r
1979 dirtyNoteGuids = new ArrayList<String>();
\r
1981 for (int i=0; i<dirtyNotes.size() && keepRunning; i++) {
\r
1982 dirtyNoteGuids.add(dirtyNotes.get(i).getGuid());
\r
1984 boolean fullSync = false;
\r
1987 boolean syncError = false;
\r
1988 while (usn < highSequence && !syncError) {
\r
1989 refreshNeeded = true;
\r
1991 SyncChunk chunk =
\r
1992 linkedNoteStore.getLinkedNotebookSyncChunk(token, book, usn, 10, fullSync);
\r
1995 syncExpungedNotes(chunk);
\r
1997 logger.log(logger.EXTREME, "Syncing remote notes: " +chunk.getNotesSize());
\r
1998 syncRemoteNotes(linkedNoteStore, chunk.getNotes(), fullSync, linkedAuthResult.getAuthenticationToken());
\r
1999 logger.log(logger.EXTREME, "Finding new linked tags");
\r
2000 findNewLinkedTags(linkedNoteStore, chunk.getNotes(), linkedAuthResult.getAuthenticationToken());
\r
2002 logger.log(logger.EXTREME, "Synchronizing tags: " +chunk.getTagsSize());
\r
2003 for (int i=0; i<chunk.getResourcesSize(); i++) {
\r
2004 syncRemoteResource(linkedNoteStore, chunk.getResources().get(i), linkedAuthResult.getAuthenticationToken());
\r
2006 logger.log(logger.EXTREME, "Synchronizing linked notebooks: " +chunk.getNotebooksSize());
\r
2007 syncRemoteLinkedNotebooks(linkedNoteStore, chunk.getNotebooks(), false, book);
\r
2008 syncLinkedTags(chunk.getTags(), book.getGuid());
\r
2010 // Go through & signal any notes that have changed so we can refresh the user's view
\r
2011 for (int i=0; i<chunk.getNotesSize(); i++)
\r
2012 noteSignal.noteChanged.emit(chunk.getNotes().get(i).getGuid(), null);
\r
2014 // Expunge Notebook records
\r
2015 logger.log(logger.EXTREME, "Expunging linked notebooks: " +chunk.getExpungedLinkedNotebooksSize());
\r
2016 for (int i=0; i<chunk.getExpungedLinkedNotebooksSize(); i++) {
\r
2017 conn.getLinkedNotebookTable().expungeNotebook(chunk.getExpungedLinkedNotebooks().get(i), false);
\r
2019 usn = chunk.getChunkHighUSN();
\r
2020 conn.getLinkedNotebookTable().setLastSequenceDate(book.getGuid(),chunk.getCurrentTime());
\r
2021 conn.getLinkedNotebookTable().setLastSequenceNumber(book.getGuid(),chunk.getChunkHighUSN());
\r
2022 } catch (EDAMUserException e) {
\r
2024 status.message.emit(tr("EDAM UserException synchronizing linked notbook. See the log for datails."));
\r
2025 e.printStackTrace();
\r
2026 logger.log(logger.LOW, tr("EDAM UserException synchronizing linked notbook ")+ e.getMessage());
\r
2027 } catch (EDAMSystemException e) {
\r
2029 status.message.emit(tr("EDAM SystemException synchronizing linked notbook. See the log for datails."));
\r
2030 e.printStackTrace();
\r
2031 logger.log(logger.LOW, tr("EDAM SystemException synchronizing linked notbook. See the log for datails") +e.getMessage());
\r
2032 } catch (EDAMNotFoundException e) {
\r
2034 status.message.emit(tr("Notebook URL not found. Removing notobook ") +book.getShareName());
\r
2035 conn.getNotebookTable().deleteLinkedTags(book.getGuid());
\r
2036 conn.getLinkedNotebookTable().expungeNotebook(book.getGuid(), false);
\r
2037 logger.log(logger.LOW, tr("Notebook URL not found. Removing notobook ") +e.getMessage());
\r
2038 } catch (TException e) {
\r
2040 status.message.emit(tr("EDAM TException synchronizing linked notbook. See the log for datails."));
\r
2041 e.printStackTrace();
\r
2042 logger.log(logger.LOW, tr("EDAM TException synchronizing linked notbook. See the log for datails." )+e.getMessage());
\r
2045 logger.log(logger.EXTREME, "leaving syncLinkedNotebook");
\r
2047 // Sync remote tags
\r
2048 private void syncLinkedTags(List<Tag> tags, String notebookGuid) {
\r
2049 logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteTags");
\r
2050 if (tags != null) {
\r
2051 for (int i=0; i<tags.size() && keepRunning; i++) {
\r
2052 conn.getTagTable().syncLinkedTag(tags.get(i), notebookGuid, false);
\r
2055 logger.log(logger.EXTREME, "Leaving SyncRunner.syncRemoteTags");
\r
2058 // Sync notebooks from a linked notebook
\r
2059 private void syncRemoteLinkedNotebooks(Client noteStore, List<Notebook> notebooks, boolean readOnly, LinkedNotebook linked) {
\r
2060 logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteNotebooks");
\r
2061 if (notebooks != null) {
\r
2062 for (int i=0; i<notebooks.size() && keepRunning; i++) {
\r
2064 logger.log(logger.EXTREME, "auth token:" +linkedAuthResult.getAuthenticationToken());
\r
2065 if (!linkedAuthResult.getAuthenticationToken().equals("")) {
\r
2066 SharedNotebook s = noteStore.getSharedNotebookByAuth(linkedAuthResult.getAuthenticationToken());
\r
2067 logger.log(logger.EXTREME, "share key:"+s.getShareKey() +" notebookGuid" +s.getNotebookGuid());
\r
2068 conn.getLinkedNotebookTable().setNotebookGuid(s.getShareKey(), s.getNotebookGuid());
\r
2069 readOnly = !s.isNotebookModifiable();
\r
2073 notebooks.get(i).setName(linked.getShareName());
\r
2074 notebooks.get(i).setDefaultNotebook(false);
\r
2075 conn.getNotebookTable().syncLinkedNotebook(notebooks.get(i), false, readOnly);
\r
2076 } catch (EDAMUserException e) {
\r
2078 e.printStackTrace();
\r
2079 } catch (EDAMNotFoundException e) {
\r
2081 e.printStackTrace();
\r
2082 } catch (EDAMSystemException e) {
\r
2084 e.printStackTrace();
\r
2085 } catch (TException e) {
\r
2087 e.printStackTrace();
\r
2092 logger.log(logger.EXTREME, "Leaving SyncRunner.syncRemoteNotebooks");
\r
2095 private void findNewLinkedTags(Client noteStore, List<Note> newNotes, String token) {
\r
2096 if (newNotes == null)
\r
2098 for (int i=0; i<newNotes.size(); i++) {
\r
2099 Note n = newNotes.get(i);
\r
2100 for (int j=0; j<n.getTagGuidsSize(); j++) {
\r
2101 String tag = n.getTagGuids().get(j);
\r
2102 if (!conn.getTagTable().exists(tag)) {
\r
2105 newTag = noteStore.getTag(token, tag);
\r
2106 conn.getTagTable().addTag(newTag, false);
\r
2107 } catch (EDAMUserException e) {
\r
2108 e.printStackTrace();
\r
2109 } catch (EDAMSystemException e) {
\r
2110 e.printStackTrace();
\r
2111 } catch (EDAMNotFoundException e) {
\r
2112 e.printStackTrace();
\r
2113 } catch (TException e) {
\r
2114 e.printStackTrace();
\r
2122 // Synchronize changes locally done to linked notes
\r
2123 private void syncLocalLinkedNoteChanges(Client noteStore, LinkedNotebook book) {
\r
2124 logger.log(logger.EXTREME, "Entering SyncRunner.synclocalLinkedNoteChanges");
\r
2125 String notebookGuid = conn.getLinkedNotebookTable().getNotebookGuid(book.getGuid());
\r
2126 logger.log(logger.EXTREME, "Finding changes for " +book.getShareName() +":" +book.getGuid() + ":" +notebookGuid);
\r
2127 List<Note> notes = conn.getNoteTable().getDirtyLinked(notebookGuid);
\r
2128 logger.log(logger.EXTREME, "Number of changes found: " +notes.size());
\r
2129 for (int i=0; i<notes.size(); i++) {
\r
2130 logger.log(logger.EXTREME, "Calling syncLocalNote with key " +linkedAuthResult.getAuthenticationToken());
\r
2131 syncLocalNote(noteStore, notes.get(i), linkedAuthResult.getAuthenticationToken());
\r
2133 logger.log(logger.EXTREME, "Leaving SyncRunner.synclocalLinkedNoteChanges");
\r