/* * This file is part of NixNote/NeighborNote * Copyright 2009 Randy Baumgarte * * This file may be licensed under the terms of of the * GNU General Public License Version 2 (the ``GPL''). * * Software distributed under the License is distributed * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either * express or implied. See the GPL for the specific language * governing rights and limitations. * * You should have received a copy of the GPL along with this * program. If not, go to http://www.gnu.org/licenses/gpl.html * or write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package cx.fbn.nevernote.xml; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import com.evernote.edam.type.Data; import com.evernote.edam.type.LinkedNotebook; import com.evernote.edam.type.Note; import com.evernote.edam.type.NoteAttributes; import com.evernote.edam.type.Notebook; import com.evernote.edam.type.Publishing; import com.evernote.edam.type.Resource; import com.evernote.edam.type.SavedSearch; import com.evernote.edam.type.SharedNotebook; import com.evernote.edam.type.Tag; import com.trolltech.qt.core.QByteArray; import com.trolltech.qt.core.QFile; import com.trolltech.qt.core.QIODevice; import com.trolltech.qt.xml.QXmlStreamWriter; import cx.fbn.nevernote.Global; import cx.fbn.nevernote.evernote.NoteMetadata; import cx.fbn.nevernote.sql.DatabaseConnection; import cx.fbn.nevernote.utilities.ApplicationLogger; public class ExportData { private List<Notebook> notebooks; private final HashMap<String,String> localNotebooks; private final HashMap<String,String> dirtyNotebooks; private final ApplicationLogger logger; private List<SavedSearch> searches; private List<LinkedNotebook> linkedNotebooks; private List<SharedNotebook> sharedNotebooks; private final HashMap<String,String> dirtySearches; private List<Tag> tags; private final HashMap<String,String> dirtyTags; private final HashMap<String, String> exportableNotebooks; private final HashMap<String, String> exportableTags; private List<Note> notes; private final HashMap<String,String> dirtyNotes; private final HashMap<String,String> dirtyLinkedNotebooks; private final HashMap<Long,String> dirtySharedNotebooks; private HashMap<String, NoteMetadata> noteMeta; private final boolean fullBackup; private final DatabaseConnection conn; private QXmlStreamWriter writer; private String errorMessage; public int lastError; public ExportData(DatabaseConnection conn2, boolean full) { conn = conn2; logger = new ApplicationLogger("export.log"); notebooks = new ArrayList<Notebook>(); tags = new ArrayList<Tag>(); notes = new ArrayList<Note>(); sharedNotebooks = new ArrayList<SharedNotebook>(); linkedNotebooks = new ArrayList<LinkedNotebook>(); dirtyNotebooks = new HashMap<String,String>(); localNotebooks = new HashMap<String,String>(); dirtyLinkedNotebooks = new HashMap<String,String>(); dirtySharedNotebooks = new HashMap<Long,String>(); dirtyTags = new HashMap<String,String>(); fullBackup = full; dirtyNotes = new HashMap<String, String>(); dirtySearches = new HashMap<String, String>(); searches = new ArrayList<SavedSearch>(); exportableNotebooks = new HashMap<String, String>(); exportableTags = new HashMap<String, String>(); } public ExportData(DatabaseConnection conn2, boolean full, List<String> guids) { conn = conn2; logger = new ApplicationLogger("export.log"); notebooks = new ArrayList<Notebook>(); tags = new ArrayList<Tag>(); notes = new ArrayList<Note>(); for (int i=0; i<guids.size(); i++) { notes.add(conn.getNoteTable().getNote(guids.get(i), true, true, true, true, true)); } dirtyNotebooks = new HashMap<String,String>(); localNotebooks = new HashMap<String,String>(); dirtyTags = new HashMap<String,String>(); fullBackup = full; dirtyNotes = new HashMap<String, String>(); dirtyLinkedNotebooks = new HashMap<String,String>(); dirtySharedNotebooks = new HashMap<Long,String>(); dirtySearches = new HashMap<String, String>(); searches = new ArrayList<SavedSearch>(); exportableNotebooks = new HashMap<String, String>(); exportableTags = new HashMap<String, String>(); } public void exportData(String filename) { notebooks = conn.getNotebookTable().getAll(); tags = conn.getTagTable().getAll(); List<Notebook> books = conn.getNotebookTable().getAllLocal(); for (int i=0; i<books.size(); i++) { localNotebooks.put(books.get(i).getGuid(), ""); } books = conn.getNotebookTable().getDirty(); for (int i=0; i<books.size(); i++) { dirtyNotebooks.put(books.get(i).getGuid(), ""); } List<Tag> d= conn.getTagTable().getDirty(); for (int i=0; i<d.size(); i++) { dirtyTags.put(d.get(i).getGuid(), ""); } if (fullBackup) notes = conn.getNoteTable().getAllNotes(); List<Note> dn = conn.getNoteTable().getDirty(); for (int i=0; i<dn.size(); i++) { dirtyNotes.put(dn.get(i).getGuid(), ""); } noteMeta = conn.getNoteTable().getNotesMetaInformation(); searches = conn.getSavedSearchTable().getAll(); List<SavedSearch> ds = conn.getSavedSearchTable().getDirty(); for (int i=0; i<ds.size(); i++) { dirtySearches.put(ds.get(i).getGuid(), ""); } linkedNotebooks = conn.getLinkedNotebookTable().getAll(); List<String> dln = conn.getLinkedNotebookTable().getDirtyGuids(); for (int i=0; i<dln.size(); i++) { dirtyLinkedNotebooks.put(dln.get(i), ""); } sharedNotebooks = conn.getSharedNotebookTable().getAll(); List<Long> dsn = conn.getSharedNotebookTable().getDirtyIds(); for (int i=0; i<dsn.size(); i++) { dirtySharedNotebooks.put(dsn.get(i), ""); } lastError = 0; errorMessage = ""; QFile xmlFile = new QFile(filename); if (!xmlFile.open(QIODevice.OpenModeFlag.WriteOnly, QIODevice.OpenModeFlag.Truncate)) { lastError = 16; errorMessage = "Cannot open file."; } writer = new QXmlStreamWriter(xmlFile); writer.setAutoFormatting(true); writer.setCodec("UTF-8"); writer.writeStartDocument(); writer.writeDTD("<!DOCTYPE NeverNote-Export>"); writer.writeStartElement("nevernote-export"); writer.writeAttribute("version", "0.95"); if (fullBackup) writer.writeAttribute("exportType", "backup"); else writer.writeAttribute("exportType", "export"); writer.writeAttribute("application", "NeverNote"); writer.writeAttribute("applicationVersion", Global.version); if (fullBackup) { writer.writeStartElement("Synchronization"); long sequenceDate = conn.getSyncTable().getLastSequenceDate(); int number = conn.getSyncTable().getUpdateSequenceNumber(); createTextNode("UpdateSequenceNumber", new Long(number).toString()); createTextNode("LastSequenceDate", new Long(sequenceDate).toString()); writer.writeEndElement(); } for (int i=0; i<notes.size(); i++) { String guid = notes.get(i).getGuid(); logger.log(logger.EXTREME, "Getting note " +guid +" : " +notes.get(i).getTitle()); Note note = conn.getNoteTable().getNote(guid, true, true, true, true, true); logger.log(logger.EXTREME, "Writing note XML"); writeNote(note); } writeNotebooks(); writeTags(); writeSavedSearches(); writeLinkedNotebooks(); writeSharedNotebooks(); writer.writeEndElement(); writer.writeEndDocument(); writer.dispose(); xmlFile.close(); xmlFile.dispose(); } private void writeSavedSearches() { if (!fullBackup) return; for (int i=0; i<searches.size(); i++) { writer.writeStartElement("SavedSearch"); createTextNode("Guid", searches.get(i).getGuid()); createTextNode("Name", searches.get(i).getName()); createTextNode("Query", searches.get(i).getQuery()); createTextNode("Format", new Integer(searches.get(i).getFormat().getValue()).toString()); if (dirtySearches.containsKey(searches.get(i).getGuid())) createTextNode("Dirty","true"); else createTextNode("Dirty","false"); writer.writeEndElement(); } } private void writeLinkedNotebooks() { if (!fullBackup) return; for (int i=0; i<linkedNotebooks.size(); i++) { writer.writeStartElement("LinkedNotebook"); createTextNode("Guid", linkedNotebooks.get(i).getGuid()); createTextNode("ShardID", linkedNotebooks.get(i).getShardId()); createTextNode("ShareKey", linkedNotebooks.get(i).getShareKey()); createTextNode("ShareName", linkedNotebooks.get(i).getShareName()); createTextNode("Uri", linkedNotebooks.get(i).getUri()); createTextNode("Username", linkedNotebooks.get(i).getUsername()); createTextNode("UpdateSequenceNumber", new Long(linkedNotebooks.get(i).getUpdateSequenceNum()).toString()); if (dirtyLinkedNotebooks.containsKey(linkedNotebooks.get(i).getGuid())) createTextNode("Dirty", "true"); else createTextNode("Dirty", "false"); writer.writeEndElement(); } } private void writeSharedNotebooks() { if (!fullBackup) return; for (int i=0; i<linkedNotebooks.size(); i++) { writer.writeStartElement("SharedNotebook"); createTextNode("Id", new Long(sharedNotebooks.get(i).getId()).toString()); createTextNode("Userid", new Integer(sharedNotebooks.get(i).getUserId()).toString()); createTextNode("Email", sharedNotebooks.get(i).getEmail()); createTextNode("NotebookGuid", sharedNotebooks.get(i).getNotebookGuid()); createTextNode("ShareKey", sharedNotebooks.get(i).getShareKey()); createTextNode("Username", sharedNotebooks.get(i).getUsername()); createTextNode("ServiceCreated", new Long(sharedNotebooks.get(i).getServiceCreated()).toString()); if (dirtySharedNotebooks.containsKey(sharedNotebooks.get(i).getId())) createTextNode("Dirty", "true"); else createTextNode("Dirty", "false"); writer.writeEndElement(); } } private void writeNote(Note note) { writer.writeStartElement("Note"); createTextNode("Guid", note.getGuid()); createTextNode("UpdateSequenceNumber", new Long(note.getUpdateSequenceNum()).toString()); createTextNode("Title", note.getTitle()); createTextNode("Created", new Long(note.getCreated()).toString()); createTextNode("Updated", new Long(note.getUpdated()).toString()); createTextNode("Deleted", new Long(note.getDeleted()).toString()); createTextNode("Active", new Boolean(note.isActive()).toString()); createTextNode("NotebookGuid", note.getNotebookGuid()); if (dirtyNotes.containsKey(note.getGuid())) createTextNode("Dirty", "true"); else createTextNode("Dirty", "false"); if (noteMeta.containsKey(note.getGuid())) { Integer color = new Integer(noteMeta.get(note.getGuid()).getColor()); createTextNode("TitleColor", color.toString()); } exportableNotebooks.put(note.getNotebookGuid(), ""); if (note.getTagGuidsSize() > 0) { writer.writeStartElement("NoteTags"); for (int i=0; i<note.getTagGuidsSize(); i++) { createTextNode("Guid", note.getTagGuids().get(i)); exportableTags.put(note.getTagGuids().get(i), ""); } writer.writeEndElement(); } NoteAttributes noteAttributes = note.getAttributes(); if (noteAttributes != null) { writer.writeStartElement("NoteAttributes"); createTextNode("Author", noteAttributes.getAuthor()); createTextNode("Source", noteAttributes.getSource()); createTextNode("SourceApplication", noteAttributes.getSourceApplication()); createTextNode("SourceURL", noteAttributes.getSourceURL()); createTextNode("Altitude", new Double(noteAttributes.getAltitude()).toString()); createTextNode("Longitude", new Double(noteAttributes.getLongitude()).toString()); createTextNode("Latitude", new Double(noteAttributes.getLatitude()).toString()); createTextNode("SubjectDate", new Long(noteAttributes.getSubjectDate()).toString()); writer.writeEndElement(); } // writeResources(conn.getNoteTable().noteResourceTable.getNoteResources(note.getGuid(), true)); writeResources(note.getResources()); logger.log(logger.EXTREME, "Writing content"); writer.writeStartElement("Content"); writer.writeCDATA(conn.getNoteTable().getNoteContentNoUTFConversion(note.getGuid())); writer.writeEndElement(); writer.writeEndElement(); } private void writeResources(List<Resource> resourceTable) { Resource resource; if (resourceTable.size() == 0) return; for (int i=0; i<resourceTable.size(); i++) { resource = resourceTable.get(i); writer.writeStartElement("NoteResource"); createTextNode("Guid", resource.getGuid()); createTextNode("NoteGuid", resource.getNoteGuid()); createTextNode("UpdateSequenceNumber", new Integer(resource.getUpdateSequenceNum()).toString()); createTextNode("Mime", resource.getMime()); createTextNode("Duration", new Integer(resource.getDuration()).toString()); createTextNode("Height", new Integer(resource.getHeight()).toString()); createTextNode("Width", new Integer(resource.getWidth()).toString()); logger.log(logger.EXTREME, "Checking for data node"); if (resource.getData() != null) writeDataNode("Data", resource.getData()); logger.log(logger.EXTREME, "Checking for alternate data node"); if (resource.getAlternateData() != null) writeDataNode("AlternateData", resource.getAlternateData()); logger.log(logger.EXTREME, "Checking for recognition"); if (resource.getRecognition() != null) writeRecognitionNode("Recognition", resource.getRecognition()); if (resource.isActive()) createTextNode("Active", "true"); else createTextNode("Active", "false"); logger.log(logger.EXTREME, "Checking resource attributes"); if (resource.getAttributes() != null) { writer.writeStartElement("NoteResourceAttribute"); createTextNode("CameraMake", resource.getAttributes().getCameraMake()); createTextNode("CameraModel", resource.getAttributes().getCameraModel()); createTextNode("FileName", resource.getAttributes().getFileName()); createTextNode("RecoType", resource.getAttributes().getRecoType()); createTextNode("SourceURL", resource.getAttributes().getSourceURL()); createTextNode("Altitude", new Double(resource.getAttributes().getAltitude()).toString()); createTextNode("Longitude", new Double(resource.getAttributes().getLongitude()).toString()); createTextNode("Latitude", new Double(resource.getAttributes().getLatitude()).toString()); createTextNode("Timestamp", new Long(resource.getAttributes().getTimestamp()).toString()); if (resource.getAttributes().isAttachment()) createTextNode("Attachment", "true"); else createTextNode("Attachment", "false"); if (resource.getAttributes().isClientWillIndex()) createTextNode("ClientWillIndex", "true"); else createTextNode("ClientWillIndex", "false"); writer.writeEndElement(); } writer.writeEndElement(); } logger.log(logger.EXTREME, "Ending resource node"); // writer.writeEndElement(); } private void writeDataNode(String name, Data data) { writer.writeStartElement(name); createTextNode("Size", new Integer(data.getSize()).toString()); if (data.getBody() != null && data.getBody().length > 0) createBinaryNode("Body", new QByteArray(data.getBody()).toHex().toString()); else createBinaryNode("Body", ""); if (data.getBodyHash() != null && data.getBodyHash().length > 0) createTextNode("BodyHash", new QByteArray(data.getBodyHash()).toHex().toString()); else createTextNode("BodyHash", ""); writer.writeEndElement(); } private void writeRecognitionNode(String name, Data data) { writer.writeStartElement(name); createTextNode("Size", new Integer(data.getSize()).toString()); if (data.getBody() != null && data.getBody().length > 0) { writer.writeStartElement("Body"); writer.writeCDATA(new QByteArray(data.getBody()).toString()); // writer.writeCDATA(new QByteArray(data.getBody()).toHex().toString()); writer.writeEndElement(); } else createBinaryNode("Body", ""); if (data.getBodyHash() != null && data.getBodyHash().length > 0) createTextNode("BodyHash", new QByteArray(data.getBodyHash()).toHex().toString()); else createTextNode("BodyHash", ""); writer.writeEndElement(); } private void writeNotebooks() { for (int i=0; i<notebooks.size(); i++) { if (exportableNotebooks.containsKey(notebooks.get(i).getGuid()) || fullBackup) { writer.writeStartElement("Notebook"); createTextNode("Guid", notebooks.get(i).getGuid()); createTextNode("Name", notebooks.get(i).getName()); createTextNode("UpdateSequenceNumber", new Long(notebooks.get(i).getUpdateSequenceNum()).toString()); if (notebooks.get(i).isDefaultNotebook()) createTextNode("DefaultNotebook", "true"); else createTextNode("DefaultNotebook", "false"); createTextNode("ServiceCreated", new Long(notebooks.get(i).getServiceCreated()).toString()); createTextNode("ServiceUpdated", new Long(notebooks.get(i).getServiceUpdated()).toString()); if (localNotebooks.containsKey(notebooks.get(i).getGuid())) createTextNode("Local","true"); else createTextNode("Local","false"); if (dirtyNotebooks.containsKey(notebooks.get(i).getGuid())) createTextNode("Dirty","true"); else createTextNode("Dirty","false"); if (conn.getNotebookTable().isReadOnly(notebooks.get(i).getGuid())) createTextNode("ReadOnly", "true"); else createTextNode("ReadOnly", "false"); if (notebooks.get(i).getPublishing() != null) { Publishing p = notebooks.get(i).getPublishing(); createTextNode("PublishingPublicDescription", p.getPublicDescription()); createTextNode("PublishingUri", p.getUri()); createTextNode("PublishingOrder", new Integer(p.getOrder().getValue()).toString()); if (p.isAscending()) createTextNode("PublishingAscending", "true"); else createTextNode("PublishingAscending", "false"); } QByteArray b = conn.getNotebookTable().getIconAsByteArray(notebooks.get(i).getGuid()); if (b != null) createBinaryNode("Icon", b.toHex().toString()); if (notebooks.get(i).getStack() != null && !notebooks.get(i).getStack().trim().equals("")) createTextNode("Stack", notebooks.get(i).getStack()); writer.writeEndElement(); } } } private void writeTags() { for (int i=0; i<tags.size(); i++) { if (exportableTags.containsKey(tags.get(i).getGuid()) || fullBackup) { writer.writeStartElement("Tag"); createTextNode("Guid", tags.get(i).getGuid()); createTextNode("Name", tags.get(i).getName()); createTextNode("ParentGuid", tags.get(i).getParentGuid()); createTextNode("UpdateSequenceNumber", new Long(tags.get(i).getUpdateSequenceNum()).toString()); if (dirtyTags.containsKey(tags.get(i).getGuid())) createTextNode("Dirty","true"); else createTextNode("Dirty","false"); writer.writeEndElement(); } } } private void createTextNode(String nodeName, String value) { if (value == null) value = ""; writer.writeTextElement(nodeName, value); return; } private void createBinaryNode(String nodeName, String value) { if (value == null) value = ""; logger.log(logger.EXTREME, "Writing binary node"); writer.writeStartElement(nodeName); /* int i=0; for (; i<value.length(); i+=80) { writer.writeCharacters("\n"+value.substring(i,i+80)); } writer.writeCharacters("\n"+value.substring(i)+"\n"); */ writer.writeCharacters(value); writer.writeEndElement(); return; } public String getErrorMessage() { return errorMessage; } }