gnotesyncclient.cpp 8.07 KB
Newer Older
1 2 3
/*
 * gnote
 *
4
 * Copyright (C) 2012-2014 Aurimas Cernius
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */


#ifndef _SYNCHRONIZATION_GNOTESYNCCLIENT_HPP_
#define _SYNCHRONIZATION_GNOTESYNCCLIENT_HPP_


25
#include <glibmm/i18n.h>
26 27

#include "debug.hpp"
28
#include "ignote.hpp"
29
#include "gnotesyncclient.hpp"
30
#include "notemanager.hpp"
31
#include "sharp/files.hpp"
Aurimas Černius's avatar
Aurimas Černius committed
32
#include "sharp/xmlreader.hpp"
33
#include "sharp/xmlwriter.hpp"
34 35 36 37 38 39 40


namespace gnote {
namespace sync {

  const char * GnoteSyncClient::LOCAL_MANIFEST_FILE_NAME = "manifest.xml";

41 42 43 44 45 46 47 48 49 50 51 52 53
  SyncClient::Ptr GnoteSyncClient::create(NoteManagerBase & manager)
  {
    GnoteSyncClient *ptr = new GnoteSyncClient;
    ptr->init(manager);
    return SyncClient::Ptr(ptr);
  }

  GnoteSyncClient::GnoteSyncClient()
  {
  }


  void GnoteSyncClient::init(NoteManagerBase & manager)
54
  {
55
    m_local_manifest_file_path = Glib::build_filename(IGnote::conf_dir(), LOCAL_MANIFEST_FILE_NAME);
56
    Glib::RefPtr<Gio::File> manifest = Gio::File::create_for_path(m_local_manifest_file_path);
Dominique Leuenberger's avatar
Dominique Leuenberger committed
57
    if(manifest) {
58 59 60 61
      m_file_watcher = manifest->monitor_file();
      m_file_watcher->signal_changed()
        .connect(sigc::mem_fun(*this, &GnoteSyncClient::on_changed));
    }
62 63 64

    parse(m_local_manifest_file_path);

65
    manager.signal_note_deleted
66 67 68 69
      .connect(sigc::mem_fun(*this, &GnoteSyncClient::note_deleted_handler));
  }


70
  void GnoteSyncClient::note_deleted_handler(const NoteBase::Ptr & deletedNote)
71 72 73 74 75 76 77 78
  {
    m_deleted_notes[deletedNote->id()] = deletedNote->get_title();
    m_file_revisions.erase(deletedNote->id());

    write(m_local_manifest_file_path);
  }


79 80 81 82 83 84 85
  void GnoteSyncClient::on_changed(const Glib::RefPtr<Gio::File>&, const Glib::RefPtr<Gio::File>&,
                                   Gio::FileMonitorEvent)
  {
    parse(m_local_manifest_file_path);
  }


Aurimas Černius's avatar
Aurimas Černius committed
86 87 88 89 90 91 92 93 94 95 96 97 98
  void GnoteSyncClient::read_updated_note_atts(sharp::XmlReader & reader)
  {
    std::string guid, rev;
    while(reader.move_to_next_attribute()) {
      if(reader.get_name() == "guid") {
	guid = reader.get_value();
      }
      else if(reader.get_name() == "latest-revision") {
	rev = reader.get_value();
      }
    }
    int revision = -1;
    try {
99
      revision = STRING_TO_INT(rev);
Aurimas Černius's avatar
Aurimas Černius committed
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
    }
    catch(...) {}
    if(guid != "") {
      m_file_revisions[guid] = revision;
    }
  }


  void GnoteSyncClient::read_deleted_note_atts(sharp::XmlReader & reader)
  {
    std::string guid, title;
    while(reader.move_to_next_attribute()) {
      if(reader.get_name() == "guid") {
	guid = reader.get_value();
      }
      else if(reader.get_name() == "title") {
	title = reader.get_value();
      }
    }
    if(guid != "") {
      m_deleted_notes[guid] = title;
    }
  }


  void GnoteSyncClient::read_notes(sharp::XmlReader & reader, void (GnoteSyncClient::*read_note_atts)(sharp::XmlReader&))
  {
    while(reader.read()) {
      if(reader.get_node_type() == XML_READER_TYPE_END_ELEMENT) {
	return;
      }
      if(reader.get_node_type() == XML_READER_TYPE_ELEMENT) {
	if(reader.get_name() == "note") {
	  std::string guid, rev;
	  (this->*read_note_atts)(reader);
	}
      }
    }
  }


141 142 143 144 145
  void GnoteSyncClient::parse(const std::string & manifest_path)
  {
    // Set defaults before parsing
    m_last_sync_date = sharp::DateTime::now().add_days(-1);
    m_last_sync_rev = -1;
Aurimas Černius's avatar
Aurimas Černius committed
146 147 148
    m_file_revisions.clear();
    m_deleted_notes.clear();
    m_server_id = "";
149 150 151 152 153 154

    if(!sharp::file_exists(manifest_path)) {
      m_last_sync_date = sharp::DateTime();
      write(manifest_path);
    }

Aurimas Černius's avatar
Aurimas Černius committed
155 156 157 158 159 160 161 162 163
    sharp::XmlReader reader(manifest_path);
    while(reader.read()) {
      if(reader.get_node_type() == XML_READER_TYPE_ELEMENT) {
	if(reader.get_name() == "last-sync-date") {
	  std::string value = reader.read_string();
	  try {
	    m_last_sync_date = sharp::DateTime::from_iso8601(value);
	  }
	  catch(...) {
164 165
            /* TRANSLATORS: %s is file */
	    ERR_OUT(_("Unparsable last-sync-date element in %s"), manifest_path.c_str());
166 167
	  }
	}
Aurimas Černius's avatar
Aurimas Černius committed
168 169 170
	else if(reader.get_name() == "last-sync-rev") {
	  std::string value = reader.read_string();
	  try {
171
	    m_last_sync_rev = STRING_TO_INT(value);
Aurimas Černius's avatar
Aurimas Černius committed
172 173
	  }
	  catch(...) {
174 175
            /* TRANSLATORS: %s is file */
	    ERR_OUT(_("Unparsable last-sync-rev element in %s"), manifest_path.c_str());
176 177
	  }
	}
Aurimas Černius's avatar
Aurimas Černius committed
178 179
	else if(reader.get_name() == "server-id") {
	  m_server_id = reader.read_string();
180
	}
Aurimas Černius's avatar
Aurimas Černius committed
181 182
	else if(reader.get_name() == "note-revisions") {
	  read_notes(reader, &GnoteSyncClient::read_updated_note_atts);
183
	}
Aurimas Černius's avatar
Aurimas Černius committed
184 185
	else if(reader.get_name() == "note-deletions") {
	  read_notes(reader, &GnoteSyncClient::read_deleted_note_atts);
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
	}
      }
    }
  }


  void GnoteSyncClient::write(const std::string & manifest_path)
  {
    sharp::XmlWriter xml(manifest_path);

    try {
      xml.write_start_document();
      xml.write_start_element("", "manifest", "http://beatniksoftware.com/tomboy");

      xml.write_start_element("", "last-sync-date", "");
      xml.write_string(m_last_sync_date.to_iso8601());
      xml.write_end_element();

      xml.write_start_element("", "last-sync-rev", "");
205
      xml.write_string(TO_STRING(m_last_sync_rev));
206 207 208 209 210 211 212 213 214 215 216 217
      xml.write_end_element();

      xml.write_start_element("", "server-id", "");
      xml.write_string(m_server_id);
      xml.write_end_element();

      xml.write_start_element("", "note-revisions", "");

      for(std::map<std::string, int>::iterator noteGuid = m_file_revisions.begin();
          noteGuid != m_file_revisions.end(); ++noteGuid) {
	xml.write_start_element("", "note", "");
	xml.write_attribute_string("", "guid", "", noteGuid->first);
218
	xml.write_attribute_string("", "latest-revision", "", TO_STRING(noteGuid->second));
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
	xml.write_end_element();
      }

      xml.write_end_element(); // </note-revisons>

      xml.write_start_element("", "note-deletions", "");

      for(std::map<std::string, std::string>::iterator noteGuid = m_deleted_notes.begin();
          noteGuid != m_deleted_notes.end(); ++noteGuid) {
	xml.write_start_element("", "note", "");
	xml.write_attribute_string("", "guid", "", noteGuid->first);
	xml.write_attribute_string("", "title", "", noteGuid->second);
	xml.write_end_element();
      }

      xml.write_end_element(); // </note-deletions>

      xml.write_end_element(); // </manifest>
      xml.close();
    }
    catch(...) {
      xml.close();
      throw;
    }
243 244 245 246 247 248 249 250
  }


  void GnoteSyncClient::last_sync_date(const sharp::DateTime & date)
  {
    m_last_sync_date = date;
    // If we just did a sync, we should be able to forget older deleted notes
    m_deleted_notes.clear();
251
    write(m_local_manifest_file_path);
252 253 254 255 256 257
  }


  void GnoteSyncClient::last_synchronized_revision(int revision)
  {
    m_last_sync_rev = revision;
258
    write(m_local_manifest_file_path);
259 260 261
  }


262
  int GnoteSyncClient::get_revision(const NoteBase::Ptr & note)
263 264 265 266 267 268 269 270 271 272 273 274
  {
    std::string note_guid = note->id();
    std::map<std::string, int>::const_iterator iter = m_file_revisions.find(note_guid);
    if(iter != m_file_revisions.end()) {
      return iter->second;
    }
    else {
      return -1;
    }
  }


275
  void GnoteSyncClient::set_revision(const NoteBase::Ptr & note, int revision)
276 277 278
  {
    m_file_revisions[note->id()] = revision;
    // TODO: Should we write on each of these or no?
279
    write(m_local_manifest_file_path);
280 281 282 283 284 285 286 287
  }


  void GnoteSyncClient::reset()
  {
    if(sharp::file_exists(m_local_manifest_file_path)) {
      sharp::file_delete(m_local_manifest_file_path);
    }
288
    parse(m_local_manifest_file_path);
289 290 291 292 293 294 295
  }


  void GnoteSyncClient::associated_server_id(const std::string & server_id)
  {
    if(m_server_id != server_id) {
      m_server_id = server_id;
296
      write(m_local_manifest_file_path);
297 298 299 300 301 302 303 304
    }
  }

}
}


#endif