*/\r
package cx.fbn.nevernote.threads;\r
\r
+import java.io.BufferedOutputStream;\r
+import java.io.File;\r
+import java.io.FileOutputStream;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.UnsupportedEncodingException;\r
import java.net.UnknownHostException;\r
import java.util.ArrayList;\r
import java.util.Calendar;\r
import java.util.Vector;\r
import java.util.concurrent.LinkedBlockingQueue;\r
\r
+import org.apache.http.HttpEntity;\r
+import org.apache.http.HttpResponse;\r
+import org.apache.http.NameValuePair;\r
+import org.apache.http.client.ClientProtocolException;\r
+import org.apache.http.client.HttpClient;\r
+import org.apache.http.client.entity.UrlEncodedFormEntity;\r
+import org.apache.http.client.methods.HttpPost;\r
+import org.apache.http.impl.client.DefaultHttpClient;\r
+import org.apache.http.message.BasicNameValuePair;\r
+import org.apache.http.protocol.HTTP;\r
import org.apache.thrift.TException;\r
import org.apache.thrift.protocol.TBinaryProtocol;\r
import org.apache.thrift.transport.THttpClient;\r
import com.evernote.edam.notestore.SyncChunk;\r
import com.evernote.edam.notestore.SyncState;\r
import com.evernote.edam.type.Data;\r
+import com.evernote.edam.type.LinkedNotebook;\r
import com.evernote.edam.type.Note;\r
import com.evernote.edam.type.Notebook;\r
import com.evernote.edam.type.Resource;\r
import com.evernote.edam.type.SavedSearch;\r
+import com.evernote.edam.type.SharedNotebook;\r
import com.evernote.edam.type.Tag;\r
import com.evernote.edam.type.User;\r
import com.evernote.edam.userstore.AuthenticationResult;\r
import com.evernote.edam.userstore.UserStore;\r
+import com.trolltech.qt.core.QByteArray;\r
+import com.trolltech.qt.core.QFile;\r
+import com.trolltech.qt.core.QIODevice.OpenModeFlag;\r
import com.trolltech.qt.core.QObject;\r
import com.trolltech.qt.gui.QMessageBox;\r
\r
updateSequenceNumber = 0;\r
conn.getSyncTable().setUpdateSequenceNumber(0);\r
}\r
-\r
+ // Check for "special" sync instructions\r
+ String syncLinked = conn.getSyncTable().getRecord("FullLinkedNotebookSync");\r
+ String syncShared = conn.getSyncTable().getRecord("FullLinkedNotebookSync");\r
+ String syncNotebooks = conn.getSyncTable().getRecord("FullNotebookSync");\r
+ String syncInkNoteImages = conn.getSyncTable().getRecord("FullInkNoteImageSync");\r
+ if (syncLinked != null) {\r
+ downloadAllLinkedNotebooks();\r
+ }\r
+ if (syncShared != null) {\r
+ downloadAllSharedNotebooks();\r
+ }\r
+ if (syncNotebooks != null) {\r
+ downloadAllNotebooks();\r
+ }\r
+ \r
+ if (syncInkNoteImages != null) {\r
+ List<String> guids = conn.getNoteTable().noteResourceTable.findInkNotes();\r
+ for (int i=0; i<guids.size(); i++) {\r
+ downloadInkNoteImage(guids.get(i));\r
+ }\r
+ conn.getSyncTable().deleteRecord("FullInkNoteImageSync");\r
+ }\r
+ \r
// If there are remote changes\r
logger.log(logger.LOW, "Update Count: " +syncState.getUpdateCount());\r
logger.log(logger.LOW, "Last Update Count: " +updateSequenceNumber);\r
}\r
if (refreshNeeded)\r
syncSignal.refreshLists.emit();\r
+ \r
if (!error) {\r
logger.log(logger.EXTREME, "Sync completed. Errors=" +error);\r
if (!disableUploads) \r
}\r
logger.log(logger.HIGH, "Leaving SyncRunner.evernoteSync");\r
}\r
+ \r
// Sync deleted items with Evernote\r
private void syncExpunged() {\r
logger.log(logger.HIGH, "Entering SyncRunner.syncExpunged");\r
\r
List<DeletedItemRecord> expunged = conn.getDeletedTable().getAllDeleted();\r
boolean error = false;\r
- for (int i=0; i<expunged.size(); i++) {\r
+ for (int i=0; i<expunged.size() && keepRunning; i++) {\r
\r
if (authRefreshNeeded)\r
refreshConnection();\r
syncRemoteNotebooks(chunk.getNotebooks());\r
syncRemoteNotes(chunk.getNotes(), fullSync);\r
syncRemoteResources(chunk.getResources());\r
+ syncRemoteLinkedNotebooks(chunk.getLinkedNotebooks());\r
\r
// Do the local deletes\r
logger.log(logger.EXTREME, "Doing local deletes");\r
List<String> guid = chunk.getExpungedNotes();\r
- if (guid != null) \r
+ if (guid != null) {\r
for (int i=0; i<guid.size() && keepRunning; i++) {\r
- logger.log(logger.EXTREME, "Expunging local note from database");\r
- conn.getNoteTable().expungeNote(guid.get(i), true, false);\r
+ String notebookGuid = "";\r
+ Note localNote = conn.getNoteTable().getNote(guid.get(i), false, false, false, false, false);\r
+ if (localNote != null) {\r
+ conn.getNoteTable().updateNoteSequence(guid.get(i), 0);\r
+ notebookGuid = localNote.getNotebookGuid();\r
+ }\r
+ if (!conn.getNotebookTable().isNotebookLocal(notebookGuid)) {\r
+ logger.log(logger.EXTREME, "Expunging local note from database");\r
+ conn.getNoteTable().expungeNote(guid.get(i), true, false);\r
+ }\r
}\r
+ }\r
guid = chunk.getExpungedNotebooks();\r
if (guid != null)\r
for (int i=0; i<guid.size() && keepRunning; i++) {\r
logger.log(logger.EXTREME, "Expunging saved search from local database");\r
conn.getSavedSearchTable().expungeSavedSearch(guid.get(i), false);\r
}\r
+ guid = chunk.getExpungedLinkedNotebooks();\r
+ if (guid != null) \r
+ for (int i=0; i<guid.size() && keepRunning; i++) {\r
+ logger.log(logger.EXTREME, "Expunging linked notebook from local database");\r
+ conn.getLinkedNotebookTable().expungeNotebook(guid.get(i), false);\r
+ }\r
\r
\r
// Check for more notes\r
}\r
logger.log(logger.EXTREME, "Leaving SyncRunner.syncRemoteTags");\r
}\r
- // Sync remote tags\r
+ // Sync remote saved searches\r
private void syncRemoteSavedSearches(List<SavedSearch> searches) {\r
logger.log(logger.EXTREME, "Entering SyncRunner.syncSavedSearches");\r
if (searches != null) {\r
}\r
logger.log(logger.EXTREME, "Leaving SyncRunner.syncSavedSearches");\r
}\r
+ // Sync remote linked notebooks\r
+ private void syncRemoteLinkedNotebooks(List<LinkedNotebook> books) {\r
+ logger.log(logger.EXTREME, "Entering SyncRunner.syncSavedSearches");\r
+ if (books != null) {\r
+ for (int i=0; i<books.size() && keepRunning; i++) {\r
+ conn.getLinkedNotebookTable().updateNotebook(books.get(i), false); \r
+ }\r
+ }\r
+ logger.log(logger.EXTREME, "Leaving SyncRunner.syncSavedSearches");\r
+ }\r
// Sync remote Notebooks 2\r
private void syncRemoteNotebooks(List<Notebook> notebooks) {\r
logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteNotebooks");\r
\r
if (saveNeeded) \r
conn.getNoteTable().noteResourceTable.updateNoteResource(r, false);\r
+ if (r.getMime().equalsIgnoreCase("application/vnd.evernote.ink"))\r
+ downloadInkNoteImage(r.getGuid());\r
\r
}\r
}\r
logger.log(logger.EXTREME, "Leaving SyncRunner.syncRemoteResources");\r
}\r
- // Sync remote notebooks\r
+ // Sync remote notes\r
private void syncRemoteNotes(List<Note> note, boolean fullSync) {\r
logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteNotes");\r
if (note != null) {\r
for (int q=0; q<n.getResources().size() && keepRunning; q++) {\r
logger.log(logger.EXTREME, "Getting note resources.");\r
conn.getNoteTable().noteResourceTable.updateNoteResource(n.getResources().get(q), false);\r
+ if (n.getResources().get(q).getMime().equalsIgnoreCase("application/vnd.evernote.ink"))\r
+ downloadInkNoteImage(n.getResources().get(q).getGuid());\r
}\r
}\r
}\r
n.setContent(conn.getNoteTable().getNoteContentBinary(n.getGuid()));\r
return n;\r
}\r
+\r
+\r
+\r
+ //*********************************************************\r
+ //* Special download instructions. Used for DB upgrades\r
+ //*********************************************************\r
+ private void downloadAllSharedNotebooks() {\r
+ try {\r
+ List<SharedNotebook> books = noteStore.listSharedNotebooks(authToken);\r
+ logger.log(logger.LOW, "Shared notebooks found = " +books.size());\r
+ for (int i=0; i<books.size(); i++) {\r
+ conn.getSharedNotebookTable().updateNotebook(books.get(i), false);\r
+ }\r
+ conn.getSyncTable().deleteRecord("FullSharedNotebookSync");\r
+ } catch (EDAMUserException e1) {\r
+ e1.printStackTrace();\r
+ status.message.emit(tr("User exception Listing shared notebooks."));\r
+ logger.log(logger.LOW, e1.getMessage());\r
+ return;\r
+ } catch (EDAMSystemException e1) {\r
+ e1.printStackTrace();\r
+ status.message.emit(tr("System exception Listing shared notebooks."));\r
+ logger.log(logger.LOW, e1.getMessage());\r
+ return;\r
+ } catch (TException e1) {\r
+ e1.printStackTrace();\r
+ status.message.emit(tr("Transaction exception Listing shared notebooks."));\r
+ logger.log(logger.LOW, e1.getMessage());\r
+ return;\r
+ } catch (EDAMNotFoundException e1) {\r
+ e1.printStackTrace();\r
+ status.message.emit(tr("EDAM Not Found exception Listing shared notebooks."));\r
+ logger.log(logger.LOW, e1.getMessage());\r
+ }\r
+ }\r
+ private void downloadAllNotebooks() {\r
+ try {\r
+ List<Notebook> books = noteStore.listNotebooks(authToken);\r
+ logger.log(logger.LOW, "Shared notebooks found = " +books.size());\r
+ for (int i=0; i<books.size(); i++) {\r
+ conn.getNotebookTable().updateNotebook(books.get(i), false);\r
+ }\r
+ conn.getSyncTable().deleteRecord("FullNotebookSync");\r
+ } catch (EDAMUserException e1) {\r
+ e1.printStackTrace();\r
+ status.message.emit(tr("User exception Listing notebooks."));\r
+ logger.log(logger.LOW, e1.getMessage());\r
+ return;\r
+ } catch (EDAMSystemException e1) {\r
+ e1.printStackTrace();\r
+ status.message.emit(tr("System exception Listing notebooks."));\r
+ logger.log(logger.LOW, e1.getMessage());\r
+ return;\r
+ } catch (TException e1) {\r
+ e1.printStackTrace();\r
+ status.message.emit(tr("Transaction exception Listing notebooks."));\r
+ logger.log(logger.LOW, e1.getMessage());\r
+ return;\r
+ }\r
+ }\r
+ private void downloadAllLinkedNotebooks() {\r
+ try {\r
+ List<LinkedNotebook> books = noteStore.listLinkedNotebooks(authToken);\r
+ logger.log(logger.LOW, "Linked notebooks found = " +books.size());\r
+ for (int i=0; i<books.size(); i++) {\r
+ conn.getLinkedNotebookTable().updateNotebook(books.get(i), false);\r
+ }\r
+ conn.getSyncTable().deleteRecord("FullLinkedNotebookSync");\r
+ } catch (EDAMUserException e1) {\r
+ e1.printStackTrace();\r
+ status.message.emit(tr("User exception Listing linked notebooks."));\r
+ logger.log(logger.LOW, e1.getMessage());\r
+ return;\r
+ } catch (EDAMSystemException e1) {\r
+ e1.printStackTrace();\r
+ status.message.emit(tr("System exception Listing linked notebooks."));\r
+ logger.log(logger.LOW, e1.getMessage());\r
+ return;\r
+ } catch (TException e1) {\r
+ e1.printStackTrace();\r
+ status.message.emit(tr("Transaction exception Listing lineked notebooks."));\r
+ logger.log(logger.LOW, e1.getMessage());\r
+ return;\r
+ } catch (EDAMNotFoundException e1) {\r
+ e1.printStackTrace();\r
+ status.message.emit(tr("EDAM Not Found exception Listing linked notebooks."));\r
+ logger.log(logger.LOW, e1.getMessage());\r
+ }\r
+ }\r
+\r
+ \r
+ private void downloadInkNoteImage(String guid) {\r
+ String urlBase = noteStoreUrl.replace("/edam/note/", "/shard/") + "/res/"+guid+".ink?slice=";\r
+// urlBase = "https://www.evernote.com/shard/s1/res/52b567a9-54ae-4a08-afc5-d5bae275b2a8.ink?slice=";\r
+ Integer slice = 1;\r
+ Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(guid, false);\r
+ conn.getInkImagesTable().expungeImage(r.getGuid());\r
+ int sliceCount = 1+((r.getHeight()-1)/480);\r
+ HttpClient http = new DefaultHttpClient();\r
+ for (int i=0; i<sliceCount; i++) {\r
+ String url = urlBase + slice.toString();\r
+ HttpPost post = new HttpPost(url);\r
+ post.getParams().setParameter("auth", authToken);\r
+ List <NameValuePair> nvps = new ArrayList <NameValuePair>();\r
+ nvps.add(new BasicNameValuePair("auth", authToken));\r
+\r
+ try {\r
+ post.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));\r
+ } catch (UnsupportedEncodingException e1) {\r
+ // TODO Auto-generated catch block\r
+ e1.printStackTrace();\r
+ }\r
+ try {\r
+ HttpResponse response = http.execute(post);\r
+ HttpEntity resEntity = response.getEntity();\r
+ InputStream is = resEntity.getContent();\r
+ QByteArray data = writeToFile(is);\r
+ conn.getInkImagesTable().saveImage(guid, slice, data);\r
+ } catch (ClientProtocolException e) {\r
+ e.printStackTrace();\r
+ } catch (IOException e) {\r
+ e.printStackTrace();\r
+ }\r
+\r
+ slice++;\r
+ }\r
+ http.getConnectionManager().shutdown(); \r
+ noteSignal.noteChanged.emit(r.getNoteGuid(), null); // Signal to ivalidate note cache\r
+ }\r
+ \r
+ \r
+ public QByteArray writeToFile(InputStream iStream) throws IOException {\r
+\r
+ File temp = File.createTempFile("nn-inknote-temp", ".png");\r
+\r
+ // Save InputStream to the file.\r
+ BufferedOutputStream fOut = null;\r
+ try {\r
+ fOut = new BufferedOutputStream(new FileOutputStream(temp));\r
+ byte[] buffer = new byte[32 * 1024];\r
+ int bytesRead = 0;\r
+ while ((bytesRead = iStream.read(buffer)) != -1) {\r
+ fOut.write(buffer, 0, bytesRead);\r
+ }\r
+ }\r
+ finally {\r
+ iStream.close();\r
+ fOut.close();\r
+ }\r
+ QFile tempFile = new QFile(temp.getAbsoluteFile().toString());\r
+ tempFile.open(OpenModeFlag.ReadOnly);\r
+ QByteArray data = tempFile.readAll();\r
+ tempFile.close();\r
+ tempFile.remove();\r
+ return data;\r
+ }\r
+ \r
}\r