diff --git a/CMakeLists.txt b/CMakeLists.txt index 706373b..715359f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,213 +1,213 @@ cmake_minimum_required(VERSION 2.8.5) project(Libkolabxml NONE) option( BUILD_TESTS "Build the tests" TRUE ) option( BUILD_UTILS "Build optional utils" FALSE ) option( DIST_ONLY "Build dist targets only (does not require a compiler)" FALSE ) option( PYTHON_BINDINGS "Build bindings for python" FALSE ) option( PHP_BINDINGS "Build bindings for php" FALSE ) option( CSHARP_BINDINGS "Build bindings for csharp" FALSE ) option( JAVA_BINDINGS "Build bindings for java" FALSE ) option( QT5_BUILD "Build libkolabxml using the Qt5 framework" FALSE) set(Libkolabxml_MODULE_DIR ${Libkolabxml_SOURCE_DIR}/cmake/modules) set(CMAKE_MODULE_PATH ${Libkolabxml_MODULE_DIR}) # only available from cmake-2.8.0 if(${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} GREATER 7) cmake_policy(SET CMP0012 NEW) endif() # only available from cmake-2.8.4 if(${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} GREATER 7 AND ${CMAKE_PATCH_VERSION} GREATER 3) cmake_policy(SET CMP0017 NEW) endif() # Versioning # x.y.z scheme # Development versions are only x.y # # i.e. # 0.1 (0.1 development version) # 0.1.0 (first release) # 0.1.1 (patch release for 0.1.0) # 0.2 (0.2 development version) set (Libkolabxml_VERSION_MAJOR 1) set (Libkolabxml_VERSION_MINOR 2) # Enable the full x.y.z version only for release versions set (Libkolabxml_VERSION_PATCH 1) set (Libkolabxml_VERSION "${Libkolabxml_VERSION_MAJOR}.${Libkolabxml_VERSION_MINOR}.${Libkolabxml_VERSION_PATCH}" ) #set (Libkolabxml_VERSION "${Libkolabxml_VERSION_MAJOR}.${Libkolabxml_VERSION_MINOR}" ) set (Libkolabxml_VERSION_STRING ${CMAKE_PROJECT_NAME}-${Libkolabxml_VERSION}) set (KOLAB_FORMAT_VERSION "3.1.0") message("Building DIST targets (make dist, make snapshot)") #make dist requires a tag with ${ARCHIVE_NAME} (e.g. libkolabxml-0.2.0) set(ARCHIVE_NAME ${CMAKE_PROJECT_NAME}-${Libkolabxml_VERSION}) add_custom_target(dist COMMAND git archive --prefix=${ARCHIVE_NAME}/ ${ARCHIVE_NAME} | bzip2 > ${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}.tar.bz2 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) #snapshot of current development version set(SNAPSHOTARCHIVE_NAME "${CMAKE_PROJECT_NAME}-${Libkolabxml_VERSION}-HEAD") add_custom_target(snapshot COMMAND git archive --prefix=${SNAPSHOTARCHIVE_NAME}/ HEAD | bzip2 > ${CMAKE_BINARY_DIR}/${SNAPSHOTARCHIVE_NAME}.tar.bz2 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) #It's possible to make dist targets only using: #cmake -DDIST_ONLY=TRUE .. if (DIST_ONLY) message("Building DIST targets ONLY (cmake -DDIST_ONLY=FALSE .. for full build)") return() endif() #C++ is required from here on enable_language(CXX) # Used to set installation paths include(GNUInstallDirs) set(LIB_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR} CACHE STRING "The directories where to install libraries to") set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR} CACHE STRING "The directory where to install headers to") set(INCLUDE_INSTALL_DIR ${INCLUDE_INSTALL_DIR}/kolabxml) set(CMAKECONFIG_INSTALL_DIR ${LIB_INSTALL_DIR}/cmake/Libkolabxml ) # Make relative paths absolute (needed later on) foreach(p LIB INCLUDE CMAKECONFIG) set(var ${p}_INSTALL_DIR) if(NOT IS_ABSOLUTE "${${var}}") set(${var} "${CMAKE_INSTALL_PREFIX}/${${var}}") endif() endforeach() configure_file(libkolabxml-version.h.cmake "${CMAKE_BINARY_DIR}/libkolabxml-version.h" @ONLY) set(Boost_USE_MULTITHREADED ON) find_package(Boost REQUIRED COMPONENTS thread system) if (Boost_FOUND) message("Found boost in ${Boost_INCLUDE_DIRS}") endif (Boost_FOUND) find_package(LibkolabxmlDependencies REQUIRED) # Must be after findboost set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall" ) execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) if (GCC_VERSION VERSION_GREATER 4.7 OR GCC_VERSION VERSION_EQUAL 4.7) message(STATUS "GCC Version >= 4.7, applying unqualified lookup workaround") # gcc 4.7 no longer performs unqualified lookups by default, see: http://gcc.gnu.org/gcc-4.7/porting_to.html. # This workaround is added for xsd code, which fails otherwise to compile. -fpermissive turns the errors into warnings. # It's only temporary, and should be removed once xsd is fixed. set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive" ) endif() file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/bindings) set( SCHEMA_DIR ${CMAKE_SOURCE_DIR}/schemas ) # Generate bindings # WARNING: The inclusion order in SCHEMAS matters with xerces < 3.1.0. It seems without XMLUni::fgXercesHandleMultipleImports at least kolabformat-xcard.xsd MUST be before xCard.xsd, # otherwise the compiled schema will simply lack the definitions of kolabformat-xcard.xsd (this affects xsdbin only). set( SCHEMAS ${SCHEMA_DIR}/ical/kolabformat-xcal.xsd ${SCHEMA_DIR}/ical/iCalendar-params.xsd ${SCHEMA_DIR}/ical/iCalendar-props.xsd ${SCHEMA_DIR}/ical/iCalendar-valtypes.xsd ${SCHEMA_DIR}/kolabformat-xcard.xsd ${SCHEMA_DIR}/xCard.xsd ${SCHEMA_DIR}/kolabformat.xsd ) set( SCHEMA_SOURCEFILES ${CMAKE_BINARY_DIR}/bindings/kolabformat.cxx ${CMAKE_BINARY_DIR}/bindings/xCard.cxx ${CMAKE_BINARY_DIR}/bindings/kolabformat-xcal.cxx ${CMAKE_BINARY_DIR}/bindings/kolabformat-xcard.cxx ${CMAKE_BINARY_DIR}/bindings/iCalendar-params.cxx ${CMAKE_BINARY_DIR}/bindings/iCalendar-props.cxx ${CMAKE_BINARY_DIR}/bindings/iCalendar-valtypes.cxx # bindings/iCalendar-link-extension.cxx # bindings/iCalendar-bw-extensions.cxx # bindings/iCalendar-ms-extensions.cxx ) #xsdcxx cxx-tree --generate-xml-schema --generate-serialization --custom-type date_time --hxx-epilogue '#include "bindings/customtypes/xml-schema-custom.hxx"' xml-schema.xsd # --generate-inline --extern-xml-schema xml-schema.xsd # --cxx-suffix .cpp --hxx-suffix .h add_custom_command(OUTPUT ${SCHEMA_SOURCEFILES} - COMMAND ${XSDCXX} cxx-tree --generate-polymorphic --generate-serialization --namespace-map http://kolab.org=KolabXSD --root-element icalendar --root-element vcards --root-element note --root-element configuration --root-element file --output-dir ${CMAKE_BINARY_DIR}/bindings ${SCHEMAS} + COMMAND ${XSDCXX} cxx-tree --std c++11 --generate-polymorphic --generate-serialization --namespace-map http://kolab.org=KolabXSD --root-element icalendar --root-element vcards --root-element note --root-element configuration --root-element file --output-dir ${CMAKE_BINARY_DIR}/bindings ${SCHEMAS} COMMENT "Generating XSD bindings" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} DEPENDS ${SCHEMAS} VERBATIM ) # Compile xsdbin if not found if (NOT XSDBIN_FOUND) add_executable(xsdbin compiled/xsdbin.cxx) target_link_libraries(xsdbin ${XERCES_C}) set(XSDBIN ${CMAKE_BINARY_DIR}/xsdbin) endif () # Compile Schemas add_custom_command(OUTPUT kolabformat-xcal-schema.cxx COMMAND ${XSDBIN} --verbose --array-name iCalendar_schema --output-dir ${CMAKE_BINARY_DIR} ${SCHEMAS} COMMENT "Compiling Kolab XSD schema" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} DEPENDS ${SCHEMAS} ${XSDBIN} VERBATIM ) set( SCHEMA_SOURCEFILES ${SCHEMA_SOURCEFILES} ${CMAKE_BINARY_DIR}/kolabformat-xcal-schema.cxx) # --------- SET_SOURCE_FILES_PROPERTIES(${SCHEMA_SOURCEFILES} PROPERTIES GENERATED 1) ADD_CUSTOM_TARGET(generate_bindings ALL DEPENDS ${SCHEMA_SOURCEFILES}) include_directories( ./ compiled src/containers ${CMAKE_CURRENT_BINARY_DIR} ${Boost_INCLUDE_DIRS} ${XSDCXX_INCLUDE_DIRS} ${XERCES_C_INCLUDE_DIRS} ${CURL_INCLUDE_DIRS} ) add_subdirectory(src) if (BUILD_UTILS) add_subdirectory(utils) endif() if (BUILD_TESTS) enable_testing() add_subdirectory(tests) endif() #Get the include directory relative to CMAKECONFIG_INSTALL_DIR file(RELATIVE_PATH REL_INCLUDE_DIR "${CMAKECONFIG_INSTALL_DIR}" "${INCLUDE_INSTALL_DIR}") #Assemble the full relative path. This will be used in the LibkolabxmlConfig.cmake, which will be installed in CMAKECONFIG_INSTALL_DIR set(CONF_INCLUDE_DIRS "\${Libkolabxml_CMAKE_DIR}/${REL_INCLUDE_DIR}") install(EXPORT LibkolabxmlExport DESTINATION ${CMAKECONFIG_INSTALL_DIR} FILE LibkolabxmlTargets.cmake ) configure_file(${Libkolabxml_MODULE_DIR}/LibkolabxmlConfig.cmake.in ${Libkolabxml_BINARY_DIR}/LibkolabxmlConfig.cmake @ONLY ) configure_file(${Libkolabxml_MODULE_DIR}/LibkolabxmlConfigVersion.cmake.in ${Libkolabxml_BINARY_DIR}/LibkolabxmlConfigVersion.cmake @ONLY ) # Install these two files into the same directory as the generated exports-file. install(FILES ${Libkolabxml_BINARY_DIR}/LibkolabxmlConfig.cmake ${Libkolabxml_BINARY_DIR}/LibkolabxmlConfigVersion.cmake DESTINATION ${CMAKECONFIG_INSTALL_DIR} ) diff --git a/compiled/XMLParserWrapper.cpp b/compiled/XMLParserWrapper.cpp index 96e859c..118c8cd 100644 --- a/compiled/XMLParserWrapper.cpp +++ b/compiled/XMLParserWrapper.cpp @@ -1,295 +1,295 @@ /* * Copyright (C) 2011 Christian Mollekopf * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "XMLParserWrapper.h" -#include // std::auto_ptr +#include // std::unique_ptr #include #include #include #include // chLatin_* #include #include // xercesc::Grammar #include #if _XERCES_VERSION >= 30000 # include #else # include #endif #include #include #include #include #include #include #include "kolabformat-xcal-schema.hxx" #include "grammar-input-stream.hxx" XMLParserWrapper::XMLParserWrapper() : ehp(eh), parser(0), gp(0) { // We need to initialize the Xerces-C++ runtime because we // are doing the XML-to-DOM parsing ourselves. // xercesc::XMLPlatformUtils::Initialize (); init(); } XMLParserWrapper::~XMLParserWrapper() { delete parser; delete gp; xercesc::XMLPlatformUtils::Terminate (); } boost::thread_specific_ptr ptr; XMLParserWrapper& XMLParserWrapper::inst() { XMLParserWrapper *t = ptr.get(); if (!t) { t = new XMLParserWrapper(); ptr.reset(t); } return *t; } void XMLParserWrapper::init() { using namespace std; if (parser) { return; } try { using namespace xercesc; namespace xml = xsd::cxx::xml; namespace tree = xsd::cxx::tree; // Create and load the grammar pool. // MemoryManager* mm (XMLPlatformUtils::fgMemoryManager); gp = new XMLGrammarPoolImpl (mm); try { grammar_input_stream is (iCalendar_schema, sizeof (iCalendar_schema)); gp->deserializeGrammars(&is); } catch(const XSerializationException& e) { cerr << "unable to load schema: " << xml::transcode (e.getMessage ()) << endl; return; } // Lock the grammar pool. This is necessary if we plan to use the // same grammar pool in multiple threads (this way we can reuse the // same grammar in multiple parsers). Locking the pool disallows any // modifications to the pool, such as an attempt by one of the threads // to cache additional schemas. // gp->lockPool (); // Get an implementation of the Load-Store (LS) interface. // const XMLCh ls_id [] = {chLatin_L, chLatin_S, chNull}; DOMImplementation* impl ( DOMImplementationRegistry::getDOMImplementation (ls_id)); #if _XERCES_VERSION >= 30000 // Xerces-C++ 3.0.0 and later. // parser = impl->createLSParser ( DOMImplementationLS::MODE_SYNCHRONOUS, 0, mm, gp); DOMConfiguration* conf (parser->getDomConfig ()); // Discard comment nodes in the document. // conf->setParameter (XMLUni::fgDOMComments, false); // Enable datatype normalization. // conf->setParameter (XMLUni::fgDOMDatatypeNormalization, true); // Do not create EntityReference nodes in the DOM tree. No // EntityReference nodes will be created, only the nodes // corresponding to their fully expanded substitution text // will be created. // conf->setParameter (XMLUni::fgDOMEntities, false); // Perform namespace processing. // conf->setParameter (XMLUni::fgDOMNamespaces, true); // Do not include ignorable whitespace in the DOM tree. // conf->setParameter (XMLUni::fgDOMElementContentWhitespace, false); // Enable validation. // conf->setParameter (XMLUni::fgDOMValidate, true); conf->setParameter (XMLUni::fgXercesSchema, true); conf->setParameter (XMLUni::fgXercesSchemaFullChecking, false); // Xerces-C++ 3.1.0 is the first version with working multi import // support. // #if _XERCES_VERSION >= 30100 conf->setParameter (XMLUni::fgXercesHandleMultipleImports, true); #endif // Use the loaded grammar during parsing. // conf->setParameter (XMLUni::fgXercesUseCachedGrammarInParse, true); // Disable loading schemas via other means (e.g., schemaLocation). // conf->setParameter (XMLUni::fgXercesLoadSchema, false); // We will release the DOM document ourselves. // conf->setParameter (XMLUni::fgXercesUserAdoptsDOMDocument, true); // Set error handler. // // tree::error_handler eh; // xml::dom::bits::error_handler_proxy ehp (eh); conf->setParameter (XMLUni::fgDOMErrorHandler, &ehp); //TODO does conf take a copy or should the ehp object live on? #else // _XERCES_VERSION >= 30000 // Same as above but for Xerces-C++ 2 series. // parser = impl->createDOMBuilder( DOMImplementationLS::MODE_SYNCHRONOUS, 0, mm, gp); parser->setFeature (XMLUni::fgDOMComments, false); parser->setFeature (XMLUni::fgDOMDatatypeNormalization, true); parser->setFeature (XMLUni::fgDOMEntities, false); parser->setFeature (XMLUni::fgDOMNamespaces, true); parser->setFeature (XMLUni::fgDOMWhitespaceInElementContent, false); parser->setFeature (XMLUni::fgDOMValidation, true); parser->setFeature (XMLUni::fgXercesSchema, true); parser->setFeature (XMLUni::fgXercesSchemaFullChecking, false); parser->setFeature (XMLUni::fgXercesUseCachedGrammarInParse, true); parser->setFeature (XMLUni::fgXercesUserAdoptsDOMDocument, true); //tree::error_handler eh; // xml::dom::bits::error_handler_proxy ehp (eh); parser->setErrorHandler (&ehp); #endif // _XERCES_VERSION >= 30000 // Parse XML documents. // } catch (const xml_schema::exception& e) { cout << "schema exception" << endl; cerr << e << endl; } catch (const std::ios_base::failure&) { cerr << ": unable to open or read failure" << endl; } } -xsd::cxx::xml::dom::auto_ptr< xercesc::DOMDocument > XMLParserWrapper::parseFile(const std::string& url) +std::unique_ptr< xercesc::DOMDocument > XMLParserWrapper::parseFile(const std::string& url) { try { std::ifstream ifs; ifs.exceptions (std::ifstream::badbit | std::ifstream::failbit); //TODO handle exceptions ifs.open (url.c_str()); return parse(ifs, url); } catch (const std::ios_base::failure&) { std::cerr << ": unable to open or read failure" << std::endl; } - return xsd::cxx::xml::dom::auto_ptr< xercesc::DOMDocument >(); + return std::unique_ptr< xercesc::DOMDocument >(); } -xsd::cxx::xml::dom::auto_ptr< xercesc::DOMDocument > XMLParserWrapper::parseString(const std::string& s) +std::unique_ptr< xercesc::DOMDocument > XMLParserWrapper::parseString(const std::string& s) { std::istringstream is(s); return parse(is, ""); //TODO set identifier? } -xml_schema::dom::auto_ptr XMLParserWrapper::parse(std::istream &ifs, const std::string &name) +std::unique_ptr XMLParserWrapper::parse(std::istream &ifs, const std::string &name) { using namespace std; try { using namespace xercesc; namespace xml = xsd::cxx::xml; namespace tree = xsd::cxx::tree; // Parse XML documents. // { // Wrap the standard input stream. // xml::sax::std_input_source isrc (ifs, name); Wrapper4InputSource wrap (&isrc, false); // Parse XML to DOM. // #if _XERCES_VERSION >= 30000 - xml_schema::dom::auto_ptr doc (parser->parse (&wrap)); + std::unique_ptr doc (parser->parse (&wrap)); #else - xml_schema::dom::auto_ptr doc (parser->parse (wrap)); + std::unique_ptr doc (parser->parse (wrap)); #endif eh.throw_if_failed (); return doc; } } catch (const xml_schema::exception& e) { cerr << "schema exception" << endl; cerr << e << endl; } catch (const std::ios_base::failure&) { cerr << ": unable to open or read failure" << endl; } catch (...) { cerr << ": unknown exception thrown" << endl; } eh.reset(); - return xml_schema::dom::auto_ptr(); + return std::unique_ptr(); } diff --git a/compiled/XMLParserWrapper.h b/compiled/XMLParserWrapper.h index 86a76c1..8297f52 100644 --- a/compiled/XMLParserWrapper.h +++ b/compiled/XMLParserWrapper.h @@ -1,89 +1,89 @@ /* * Copyright (C) 2011 Christian Mollekopf * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef XMLPARSER_WRAPPER_H #define XMLPARSER_WRAPPER_H #include #include #include #include #include #include #if _XERCES_VERSION >= 30000 # include # include #else # include #endif #include /** * This wrapper controls the lifetime of the parser object. * * Initializing the parser is much more expensive than parsing a single XML document, therefore the parser should be reused if possible. * * It might make sense to use a singleton internally to keep the parser alive between usages. Alternatively this object can be kept alive for as long as it makes sense. * * This class also encapsulates the initialization of the whole parser, which must be done manually because precomiled schemas are used (which greatly improves the initialization performance). * * Writing the document is static and doesn't need any initialization and is therefore not wrapped by this object. * */ class XMLParserWrapper { public: XMLParserWrapper(); ~XMLParserWrapper(); /** * Threadsafe singleton. One Xerces instance is created per thread (threadlocal). * Access via singleton to reuse parser. */ static XMLParserWrapper &inst(); - xml_schema::dom::auto_ptr parseFile(const std::string &url); - xml_schema::dom::auto_ptr parseString(const std::string &s); - xml_schema::dom::auto_ptr parse(std::istream &ifs, const std::string &name); + std::unique_ptr parseFile(const std::string &url); + std::unique_ptr parseString(const std::string &s); + std::unique_ptr parse(std::istream &ifs, const std::string &name); private: void init(); xsd::cxx::tree::error_handler eh; xsd::cxx::xml::dom::bits::error_handler_proxy ehp; #if _XERCES_VERSION >= 30000 xercesc::DOMLSParser *parser; #else xercesc::DOMBuilder *parser; #endif xercesc::XMLGrammarPool *gp; }; #endif diff --git a/compiled/xsdbin.cxx b/compiled/xsdbin.cxx index 53e2533..2249fe9 100644 --- a/compiled/xsdbin.cxx +++ b/compiled/xsdbin.cxx @@ -1,505 +1,505 @@ // file : examples/cxx/tree/embedded/xsdbin.cxx // author : Boris Kolpackov // copyright : not copyrighted - public domain // This program loads the XML Schema file(s) and converts them to // the Xerces-C++ binary schema format which can then be embedded // into C++ programs and used to validate XML documents. The output // is written as a C++ source file containing the array with the // binary data. // #include #include // std::auto_ptr #include // std::size_t #include #include #include #include #include #include #include #include #include #include #include #include #if _XERCES_VERSION >= 30000 # include #else # include #endif using namespace std; using namespace xercesc; class error_handler: public ErrorHandler { public: error_handler () : failed_ (false) { } bool failed () const { return failed_; } enum severity {s_warning, s_error, s_fatal}; virtual void warning (const SAXParseException&); virtual void error (const SAXParseException&); virtual void fatalError (const SAXParseException&); virtual void resetErrors () { failed_ = false; } void handle (const SAXParseException&, severity); private: bool failed_; }; void cxx_escape (string&); int main (int argc, char* argv[]) { const char* hxx_suffix = "-schema.hxx"; const char* cxx_suffix = "-schema.cxx"; string name; string base; string outdir; class usage {}; int argi (1); bool help (false); bool multi_import (true); bool verbose (false); try { for (; argi < argc; ++argi) { string a (argv[argi]); if (a == "--help") { help = true; throw usage (); } else if (a == "--verbose") { verbose = true; } else if (a == "--hxx-suffix") { if (++argi >= argc) throw usage (); hxx_suffix = argv[argi]; } else if (a == "--cxx-suffix") { if (++argi >= argc) throw usage (); cxx_suffix = argv[argi]; } else if (a == "--output-dir") { if (++argi >= argc) throw usage (); outdir = argv[argi]; } else if (a == "--array-name") { if (++argi >= argc) throw usage (); name = argv[argi]; } else if (a == "--disable-multi-import") { multi_import = false; } else break; } if (argi >= argc) { cerr << "no input file specified" << endl; throw usage (); } base = argv[argi]; } catch (usage const&) { cerr << "Usage: " << argv[0] << " [options] " << endl << "Options:" << endl << " --help Print usage information and exit." << endl << " --verbose Print progress information." << endl << " --output-dir Write generated files to ." << endl << " --hxx-suffix Header file suffix instead of '-schema.hxx'." << endl << " --cxx-suffix Source file suffix instead of '-schema.cxx'." << endl << " --array-name Binary data array name." << endl << " --disable-multi-import Disable multiple import support." << endl << endl; return help ? 0 : 1; } XMLPlatformUtils::Initialize (); { MemoryManager* mm (XMLPlatformUtils::fgMemoryManager); - auto_ptr gp (new XMLGrammarPoolImpl (mm)); + unique_ptr gp (new XMLGrammarPoolImpl (mm)); // Load the schemas into grammar pool. // { - auto_ptr parser ( + unique_ptr parser ( XMLReaderFactory::createXMLReader (mm, gp.get ())); parser->setFeature (XMLUni::fgSAX2CoreNameSpaces, true); parser->setFeature (XMLUni::fgSAX2CoreNameSpacePrefixes, true); parser->setFeature (XMLUni::fgSAX2CoreValidation, true); parser->setFeature (XMLUni::fgXercesSchema, true); parser->setFeature (XMLUni::fgXercesSchemaFullChecking, true); parser->setFeature (XMLUni::fgXercesValidationErrorAsFatal, true); // Xerces-C++ 3.1.0 is the first version with working multi import // support. // #if _XERCES_VERSION >= 30100 parser->setFeature (XMLUni::fgXercesHandleMultipleImports, multi_import); #endif error_handler eh; parser->setErrorHandler (&eh); for (; argi < argc; ++argi) { if (verbose) cerr << "loading " << argv[argi] << endl; if (!parser->loadGrammar (argv[argi], Grammar::SchemaGrammarType, true)) { cerr << argv[argi] << ": error: unable to load" << endl; return 1; } if (eh.failed ()) return 1; } } // Get the binary representation. // BinMemOutputStream data; try { gp->serializeGrammars (&data); } catch (const XSerializationException& e) { char* msg (XMLString::transcode (e.getMessage ())); cerr << "error: " << msg << endl; XMLString::release (&msg); return 1; } size_t n (static_cast (data.curPos ())); const unsigned char* buf ( static_cast (data.getRawBuffer ())); if (verbose) cerr << "uncomressed data size " << n << " bytes" << endl; // Compress zeros. // size_t cn (0); unsigned char* cbuf = new unsigned char[n]; size_t cseq (0); // Number of bytes left in a compression sequence. bool alt (false); // Alternating or sequential sequence. for (size_t i (0); i < n;) { unsigned char v (buf[i++]); // See if we are in a compression sequence. // if (cseq != 0) { // See if this byte needs to be copied. // if (alt && cseq % 2 == 0) cbuf[cn++] = v; cseq--; continue; } // If we are not in a compression sequence and this byte is // not zero then simply copy it. // if (v != 0) { cbuf[cn++] = v; continue; } // We have a zero. // cbuf[cn++] = 0; // See if we can start a new compression sequence. // if (i < n) { if (buf[i] == 0) { // Sequential sequence. See how far it runs. // alt = false; for (cseq = 1; cseq < 127 && cseq + i < n; cseq++) if (buf[cseq + i] != 0) break; } else if (i + 1 < n && buf[i + 1] == 0) { // Alternating sequence. See how far it runs. // alt = true; for (cseq = 1; cseq < 127 && cseq * 2 + i + 1 < n; cseq++) { if (buf[cseq * 2 + i + 1] != 0) break; // For longer sequences prefer sequential to alternating. // if (cseq > 2 && buf[cseq * 2 + i] == 0 && buf[(cseq - 1) * 2 + i] == 0 && buf[(cseq - 2) * 2 + i] == 0) { cseq -= 2; break; } } cseq *= 2; } } if (cseq != 0) { cbuf[cn++] = static_cast ( alt ? (128 | cseq / 2) : cseq); } else cbuf[cn++] = 0; } if (verbose) cerr << "comressed data size " << cn << " bytes" << endl; buf = cbuf; n = cn; // Figure out the file names. // string::size_type p (base.rfind ('/')), p1 (base.rfind ('\\')); if (p1 != string::npos && p1 > p) p = p1; if (p != string::npos) base = string (base, p + 1); p = base.rfind ('.'); if (p != string::npos) base.resize (p); string hxx (base + hxx_suffix); string cxx (base + cxx_suffix); if (!outdir.empty ()) { #if defined (WIN32) || defined (__WIN32__) hxx = outdir + '\\' + hxx; cxx = outdir + '\\' + cxx; #else hxx = outdir + '/' + hxx; cxx = outdir + '/' + cxx; #endif } if (name.empty ()) { name = base + "_schema"; cxx_escape (name); } // Write header. // { ofstream os (hxx.c_str ()); if (!os.is_open ()) { cerr << hxx << ": error: unable to open" << endl; return 1; } os << "// Automatically generated. Do not edit." << endl << "//" << endl << endl << "#include " << endl << endl << "extern const XMLByte " << name << "[" << n << "UL];" << endl; } { ofstream os (cxx.c_str ()); if (!os.is_open ()) { cerr << cxx << ": error: unable to open" << endl; return 1; } os << "// Automatically generated. Do not edit." << endl << "//" << endl << endl << "#include " << endl << "#include " << endl << endl << "#if XERCES_GRAMMAR_SERIALIZATION_LEVEL != " << XERCES_GRAMMAR_SERIALIZATION_LEVEL << endl << "# error incompatible Xerces-C++ version detected" << endl << "#endif" << endl << endl << "extern const XMLByte " << name << "[" << n << "UL] =" << endl << "{"; for (size_t i (0); i < n; ++i) { if (i != 0) os << ','; os << (i % 12 == 0 ? "\n " : " ") << "0x"; os.width (2); os.fill ('0'); os << hex << static_cast (buf[i]); } os << endl << "};" << endl << endl; } delete[] cbuf; } XMLPlatformUtils::Terminate (); } void cxx_escape (string& s) { for (string::size_type i (0); i < s.size (); ++i) { char& c (s[i]); if (i == 0) { if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_')) c = '_'; } else { if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_')) c = '_'; } } } void error_handler:: warning (const SAXParseException& e) { handle (e, s_warning); } void error_handler:: error (const SAXParseException& e) { failed_ = true; handle (e, s_error); } void error_handler:: fatalError (const SAXParseException& e) { failed_ = true; handle (e, s_fatal); } void error_handler:: handle (const SAXParseException& e, severity s) { const XMLCh* xid (e.getPublicId ()); if (xid == 0) xid = e.getSystemId (); char* id (XMLString::transcode (xid)); char* msg (XMLString::transcode (e.getMessage ())); cerr << id << ":"; #if _XERCES_VERSION >= 30000 cerr << e.getLineNumber () << ":" << e.getColumnNumber () << " "; #else XMLSSize_t l (e.getLineNumber ()); XMLSSize_t c (e.getColumnNumber ()); cerr << (l == -1 ? 0 : l) << ":" << (c == -1 ? 0 : c) << " "; #endif cerr << (s == s_warning ? "warning: " : "error: ") << msg << endl; XMLString::release (&id); XMLString::release (&msg); } diff --git a/src/kolabconversions.h b/src/kolabconversions.h index 3afc229..93e32d5 100644 --- a/src/kolabconversions.h +++ b/src/kolabconversions.h @@ -1,709 +1,709 @@ /* * Copyright (C) 2012 Christian Mollekopf * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef KOLABOBJECTCONVERSION_H #define KOLABOBJECTCONVERSION_H #include #include #include #include #include #include #include "kolabcontainers.h" #include "global_definitions.h" #include "utils.h" #include "kolabnote.h" #include "shared_conversions.h" #include "kolabconfiguration.h" #include "kolabfile.h" #include "base64.h" namespace Kolab { namespace KolabObjects { const char* const KOLAB_NAMESPACE = "http://kolab.org"; const char* const BASE64 = "BASE64"; using namespace Kolab::Utils; using namespace Kolab::Shared; template std::vector toStringList(const xsd::cxx::tree::sequence &s) { std::vector d; std::copy(s.begin(), s.end(), std::back_inserter(d)); return d; } Kolab::Attachment toAttachment(KolabXSD::attachmentPropType aProp) { Kolab::Attachment a; const KolabXSD::attachmentPropType ::parameters_type ¶meters = aProp.parameters(); std::string mimetype = parameters.fmttype(); if (parameters.encoding() && (*parameters.encoding() != BASE64)) { ERROR("wrong encoding"); return Kolab::Attachment(); } if (parameters.x_label()) { a.setLabel(*parameters.x_label()); } if (mimetype.empty()) { ERROR("no mimetype"); } if (aProp.uri()) { a.setUri(*aProp.uri(), mimetype); } else if (aProp.binary()) { a.setData(base64_decode(*aProp.binary()), mimetype); } else { ERROR("not uri and no data available"); } return a; } KolabXSD::attachmentPropType fromAttachment(const Kolab::Attachment &a) { KolabXSD::attachmentPropType::parameters_type p(a.mimetype()); if (!a.label().empty()) { p.x_label(a.label()); } if (!a.data().empty()) { p.encoding(BASE64); } KolabXSD::attachmentPropType attachment(p); if (!a.uri().empty()) { attachment.uri(a.uri()); } else if (!a.data().empty()) { attachment.binary(base64_encode(reinterpret_cast(a.data().c_str()), static_cast(a.data().length()))); } else { ERROR("no uri and no data"); } return attachment; } void writeColors(KolabXSD::Configuration::categorycolor_sequence &colors, const std::vector &input) { BOOST_FOREACH (const CategoryColor &entry, input) { KolabXSD::Configuration::categorycolor_type c(entry.category()); c.color(entry.color()); writeColors(c.categorycolor(), entry.subcategories()); colors.push_back(c); } } std::vector readColors(const KolabXSD::Configuration::categorycolor_sequence &list) { std::vector colors ; BOOST_FOREACH (const KolabXSD::Configuration::categorycolor_type &entry, list) { if (!entry.color()) { ERROR("Color is missing"); continue; } CategoryColor color(entry.category()); color.setColor(*entry.color()); color.setSubcategories(readColors(entry.categorycolor())); colors.push_back(color); } return colors; } KolabXSD::Configuration::type_type getConfigurationType(Kolab::Configuration::ConfigurationType t) { switch (t) { case Kolab::Configuration::TypeDictionary: return KolabXSD::Configuration::type_type::dictionary; case Kolab::Configuration::TypeCategoryColor: return KolabXSD::Configuration::type_type::categorycolor; case Kolab::Configuration::TypeSnippet: return KolabXSD::Configuration::type_type::snippets; case Kolab::Configuration::TypeRelation: return KolabXSD::Configuration::type_type::relation; case Kolab::Configuration::TypeFileDriver: return KolabXSD::Configuration::type_type::file_driver; case Kolab::Configuration::Invalid: CRITICAL("Invalid configuration type"); } return KolabXSD::Configuration::type_type::dictionary; } template std::string serializeObject(const T &, const std::string prod = std::string()); template <> std::string serializeObject (const Kolab::Configuration &configuration, const std::string prod) { try { const std::string &uid = getUID(configuration.uid()); setCreatedUid(uid); KolabXSD::Configuration::creation_date_type created(0,0,0,0,0,0); if (configuration.created().isValid()) { created = fromDateTime(configuration.created()); } else { created = fromDateTime(timestamp()); } KolabXSD::Configuration::last_modification_date_type lastModificationDate(0,0,0,0,0,0); if (configuration.lastModified().isValid()) { lastModificationDate = fromDateTime(configuration.lastModified()); } else { // WARNING("missing last_modification_date, fallback to current timestamp"); lastModificationDate = fromDateTime(timestamp()); } KolabXSD::Configuration n(uid, getProductId(prod), created, lastModificationDate, getConfigurationType(configuration.type())); switch (configuration.type()) { case Kolab::Configuration::TypeDictionary: { const Kolab::Dictionary &dict = configuration.dictionary(); n.language(dict.language()); BOOST_FOREACH(const std::string &e, dict.entries()) { n.e().push_back(e); } } break; case Kolab::Configuration::TypeCategoryColor: writeColors(n.categorycolor(), configuration.categoryColor()); break; case Kolab::Configuration::TypeSnippet: { const Kolab::SnippetsCollection &snippets = configuration.snippets(); n.name(snippets.name()); BOOST_FOREACH(const Kolab::Snippet &s, snippets.snippets()) { KolabXSD::Snippet::textformat_type type = KolabXSD::Snippet::textformat_type::PLAIN; if (s.textType() == Snippet::HTML) { type = KolabXSD::Snippet::textformat_type::HTML; } KolabXSD::Configuration::snippet_type snippet(s.name(), s.text(), type); if (!s.shortCut().empty()) { snippet.shortcut(s.shortCut()); } n.snippet().push_back(snippet); } } break; case Kolab::Configuration::TypeRelation: { const Kolab::Relation &relation = configuration.relation(); n.name(relation.name()); if (!relation.type().empty()) { n.relationType(relation.type()); } if (!relation.color().empty()) { n.color(relation.color()); } if (!relation.iconName().empty()) { n.iconName(relation.iconName()); } if (!relation.parent().empty()) { n.parent(relation.parent()); } if (relation.priority() != 0) { n.priority(fromInt(relation.priority())); } BOOST_FOREACH(const std::string &s, relation.members()) { n.member().push_back(s); } } break; case Kolab::Configuration::TypeFileDriver: { const Kolab::FileDriver &fileDriver = configuration.fileDriver(); n.driver(fileDriver.driver()); n.title(fileDriver.title()); n.enabled(fileDriver.enabled()); KolabXSD::FileDriverSettings settings; settings.host(fileDriver.host()); settings.port(fileDriver.port()); settings.username(fileDriver.username()); settings.password(fileDriver.password()); n.settings(settings); } break; case Kolab::Configuration::Invalid: WARNING("Invalid configuration"); break; } xml_schema::namespace_infomap map; map[""].name = KOLAB_NAMESPACE; std::ostringstream ostringstream; KolabXSD::configuration(ostringstream, n, map); return ostringstream.str(); } catch (const xml_schema::exception& e) { std::cerr << e << std::endl; } catch (...) { CRITICAL("Unhandled exception"); } CRITICAL("Failed to write configuration!"); return std::string(); } template <> std::string serializeObject (const Kolab::Note ¬e, const std::string prod) { try { const std::string &uid = getUID(note.uid()); setCreatedUid(uid); KolabXSD::Note::creation_date_type created(0,0,0,0,0,0); if (note.created().isValid()) { created = fromDateTime(note.created()); } else { created = fromDateTime(timestamp()); } KolabXSD::Note::last_modification_date_type lastModificationDate(0,0,0,0,0,0); if (note.lastModified().isValid()) { lastModificationDate = fromDateTime(note.lastModified()); } else { // WARNING("missing last_modification_date, fallback to current timestamp"); lastModificationDate = fromDateTime(timestamp()); } KolabXSD::Note n(uid, getProductId(prod), created, lastModificationDate); if (!note.categories().empty()) { KolabXSD::Note::categories_sequence categories; const std::vector &l = note.categories(); BOOST_FOREACH(const std::string &c, l) { categories.push_back(c); } n.categories(categories); } switch (note.classification()) { case Kolab::ClassPublic: n.classification(KolabXSD::Note::classification_type::PUBLIC); break; case Kolab::ClassPrivate: n.classification(KolabXSD::Note::classification_type::PRIVATE); break; case Kolab::ClassConfidential: n.classification(KolabXSD::Note::classification_type::CONFIDENTIAL); break; } if (!note.attachments().empty()) { const std::vector &l = note.attachments(); BOOST_FOREACH(const Kolab::Attachment &a, l) { n.attachment().push_back(fromAttachment(a)); } } n.summary(note.summary()); n.description(note.description()); n.color(note.color()); if (!note.customProperties().empty()) { const std::vector &l = note.customProperties(); BOOST_FOREACH(const Kolab::CustomProperty &a, l) { n.x_custom().push_back(KolabXSD::CustomType(a.identifier, a.value)); } } xml_schema::namespace_infomap map; map[""].name = KOLAB_NAMESPACE; std::ostringstream ostringstream; KolabXSD::note(ostringstream, n, map); return ostringstream.str(); } catch (const xml_schema::exception& e) { std::cerr << e << std::endl; } catch (...) { CRITICAL("Unhandled exception"); } CRITICAL("Failed to write note!"); return std::string(); } template <> std::string serializeObject (const Kolab::File &file, const std::string prod) { try { const std::string &uid = getUID(file.uid()); setCreatedUid(uid); KolabXSD::File::creation_date_type created(0,0,0,0,0,0); if (file.created().isValid()) { created = fromDateTime(file.created()); } else { created = fromDateTime(timestamp()); } KolabXSD::File::last_modification_date_type lastModificationDate(0,0,0,0,0,0); if (file.lastModified().isValid()) { lastModificationDate = fromDateTime(file.lastModified()); } else { // WARNING("missing last_modification_date, fallback to current timestamp"); lastModificationDate = fromDateTime(timestamp()); } if (file.file().label().empty()) { ERROR("missing filename"); } KolabXSD::File n(uid, getProductId(prod), created, lastModificationDate, fromAttachment(file.file())); if (!file.categories().empty()) { KolabXSD::File::categories_sequence categories; const std::vector &l = file.categories(); BOOST_FOREACH(const std::string &c, l) { categories.push_back(c); } n.categories(categories); } switch (file.classification()) { case Kolab::ClassPublic: n.classification(KolabXSD::File::classification_type::PUBLIC); break; case Kolab::ClassPrivate: n.classification(KolabXSD::File::classification_type::PRIVATE); break; case Kolab::ClassConfidential: n.classification(KolabXSD::File::classification_type::CONFIDENTIAL); break; } n.note(file.note()); if (!file.customProperties().empty()) { const std::vector &l = file.customProperties(); BOOST_FOREACH(const Kolab::CustomProperty &a, l) { n.x_custom().push_back(KolabXSD::CustomType(a.identifier, a.value)); } } xml_schema::namespace_infomap map; map[""].name = KOLAB_NAMESPACE; std::ostringstream ostringstream; KolabXSD::file(ostringstream, n, map); return ostringstream.str(); } catch (const xml_schema::exception& e) { std::cerr << e << std::endl; } catch (...) { CRITICAL("Unhandled exception"); } CRITICAL("Failed to write file!"); return std::string(); } template boost::shared_ptr deserializeObject(const std::string& s, bool isUrl); template <> boost::shared_ptr deserializeObject (const std::string& s, bool isUrl) { try { - std::auto_ptr note; + std::unique_ptr note; if (isUrl) { - xsd::cxx::xml::dom::auto_ptr doc = XMLParserWrapper::inst().parseFile(s); + std::unique_ptr doc = XMLParserWrapper::inst().parseFile(s); if (doc.get()) { - note = KolabXSD::note(doc); + note = KolabXSD::note(*doc); } } else { - xsd::cxx::xml::dom::auto_ptr doc = XMLParserWrapper::inst().parseString(s); + std::unique_ptr doc = XMLParserWrapper::inst().parseString(s); if (doc.get()) { - note = KolabXSD::note(doc); + note = KolabXSD::note(*doc); } } if (!note.get()) { CRITICAL("failed to parse note!"); return boost::shared_ptr(); } boost::shared_ptr n = boost::shared_ptr(new Kolab::Note); n->setUid(note->uid()); n->setCreated(*toDate(note->creation_date())); n->setLastModified(*toDate(note->last_modification_date())); std::vector categories; std::copy(note->categories().begin(), note->categories().end(), std::back_inserter(categories)); n->setCategories(categories); if (note->classification()) { switch (*note->classification()) { case KolabXSD::Note::classification_type::PUBLIC: n->setClassification(Kolab::ClassPublic); break; case KolabXSD::Note::classification_type::PRIVATE: n->setClassification(Kolab::ClassPrivate); break; case KolabXSD::Note::classification_type::CONFIDENTIAL: n->setClassification(Kolab::ClassConfidential); break; } } if (!note->attachment().empty()) { std::vector attachments; BOOST_FOREACH(KolabXSD::Note::attachment_type &aProp, note->attachment()) { const Kolab::Attachment &a = toAttachment(aProp); if (!a.isValid()) { ERROR("invalid attachment"); continue; } attachments.push_back(a); } n->setAttachments(attachments); } if (note->summary()) { n->setSummary(*note->summary()); } if (note->description()) { n->setDescription(*note->description()); } if (note->color()) { n->setColor(*note->color()); } setProductId( note->prodid() ); // setFormatVersion( vcards->vcard().version().text() ); // global_xCardVersion = vcalendar.properties().version().text(); setKolabVersion( note->version() ); if (!note->x_custom().empty()) { std::vector customProperties; BOOST_FOREACH(const KolabXSD::CustomType &p, note->x_custom()) { customProperties.push_back(CustomProperty(p.identifier(), p.value())); } n->setCustomProperties(customProperties); } return n; } catch (const xml_schema::exception& e) { std::cerr << e << std::endl; } catch (...) { CRITICAL("Unhandled exception"); } CRITICAL("Failed to read note!"); return boost::shared_ptr(); } template <> boost::shared_ptr deserializeObject (const std::string& s, bool isUrl) { try { - std::auto_ptr configuration; + std::unique_ptr configuration; if (isUrl) { - xsd::cxx::xml::dom::auto_ptr doc = XMLParserWrapper::inst().parseFile(s); + std::unique_ptr doc = XMLParserWrapper::inst().parseFile(s); if (doc.get()) { - configuration = KolabXSD::configuration(doc); + configuration = KolabXSD::configuration(*doc); } } else { - xsd::cxx::xml::dom::auto_ptr doc = XMLParserWrapper::inst().parseString(s); + std::unique_ptr doc = XMLParserWrapper::inst().parseString(s); if (doc.get()) { - configuration = KolabXSD::configuration(doc); + configuration = KolabXSD::configuration(*doc); } } if (!configuration.get()) { CRITICAL("failed to parse configuration!"); return boost::shared_ptr(); } boost::shared_ptr n; if (configuration->type() == KolabXSD::ConfigurationType::dictionary) { std::string lang("XX"); if (configuration->language()) { lang = *configuration->language(); } else { WARNING("missing dictionary language, default to special value XX"); } Dictionary dict(lang); std::vector entries; BOOST_FOREACH (const KolabXSD::Configuration::e_type &entry, configuration->e()) { entries.push_back(entry); } dict.setEntries(entries); n = boost::shared_ptr(new Kolab::Configuration(dict)); } else if (configuration->type() == KolabXSD::ConfigurationType::categorycolor) { n = boost::shared_ptr(new Kolab::Configuration(readColors(configuration->categorycolor()))); } else if (configuration->type() == KolabXSD::ConfigurationType::snippets) { std::string name; if (configuration->name()) { name = *configuration->name(); } SnippetsCollection collection(name); std::vector snippets; BOOST_FOREACH (const KolabXSD::Configuration::snippet_type &entry, configuration->snippet()) { Snippet snippet(entry.name(), entry.text()); if (entry.textformat() == KolabXSD::textformatType::HTML) { snippet.setTextType(Snippet::HTML); } if (entry.shortcut()) { snippet.setShortCut(*entry.shortcut()); } snippets.push_back(snippet); } collection.setSnippets(snippets); n = boost::shared_ptr(new Kolab::Configuration(collection)); } else if (configuration->type() == KolabXSD::ConfigurationType::relation) { std::string name; if (configuration->name()) { name = *configuration->name(); } std::string type; if (configuration->relationType()) { type = *configuration->relationType(); } Relation relation(name, type); if (configuration->color()) { relation.setColor(*configuration->color()); } if (configuration->iconName()) { relation.setIconName(*configuration->iconName()); } if (configuration->parent()) { relation.setParent(*configuration->parent()); } if (configuration->priority()) { relation.setPriority(convertToInt(*configuration->priority())); } relation.setMembers(toStringList(configuration->member())); n = boost::shared_ptr(new Kolab::Configuration(relation)); } else if (configuration->type() == KolabXSD::ConfigurationType::file_driver) { std::string driver; if (configuration->driver()) { driver = *configuration->driver(); } std::string title; if (configuration->title()) { title = *configuration->title(); } Kolab::FileDriver fileDriver(driver, title); fileDriver.setEnabled(*configuration->enabled()); if (configuration->settings()) { fileDriver.setHost(*configuration->settings()->host()); fileDriver.setPort(convertToInt(*configuration->settings()->port())); fileDriver.setUsername(*configuration->settings()->username()); fileDriver.setPassword(*configuration->settings()->password()); } else { CRITICAL("Settings are missing"); } n = boost::shared_ptr(new Kolab::Configuration(fileDriver)); } else { CRITICAL("No valid configuration type"); } n->setUid(configuration->uid()); n->setCreated(*toDate(configuration->creation_date())); n->setLastModified(*toDate(configuration->last_modification_date())); setProductId( configuration->prodid() ); // setFormatVersion( vcards->vcard().version().text() ); // global_xCardVersion = vcalendar.properties().version().text(); setKolabVersion( configuration->version() ); return n; } catch (const xml_schema::exception& e) { std::cerr << e << std::endl; } catch (...) { CRITICAL("Unhandled exception"); } CRITICAL("Failed to read configuration!"); return boost::shared_ptr(); } template <> boost::shared_ptr deserializeObject (const std::string& s, bool isUrl) { try { - std::auto_ptr file; + std::unique_ptr file; if (isUrl) { - xsd::cxx::xml::dom::auto_ptr doc = XMLParserWrapper::inst().parseFile(s); + std::unique_ptr doc = XMLParserWrapper::inst().parseFile(s); if (doc.get()) { - file = KolabXSD::file(doc); + file = KolabXSD::file(*doc); } } else { - xsd::cxx::xml::dom::auto_ptr doc = XMLParserWrapper::inst().parseString(s); + std::unique_ptr doc = XMLParserWrapper::inst().parseString(s); if (doc.get()) { - file = KolabXSD::file(doc); + file = KolabXSD::file(*doc); } } if (!file.get()) { CRITICAL("failed to parse file!"); return boost::shared_ptr(); } boost::shared_ptr n = boost::shared_ptr(new Kolab::File); n->setUid(file->uid()); n->setCreated(*toDate(file->creation_date())); n->setLastModified(*toDate(file->last_modification_date())); std::vector categories; std::copy(file->categories().begin(), file->categories().end(), std::back_inserter(categories)); n->setCategories(categories); if (file->classification()) { switch (*file->classification()) { case KolabXSD::File::classification_type::PUBLIC: n->setClassification(Kolab::ClassPublic); break; case KolabXSD::File::classification_type::PRIVATE: n->setClassification(Kolab::ClassPrivate); break; case KolabXSD::File::classification_type::CONFIDENTIAL: n->setClassification(Kolab::ClassConfidential); break; } } const Kolab::Attachment &attachment = toAttachment(file->file()); if (attachment.label().empty()) { ERROR("Missing filename"); } if (!attachment.isValid()) { ERROR("invalid attachment"); } n->setFile(attachment); if (file->note()) { n->setNote(*file->note()); } setProductId( file->prodid() ); // setFormatVersion( vcards->vcard().version().text() ); // global_xCardVersion = vcalendar.properties().version().text(); setKolabVersion( file->version() ); if (!file->x_custom().empty()) { std::vector customProperties; BOOST_FOREACH(const KolabXSD::CustomType &p, file->x_custom()) { customProperties.push_back(CustomProperty(p.identifier(), p.value())); } n->setCustomProperties(customProperties); } return n; } catch (const xml_schema::exception& e) { std::cerr << e << std::endl; } catch (...) { CRITICAL("Unhandled exception"); } CRITICAL("Failed to read file!"); return boost::shared_ptr(); } }//Namespace } //Namespace #endif diff --git a/src/xcalconversions.h b/src/xcalconversions.h index b62a739..ae60de7 100644 --- a/src/xcalconversions.h +++ b/src/xcalconversions.h @@ -1,2025 +1,2025 @@ /* * Copyright (C) 2011 Christian Mollekopf * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef XCALCONVERSIONS_H #define XCALCONVERSIONS_H #include "global_definitions.h" #include "libkolabxml-version.h" #include #include #include #include #include #include #include #include #include #include #include "kolabcontainers.h" #include "kolabtodo.h" #include "kolabevent.h" #include "kolabjournal.h" #include #include "utils.h" #include "base64.h" #include "shared_conversions.h" namespace Kolab { namespace XCAL { const char* const XCAL_VERSION = "2.0"; const char* const XCAL_NAMESPACE = "urn:ietf:params:xml:ns:icalendar-2.0"; const char* const TZ_PREFIX = "/kolab.org/"; const char* const THISANDFUTURE = "THISANDFUTURE"; const char* const BASE64 = "BASE64"; const char* const NEEDSACTION = "NEEDS-ACTION"; const char* const COMPLETED = "COMPLETED"; const char* const COMPLETED_COMPAT = "OPAQUE"; const char* const INPROCESS = "IN-PROCESS"; const char* const CANCELLED = "CANCELLED"; const char* const TENTATIVE = "TENTATIVE"; const char* const CONFIRMED = "CONFIRMED"; const char* const DRAFT = "DRAFT"; const char* const FINAL = "FINAL"; const char* const CONFIDENTIAL = "CONFIDENTIAL"; const char* const PRIVATE = "PRIVATE"; const char* const PUBLIC = "PUBLIC"; const char* const PARTACCEPTED = "ACCEPTED"; const char* const PARTDECLINED = "DECLINED"; const char* const PARTDELEGATED = "DELEGATED"; const char* const PARTNEEDSACTION = "NEEDS-ACTION"; const char* const PARTTENTATIVE = "TENTATIVE"; const char* const PARTINPROCESS = "IN-PROCESS"; const char* const PARTCOMPLETED = "COMPLETED"; const char* const CHAIR = "CHAIR"; const char* const NONPARTICIPANT = "NON-PARTICIPANT"; const char* const OPTIONAL = "OPT-PARTICIPANT"; const char* const REQUIRED = "REQ-PARTICIPANT"; const char* const DISPLAYALARM = "DISPLAY"; const char* const EMAILALARM = "EMAIL"; const char* const AUDIOALARM = "AUDIO"; const char* const TRANSPARENT = "TRANSPARENT"; const char* const OPAQUE = "OPAQUE"; const char* const MO = "MO"; const char* const TU = "TU"; const char* const WE = "WE"; const char* const TH = "TH"; const char* const FR = "FR"; const char* const SA = "SA"; const char* const SU = "SU"; const char* const GROUP = "GROUP"; const char* const INDIVIDUAL = "INDIVIDUAL"; const char* const RESOURCE = "RESOURCE"; const char* const UNKNOWN = "UNKNOWN"; const char* const ROOM = "ROOM"; //Alarms const char* const START = "START"; const char* const END = "END"; //Freebusy const char* const BUSY = "BUSY"; const char* const BUSY_TENTATIVE = "BUSY-TENTATIVE"; const char* const BUSY_OUTOFOFFICE = "X-OUT-OF-OFFICE"; using namespace Kolab::Utils; using namespace Kolab::Shared; //=== Generic Conversions === int toInt(const icalendar_2_0::IntegerPropertyType &prop) { return convertToInt(prop.integer()); } std::vector toStringList(const icalendar_2_0::TextListPropertyType &s) { std::vector d; std::copy(s.text().begin(), s.text().end(), std::back_inserter(d)); return d; } template -std::auto_ptr fromStringList(const std::vector &list) +std::unique_ptr fromStringList(const std::vector &list) { - std::auto_ptr ptr(new T()); + std::unique_ptr ptr(new T()); std::copy(list.begin(), list.end(), std::back_inserter(ptr->text())); return ptr; } //TODO doesn't seem very useful after all, remove std::string toString(const icalendar_2_0::TextPropertyType &s) { return s.text(); } std::string fromDayPos(const Kolab::DayPos &d) { std::string s; if (d.occurence() != 0) { s.append(boost::lexical_cast(d.occurence())); } switch (d.weekday()) { case Kolab::Monday: s.append(MO); break; case Kolab::Tuesday: s.append(TU); break; case Kolab::Wednesday: s.append(WE); break; case Kolab::Thursday: s.append(TH); break; case Kolab::Friday: s.append(FR); break; case Kolab::Saturday: s.append(SA); break; case Kolab::Sunday: s.append(SU); break; } return s; } Kolab::DayPos toDayPos(const std::string &s) { std::string number; bool gotOccurrence = false; int occurrence = 0; for (std::string::const_iterator it = s.begin(); it != s.end(); it++) { switch(*it) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '+': case '-': number.push_back(*it); break; default: if (!gotOccurrence && !number.empty()) { try { occurrence = boost::lexical_cast(number); } catch(boost::bad_lexical_cast &) { ERROR("failed to convert: " + number); return DayPos(); } number.clear(); } gotOccurrence = true; number.push_back(*it); break; } } if (number == MO) { return DayPos(occurrence, Kolab::Monday); } else if (number == TU) { return DayPos(occurrence, Kolab::Tuesday); } else if (number == WE) { return DayPos(occurrence, Kolab::Wednesday); } else if (number == TH) { return DayPos(occurrence, Kolab::Thursday); } else if (number == FR) { return DayPos(occurrence, Kolab::Friday); } else if (number == SA) { return DayPos(occurrence, Kolab::Saturday); } else if (number == SU) { return DayPos(occurrence, Kolab::Sunday); } return DayPos(); } std::string fromDuration(const Kolab::Duration &d) { std::string s; if (!d.isValid()) { return s; } if (d.isNegative()) { s.push_back('-'); } s.push_back('P'); try { if (d.weeks() > 0) { s.append(boost::lexical_cast(d.weeks())); s.push_back('W'); } if (d.days() > 0) { s.append(boost::lexical_cast(d.days())); s.push_back('D'); } if (d.hours() > 0 || d.minutes() > 0 || d.seconds() > 0) { s.push_back('T'); if (d.hours() > 0) { s.append(boost::lexical_cast(d.hours())); s.push_back('H'); } if (d.minutes() > 0) { s.append(boost::lexical_cast(d.minutes())); s.push_back('M'); } if (d.seconds() > 0) { s.append(boost::lexical_cast(d.seconds())); s.push_back('S'); } } } catch(boost::bad_lexical_cast &) { ERROR("failed to convert duration"); return std::string(); } return s; } Kolab::Duration toDuration(const icalendar_2_0::DurationValueType &d) { int weeks = 0; int days = 0; int hours = 0; int minutes = 0; int seconds = 0; bool negative = false; std::string number; for (std::string::const_iterator it = d.begin(); it != d.end(); it++) { switch(*it) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': number.push_back(*it); break; case 'H': try { hours = boost::lexical_cast(number); } catch(boost::bad_lexical_cast &) { ERROR("failed to convert: " + number); return Duration(); } number.clear(); break; case 'M': try { minutes = boost::lexical_cast(number); } catch(boost::bad_lexical_cast &) { ERROR("failed to convert: " + number); return Duration(); } number.clear(); break; case 'S': try { seconds = boost::lexical_cast(number); } catch(boost::bad_lexical_cast &) { ERROR("failed to convert: " + number); return Duration(); } number.clear(); break; case 'T': break; case 'W': try { weeks = boost::lexical_cast(number); } catch(boost::bad_lexical_cast &) { ERROR("failed to convert: " + number); return Duration(); } return Duration(weeks, negative); case 'D': try { days = boost::lexical_cast(number); } catch(boost::bad_lexical_cast &) { ERROR("failed to convert: " + number); return Duration(); } number.clear(); break; case '+': break; case '-': negative = true; break; case 'P': break; default: { std::ostringstream s; s << "failed to convert duration: " << *it; ERROR(s.str()); return Duration(); } } } return Duration(days, hours, minutes, seconds, negative); } template T fromContactReference(const Kolab::ContactReference &c) { T organizer(toMailto(c.email())); typename T::parameters_type p; if (!c.name().empty()) { icalendar_2_0::CnParamType name(c.name()); p.baseParameter().push_back(name); } if (!c.uid().empty()) { icalendar_2_0::DirParamType dir(toURN(c.uid())); p.baseParameter().push_back(dir); } organizer.parameters(p); return organizer; } Kolab::ContactReference toContactReference(const icalendar_2_0::CalAddressPropertyType &cal) { const std::string &email = fromMailto(cal.cal_address());; std::string name; std::string uid; if (cal.parameters()) { for (icalendar_2_0::ArrayOfParameters::baseParameter_const_iterator it((*cal.parameters()).baseParameter().begin()); it != (*cal.parameters()).baseParameter().end(); it++) { if (const icalendar_2_0::CnParamType * tz = dynamic_cast (&*it)) { name = tz->text(); continue; } if (const icalendar_2_0::DirParamType * tz = dynamic_cast (&*it)) { uid = fromURN(tz->uri()); continue; } } } return Kolab::ContactReference(email, name, uid); } template Kolab::Attachment toAttachment(T aProp) { Kolab::Attachment a; std::string mimetype; if (aProp.parameters()) { const icalendar_2_0::AttachPropType ::parameters_type ¶meters = *aProp.parameters(); for (icalendar_2_0::AttachPropType::parameters_type::baseParameter_const_iterator it(parameters.baseParameter().begin()); it != parameters.baseParameter().end(); it++) { if (const icalendar_2_0::FmttypeParamType *p = dynamic_cast (&*it)) { mimetype = p->text(); } if (const icalendar_2_0::EncodingParamType *p = dynamic_cast (&*it)) { if (p->text() != BASE64) { ERROR("wrong encoding"); return Kolab::Attachment(); } } if (const icalendar_2_0::XlabelParamType *p = dynamic_cast (&*it)) { a.setLabel(p->text()); } } } if (aProp.uri()) { a.setUri(*aProp.uri(), mimetype); } else if (aProp.binary()) { a.setData(base64_decode(*aProp.binary()), mimetype); } else { ERROR("no uri and no data available"); } return a; } icalendar_2_0::AttachPropType fromAttachment(const Kolab::Attachment &a) { icalendar_2_0::AttachPropType attachment; icalendar_2_0::AttachPropType::parameters_type p; p.baseParameter().push_back(icalendar_2_0::FmttypeParamType(a.mimetype())); if (!a.label().empty()) { p.baseParameter().push_back(icalendar_2_0::XlabelParamType(a.label())); } if (!a.uri().empty()) { attachment.uri(a.uri()); } else if (!a.data().empty()) { attachment.binary(base64_encode(reinterpret_cast(a.data().c_str()), static_cast(a.data().length()))); p.baseParameter().push_back(icalendar_2_0::EncodingParamType(BASE64)); } else { ERROR("no uri and no data"); } attachment.parameters(p); return attachment; } //==== cDateTime ==== std::string getTimezone(const icalendar_2_0::ArrayOfParameters ¶meters) { for (icalendar_2_0::DateDatetimePropertyType::parameters_type::baseParameter_const_iterator it(parameters.baseParameter().begin()); it != parameters.baseParameter().end(); it++) { if (const icalendar_2_0::TzidParamType* tz = dynamic_cast (&*it)) { std::string tzid = tz->text(); if (tzid.find(TZ_PREFIX) != std::string::npos) { tzid.erase(0, strlen(TZ_PREFIX)); } else { WARNING("/kolab.org/ timezone prefix is missing"); } return tzid; } } return std::string(); } cDateTimePtr toDate(const icalendar_2_0::DateDatetimePropertyType &dtProperty) { cDateTimePtr date; if (dtProperty.date_time()) { date = Shared::toDate(*dtProperty.date_time()); } else if (dtProperty.date()) { date = Shared::toDate(*dtProperty.date()); } if (dtProperty.parameters()) { const std::string &tzid = getTimezone(*dtProperty.parameters()); if (tzid.size()) { date->setTimezone(tzid); } } return date; } cDateTimePtr toDate(const icalendar_2_0::UtcDatetimePropertyType &dtProperty) { cDateTimePtr date; if (dtProperty.date_time()) { date = Shared::toDate(*dtProperty.date_time()); } else { //The utc-date-time element shouldn't even exist date = cDateTimePtr(new cDateTime()); ERROR("This element shouldn't even be existing"); //TODO Implement anyways? return date; } date->setUTC(true); return date; } template -std::auto_ptr fromDate(const cDateTime &dt) +std::unique_ptr fromDate(const cDateTime &dt) { - std::auto_ptr ptr(new I); + std::unique_ptr ptr(new I); if (dt.isDateOnly()) { ptr->date(Shared::fromDate(dt)); } else { ptr->date_time(Shared::fromDateTime(dt)); const std::string &timezone = dt.timezone(); if (timezone.size() != 0) { std::string tz(TZ_PREFIX); tz.append(timezone); icalendar_2_0::TzidParamType tzidParam(tz); icalendar_2_0::ArrayOfParameters parameters; parameters.baseParameter().push_back(tzidParam); ptr->parameters(parameters); } } return ptr; } template std::vector toDateTimeList(I datelistProperty) { std::vector list; std::string tzid; if (datelistProperty.parameters()) { tzid = getTimezone(*datelistProperty.parameters()); } if (!datelistProperty.date().empty()) { BOOST_FOREACH(const xml_schema::date &d, datelistProperty.date()) { list.push_back(*Shared::toDate(d)); } } else if (!datelistProperty.date_time().empty()) { BOOST_FOREACH(const xml_schema::date_time &d, datelistProperty.date_time()) { cDateTimePtr date = Shared::toDate(d); if (tzid.size()) { date->setTimezone(tzid); } list.push_back(*date); } } return list; } template -std::auto_ptr fromDateTimeList(const std::vector &dtlist) +std::unique_ptr fromDateTimeList(const std::vector &dtlist) { - std::auto_ptr ptr(new I); + std::unique_ptr ptr(new I); BOOST_FOREACH(const cDateTime &dt, dtlist) { if (dt.isDateOnly()) { ptr->date().push_back(Shared::fromDate(dt)); } else { ptr->date_time().push_back(Shared::fromDateTime(dt)); } //TODO handle utc } if (!dtlist.empty() && !dtlist.at(0).timezone().empty()) { const std::string &timezone = dtlist.at(0).timezone(); if (timezone.size() != 0) { std::string tz(TZ_PREFIX); tz.append(timezone); icalendar_2_0::TzidParamType tzidParam(tz); icalendar_2_0::ArrayOfParameters parameters; parameters.baseParameter().push_back(tzidParam); ptr->parameters(parameters); } } return ptr; } //---- cDateTime ---- //=== Attendee === std::string mapPartStat(PartStatus status) { switch (status) { case PartAccepted: return PARTACCEPTED; case PartDeclined: return PARTDECLINED; case PartDelegated: return PARTDELEGATED; case PartNeedsAction: return PARTNEEDSACTION; case PartTentative: return PARTTENTATIVE; case PartInProcess: return PARTINPROCESS; case PartCompleted: return PARTCOMPLETED; } std::ostringstream s; s << "PartStat not handled: " << status; ERROR(s.str()); return std::string(); } PartStatus mapPartStat(const std::string &status) { if (status == PARTACCEPTED) { return PartAccepted; } else if (status == PARTDECLINED) { return PartDeclined; } else if (status == PARTDELEGATED) { return PartDelegated; } else if (status == PARTNEEDSACTION) { return PartNeedsAction; } else if (status == PARTTENTATIVE) { return PartTentative; } else if (status == PARTINPROCESS) { return PartInProcess; } else if (status == PARTCOMPLETED) { return PartCompleted; } ERROR("PartStat not handled: " + status); return PartNeedsAction; } std::string mapRole(Role status) { switch (status) { case Chair: return std::string(CHAIR); case NonParticipant: return NONPARTICIPANT; case Optional: return OPTIONAL; case Required: return REQUIRED; } std::ostringstream s; s << "Role not handled: " << status; ERROR(s.str()); return std::string(); } Role mapRole(const std::string &status) { if (status == CHAIR) { return Chair; } else if (status == NONPARTICIPANT) { return NonParticipant; } else if (status == OPTIONAL) { return Optional; } else if (status == REQUIRED) { return Required; } ERROR("Unhandled status " + status); return Required; } //---------------- //=== Recurrence Rule === - typedef std::auto_ptr RecurrencePtr; + typedef std::unique_ptr RecurrencePtr; RecurrenceRule::Frequency mapRecurrenceFrequency(const icalendar_2_0::RecurType::freq_type &freq) { using namespace icalendar_2_0; switch (freq) { case FreqRecurType::YEARLY: return RecurrenceRule::Yearly; case FreqRecurType::MONTHLY: return RecurrenceRule::Monthly; case FreqRecurType::WEEKLY: return RecurrenceRule::Weekly; case FreqRecurType::DAILY: return RecurrenceRule::Daily; case FreqRecurType::HOURLY: return RecurrenceRule::Hourly; case FreqRecurType::MINUTELY: return RecurrenceRule::Minutely; case FreqRecurType::SECONDLY: return RecurrenceRule::Secondly; } return RecurrenceRule::FreqNone; } icalendar_2_0::RecurType::freq_type mapRecurrenceFrequency(RecurrenceRule::Frequency freq) { using namespace icalendar_2_0; switch (freq) { case RecurrenceRule::Yearly: return FreqRecurType::YEARLY; case RecurrenceRule::Monthly: return FreqRecurType::MONTHLY; case RecurrenceRule::Weekly: return FreqRecurType::WEEKLY; case RecurrenceRule::Daily: return FreqRecurType::DAILY; case RecurrenceRule::Hourly: return FreqRecurType::HOURLY; case RecurrenceRule::Minutely: return FreqRecurType::MINUTELY; case RecurrenceRule::Secondly: return FreqRecurType::SECONDLY; case RecurrenceRule::FreqNone: return 0; } return 0; } static void setWeekStart(RecurrencePtr &r, const icalendar_2_0::RecurType::wkst_type &wkst) { using namespace icalendar_2_0; switch (wkst) { case WeekdayRecurType::MO: r->setWeekStart(Kolab::Monday); break; case WeekdayRecurType::TU: r->setWeekStart(Kolab::Tuesday); break; case WeekdayRecurType::WE: r->setWeekStart(Kolab::Wednesday); break; case WeekdayRecurType::TH: r->setWeekStart(Kolab::Thursday); break; case WeekdayRecurType::FR: r->setWeekStart(Kolab::Friday); break; case WeekdayRecurType::SA: r->setWeekStart(Kolab::Saturday); break; case WeekdayRecurType::SU: r->setWeekStart(Kolab::Sunday); break; } } static void setByday(RecurrencePtr &r, const icalendar_2_0::RecurType::byday_sequence &list) { std::vector by; for (icalendar_2_0::RecurType::byday_const_iterator it(list.begin()); it != list.end(); it++) { by.push_back(toDayPos(*it)); } r->setByday(by); } template std::vector bylist(const xsd::cxx::tree::sequence &list) { std::vector by; BOOST_FOREACH(const T i, list) { by.push_back(convertToInt(i)); } return by; } RecurrencePtr toRRule(const icalendar_2_0::RecurType &rrule) { using namespace icalendar_2_0; RecurrencePtr r(new RecurrenceRule()); r->setFrequency(mapRecurrenceFrequency(rrule.freq())); if (rrule.until()) { cDateTimePtr date; if ((*rrule.until()).date_time()) { date = Shared::toDate(*(*rrule.until()).date_time()); } else if ((*rrule.until()).date()) { date = Shared::toDate(*(*rrule.until()).date()); } r->setEnd(*date); } else if (rrule.count()) { r->setCount(toInt(*rrule.count())); } if (rrule.interval()) { r->setInterval(toInt(*rrule.interval())); } else { r->setInterval(1); } r->setBysecond(bylist(rrule.bysecond())); r->setByminute(bylist(rrule.byminute())); r->setByhour(bylist(rrule.byhour())); setByday(r, rrule.byday()); r->setBymonthday(bylist(rrule.bymonthday())); r->setByyearday(bylist(rrule.byyearday())); r->setByweekno(bylist(rrule.byweekno())); r->setBymonth(bylist(rrule.bymonth())); if (rrule.wkst()) { setWeekStart(r, *rrule.wkst()); } return r; } //--- Recurrence Rule --- template void setIncidenceProperties(I &inc, const T &prop) { inc.setUid(toString(prop.uid())); inc.setCreated(*toDate(prop.created())); inc.setLastModified(*toDate(prop.dtstamp())); if (prop.sequence()) { inc.setSequence(toInt(*prop.sequence())); } if (prop.class_()) { std::string string(toString(*prop.class_())); Kolab::Classification sec = ClassPublic; if (string == PRIVATE) { sec = ClassPrivate; } else if (string == CONFIDENTIAL) { sec = ClassConfidential; } inc.setClassification(sec); } if (prop.categories()) { inc.setCategories(toStringList(*prop.categories())); } if (prop.dtstart()) { const cDateTimePtr date = toDate(*prop.dtstart()); inc.setStart(*date); } if (prop.summary()) { inc.setSummary(toString(*prop.summary())); } if (prop.description()) { inc.setDescription(toString(*prop.description())); } if (prop.comment()) { inc.setComment(toString(*prop.comment())); } if (prop.status()) { const std::string &status = toString(*prop.status()); if (status == NEEDSACTION) { inc.setStatus(StatusNeedsAction); } else if (status == COMPLETED || status == COMPLETED_COMPAT) { inc.setStatus(StatusCompleted); } else if (status == INPROCESS) { inc.setStatus(StatusInProcess); } else if (status == CANCELLED) { inc.setStatus(StatusCancelled); } else if (status == TENTATIVE) { inc.setStatus(StatusTentative); } else if (status == CONFIRMED) { inc.setStatus(StatusConfirmed); } else if (status == DRAFT) { inc.setStatus(StatusDraft); } else if (status == FINAL) { inc.setStatus(StatusFinal); } else { ERROR("Unhandled status"); } } if (prop.attendee().size()) { std::vector attendees; BOOST_FOREACH(typename T::attendee_type aProp, prop.attendee()) { Kolab::Attendee a; std::string name; if (aProp.parameters()) { const icalendar_2_0::AttendeePropType::parameters_type ¶meters = *aProp.parameters(); for (icalendar_2_0::AttendeePropType::parameters_type::baseParameter_const_iterator it(parameters.baseParameter().begin()); it != parameters.baseParameter().end(); it++) { if (const icalendar_2_0::CnParamType * p = dynamic_cast (&*it)) { name = p->text(); } if (const icalendar_2_0::PartstatParamType * p = dynamic_cast (&*it)) { PartStatus s = mapPartStat(p->text()); if (s != PartNeedsAction) { a.setPartStat(s); } } if (const icalendar_2_0::RoleParamType * p = dynamic_cast (&*it)) { Role s = mapRole(p->text()); if (s != Required) { a.setRole(s); } } if (const icalendar_2_0::RsvpParamType * p = dynamic_cast (&*it)) { a.setRSVP(p->boolean()); } if (const icalendar_2_0::DelegatedToParamType * p = dynamic_cast (&*it)) { std::vector list; BOOST_FOREACH(const icalendar_2_0::CalAddressListParamType::cal_address_type &adr, p->cal_address()) { list.push_back(Shared::toContactReference(adr)); } a.setDelegatedTo(list); } if (const icalendar_2_0::DelegatedFromParamType * p = dynamic_cast (&*it)) { std::vector list; BOOST_FOREACH(const icalendar_2_0::CalAddressListParamType::cal_address_type &adr, p->cal_address()) { list.push_back(Shared::toContactReference(adr)); } a.setDelegatedFrom(list); } if (const icalendar_2_0::CutypeParamType * p = dynamic_cast (&*it)) { if (p->text() == RESOURCE) { a.setCutype(CutypeResource); } else if (p->text() == INDIVIDUAL) { a.setCutype(CutypeIndividual); } else if (p->text() == GROUP) { a.setCutype(CutypeGroup); } else if (p->text() == ROOM) { a.setCutype(CutypeGroup); } else if (p->text() == UNKNOWN) { a.setCutype(CutypeGroup); } else { WARNING("Invalid attendee cutype"); } } } } Kolab::ContactReference ref = toContactReference(aProp); a.setContact(ref); attendees.push_back(a); } inc.setAttendees(attendees); } if (prop.attach().size()) { std::vector attachments; BOOST_FOREACH(typename T::attach_type aProp, prop.attach()) { const Kolab::Attachment &a = toAttachment(aProp); if (!a.isValid()) { ERROR("invalid attachment"); continue; } attachments.push_back(a); } inc.setAttachments(attachments); } if (prop.x_custom().size()) { std::vector customProperties; BOOST_FOREACH(typename T::x_custom_type p, prop.x_custom()) { customProperties.push_back(CustomProperty(p.identifier(), p.value())); } inc.setCustomProperties(customProperties); } } template void setTodoEventProperties(I &inc, const T &prop) { if (prop.rrule()) { RecurrencePtr rrule = toRRule(prop.rrule()->recur()); inc.setRecurrenceRule(*rrule); } if (prop.rdate()) { inc.setRecurrenceDates(toDateTimeList(*prop.rdate())); if (!prop.rdate()->period().empty()) { ERROR("the period element must not be used, ignored."); } } if (prop.exdate()) { inc.setExceptionDates(toDateTimeList(*prop.exdate())); } if (prop.recurrence_id()) { bool thisandfuture = false; if (prop.recurrence_id()->parameters()) { const icalendar_2_0::RecurrenceIdPropType::parameters_type ¶meters = *prop.recurrence_id()->parameters(); for (icalendar_2_0::RecurrenceIdPropType::parameters_type::baseParameter_const_iterator it(parameters.baseParameter().begin()); it != parameters.baseParameter().end(); it++) { if (dynamic_cast (&*it)) { thisandfuture = true; } } } inc.setRecurrenceID(*toDate(*prop.recurrence_id()), thisandfuture); } if (prop.priority()) { inc.setPriority(toInt(*prop.priority())); } if (prop.location()) { inc.setLocation(toString(*prop.location())); } if (prop.organizer()) { inc.setOrganizer(toContactReference(*prop.organizer())); } if (prop.url()) { inc.setUrl((*prop.url()).uri()); } } template T fromList(const std::vector &input) { T list; BOOST_FOREACH(int i, input) { list.push_back(convertToInt(i)); } return list; } -std::auto_ptr< icalendar_2_0::RrulePropType > recurrenceProperty(const RecurrenceRule &r) +std::unique_ptr< icalendar_2_0::RrulePropType > recurrenceProperty(const RecurrenceRule &r) { using namespace icalendar_2_0; - std::auto_ptr< RrulePropType > rruleProp(new RrulePropType(mapRecurrenceFrequency(r.frequency()))); + std::unique_ptr< RrulePropType > rruleProp(new RrulePropType(mapRecurrenceFrequency(r.frequency()))); RecurPropertyType::recur_type &recur = rruleProp->recur(); const cDateTime &endDate = r.end(); if (endDate.isValid()) { RecurPropertyType::recur_type::until_type until; if (endDate.isDateOnly()) { until.date(Shared::fromDate(endDate)); } else { until.date_time(Shared::fromDateTime(endDate)); } recur.until(until); } else if (r.count() > 0) { recur.count(fromInt(r.count())); } if (r.interval() > 1) { recur.interval(fromInt(r.interval())); } if (!r.bysecond().empty()) { recur.bysecond(fromList(r.bysecond())); } if (!r.byminute().empty()) { recur.byminute(fromList(r.byminute())); } if (!r.byhour().empty()) { recur.byhour(fromList(r.byhour())); } if (!r.byday().empty()) { RecurType::byday_sequence byday; const std::vector &l = r.byday(); BOOST_FOREACH(Kolab::DayPos daypos, l) { byday.push_back(fromDayPos(daypos)); } recur.byday(byday); } if (!r.bymonthday().empty()) { recur.bymonthday(fromList(r.bymonthday())); } if (!r.byyearday().empty()) { recur.byyearday(fromList(r.byyearday())); } if (!r.byweekno().empty()) { recur.byweekno(fromList(r.byweekno())); } if (!r.bymonth().empty()) { recur.bymonth(fromList(r.bymonth())); } return rruleProp; } template void getIncidenceProperties(T &prop, const I &inc) { using namespace icalendar_2_0; typedef T properties; prop.sequence(fromInt(inc.sequence())); switch (inc.classification()) { case Kolab::ClassConfidential: prop.class_(typename properties::class_type(CONFIDENTIAL)); break; case Kolab::ClassPrivate: prop.class_(typename properties::class_type(PRIVATE)); break; case Kolab::ClassPublic: prop.class_(typename properties::class_type(PUBLIC)); break; } if (!inc.categories().empty()) { prop.categories(*fromStringList(inc.categories())); } if (inc.start().isValid()) { prop.dtstart(fromDate(inc.start())); } if (!inc.summary().empty()) { prop.summary(typename properties::summary_type(inc.summary())); } if (!inc.description().empty()) { prop.description(typename properties::description_type(inc.description())); } if (!inc.comment().empty()) { prop.comment(typename properties::comment_type(inc.comment())); } switch (inc.status()) { case StatusNeedsAction: prop.status(typename properties::status_type(NEEDSACTION)); break; case StatusCompleted: prop.status(typename properties::status_type(COMPLETED)); break; case StatusInProcess: prop.status(typename properties::status_type(INPROCESS)); break; case StatusCancelled: prop.status(typename properties::status_type(CANCELLED)); break; case StatusTentative: prop.status(typename properties::status_type(TENTATIVE)); break; case StatusConfirmed: prop.status(typename properties::status_type(CONFIRMED)); break; case StatusDraft: prop.status(typename properties::status_type(DRAFT)); break; case StatusFinal: prop.status(typename properties::status_type(FINAL)); break; case StatusUndefined: break; } if (!inc.attendees().empty()) { const std::vector &l = inc.attendees(); BOOST_FOREACH(const Kolab::Attendee &a, l) { const Kolab::ContactReference &c = a.contact(); typename properties::attendee_type attendee = fromContactReference(c); typename properties::attendee_type::parameters_type &p = *attendee.parameters(); std::string stat = mapPartStat(a.partStat()); if (!stat.empty()) { p.baseParameter().push_back(icalendar_2_0::PartstatParamType(stat)); } std::string r = mapRole(a.role()); if (!r.empty()) { p.baseParameter().push_back(icalendar_2_0::RoleParamType(r)); } if (a.rsvp()) { p.baseParameter().push_back(icalendar_2_0::RsvpParamType(true)); } if (!a.delegatedTo().empty()) { icalendar_2_0::DelegatedToParamType delegatedTo; BOOST_FOREACH(const Kolab::ContactReference &ref, a.delegatedTo()) { delegatedTo.cal_address().push_back(CalAddressListParamType::cal_address_type(toMailto(ref.email(), ref.name()))); } p.baseParameter().push_back(delegatedTo); } if (!a.delegatedFrom().empty()) { icalendar_2_0::DelegatedFromParamType delegatedFrom; BOOST_FOREACH(const Kolab::ContactReference &ref, a.delegatedFrom()) { delegatedFrom.cal_address().push_back(CalAddressListParamType::cal_address_type(toMailto(ref.email(), ref.name()))); } p.baseParameter().push_back(delegatedFrom); } if (a.cutype() != CutypeIndividual) { std::string type; switch (a.cutype()) { case CutypeGroup: type = GROUP; break; case CutypeResource: type = RESOURCE; break; case CutypeRoom: type = ROOM; break; case CutypeUnknown: type = UNKNOWN; break; case CutypeIndividual: // silence compiler warning break; } p.baseParameter().push_back(icalendar_2_0::CutypeParamType(type)); } prop.attendee().push_back(attendee); } } if (!inc.attachments().empty()) { const std::vector &l = inc.attachments(); BOOST_FOREACH(const Kolab::Attachment &a, l) { prop.attach().push_back(fromAttachment(a)); } } if (!inc.customProperties().empty()) { const std::vector &l = inc.customProperties(); BOOST_FOREACH(const Kolab::CustomProperty &a, l) { prop.x_custom().push_back(typename properties::x_custom_type(a.identifier, a.value)); } } } template void getTodoEventProperties(T &prop, const I &inc) { using namespace icalendar_2_0; typedef T properties; if (inc.recurrenceRule().isValid()) { const RecurrenceRule &r = inc.recurrenceRule(); prop.rrule(recurrenceProperty(r)); //TODO check if startdate is allDay if recurrence is allDay //TODO check if startdate matches the one of the event (it MUST) } if (!inc.recurrenceDates().empty()) { prop.rdate(fromDateTimeList(inc.recurrenceDates())); } if (!inc.exceptionDates().empty()) { prop.exdate(fromDateTimeList(inc.exceptionDates())); } if (inc.recurrenceID().isValid()) { - std::auto_ptr recurrenceId = fromDate(inc.recurrenceID()); + std::unique_ptr recurrenceId = fromDate(inc.recurrenceID()); if (inc.thisAndFuture()) { if (!recurrenceId->parameters()) { recurrenceId->parameters(typename properties::recurrence_id_type::parameters_type()); } typename properties::recurrence_id_type::parameters_type ¶meters = *recurrenceId->parameters(); //There is maybe already a timezone set icalendar_2_0::RangeParamType range(THISANDFUTURE); parameters.baseParameter().push_back(range); } - prop.recurrence_id(recurrenceId); + prop.recurrence_id(std::move(recurrenceId)); } if (inc.priority() != 0) { prop.priority(typename properties::priority_type(fromInt(inc.priority()))); } if (!inc.location().empty()) { prop.location(typename properties::location_type(inc.location())); } if (inc.organizer().isValid()) { prop.organizer(fromContactReference(inc.organizer())); } if (!inc.url().empty()) { prop.url(typename properties::url_type(inc.url())); } } //=== Alarms === template void setAlarms(typename KolabType::components_type& components, const IncidenceType &incidence) { const std::vector &alarms = incidence.alarms(); BOOST_FOREACH(const Kolab::Alarm &alarm, alarms) { typedef icalendar_2_0::ValarmType::properties_type PropType; PropType::trigger_type trigger; if (alarm.start().isValid()) { if (!alarm.start().isUTC()) { ERROR("alarm start date is not UTC but MUST be UTC"); continue; } trigger.date_time(fromDateTime(alarm.start())); } else { if (!alarm.relativeStart().isValid()) { ERROR("no start and no relativeStart"); continue; } trigger.duration(PropType::trigger_type::duration_type(fromDuration(alarm.relativeStart()))); icalendar_2_0::ArrayOfParameters parameters; if (alarm.relativeTo() == Kolab::End) { parameters.baseParameter().push_back(icalendar_2_0::RelatedParamType(END)); } else { parameters.baseParameter().push_back(icalendar_2_0::RelatedParamType(START)); } trigger.parameters(parameters); } - std::auto_ptr p; + std::unique_ptr p; switch(alarm.type()) { case Kolab::Alarm::DisplayAlarm: - p = std::auto_ptr(new PropType(PropType::action_type(DISPLAYALARM), trigger)); + p = std::unique_ptr(new PropType(PropType::action_type(DISPLAYALARM), trigger)); p->description(PropType::description_type(alarm.description())); break; case Kolab::Alarm::EMailAlarm: { - p = std::auto_ptr(new PropType(PropType::action_type(EMAILALARM), trigger)); + p = std::unique_ptr(new PropType(PropType::action_type(EMAILALARM), trigger)); p->summary(PropType::summary_type(alarm.summary())); p->description(PropType::description_type(alarm.description())); const std::vector &l = alarm.attendees(); BOOST_FOREACH(const Kolab::ContactReference &attendee, l) { p->attendee().push_back(icalendar_2_0::ContactType(toMailto(attendee.email(), attendee.name()))); } break; } case Kolab::Alarm::AudioAlarm: - p = std::auto_ptr(new PropType(PropType::action_type(AUDIOALARM), trigger)); + p = std::unique_ptr(new PropType(PropType::action_type(AUDIOALARM), trigger)); p->description(PropType::description_type(alarm.description())); if (alarm.audioFile().isValid()) { p->attach(fromAttachment(alarm.audioFile())); } break; case Kolab::Alarm::InvalidAlarm: break; } if (alarm.duration().isValid()) { p->duration(PropType::duration_type(fromDuration(alarm.duration()))); p->repeat(PropType::repeat_type(fromInt(alarm.numrepeat()))); } - components.valarm().push_back(icalendar_2_0::ValarmType(p)); + components.valarm().push_back(icalendar_2_0::ValarmType(std::move(p))); } } template void getAlarms(IncidenceType &incidence, const typename KolabType::components_type &components) { typedef icalendar_2_0::ValarmType::properties_type PropType; std::vector alarms; BOOST_FOREACH(const typename KolabType::components_type::valarm_type &valarm, components.valarm()) { const icalendar_2_0::ValarmType::properties_type &prop = valarm.properties(); Kolab::Alarm alarm; if (prop.action().text() == DISPLAYALARM) { if (!prop.description()) { ERROR("description is missing"); continue; } alarm = Kolab::Alarm((*prop.description()).text()); } else if (prop.action().text() == EMAILALARM) { std::vector attendees; if (prop.attendee().empty()) { WARNING("No receipents for email alarm"); } for (typename PropType::attendee_const_iterator at(prop.attendee().begin()); at != prop.attendee().end(); at++) { std::string name; const std::string &email = fromMailto((*at).cal_address(), name); attendees.push_back(Kolab::ContactReference(Kolab::ContactReference::EmailReference, email, name)); } if (!prop.description() || !prop.summary()) { ERROR("description or summary is missing"); continue; } alarm = Kolab::Alarm((*prop.summary()).text(), (*prop.description()).text(), attendees); } else if (prop.action().text() == AUDIOALARM) { if (prop.attach()) { const Kolab::Attachment &attach = toAttachment(*prop.attach()); if (!attach.isValid()) { ERROR("audio file is invalid"); continue; } alarm = Kolab::Alarm(attach); } else { //An audio alarm without an audio file is valid according to spec alarm = Kolab::Alarm(Kolab::Alarm::AudioAlarm); } } else { ERROR("unknown alarm type " + prop.action().text()); continue; } if (prop.trigger().date_time()) { alarm.setStart(*Shared::toDate(*prop.trigger().date_time())); if (!alarm.start().isUTC()) { ERROR("The start date time must be in UTC "); continue; } } else if (prop.trigger().duration()) { Kolab::Relative relativeTo = Kolab::Start; if (prop.trigger().parameters()) { BOOST_FOREACH(const icalendar_2_0::ArrayOfParameters::baseParameter_type ¶m, (*prop.trigger().parameters()).baseParameter()) { if (const icalendar_2_0::RelatedParamType *rel = dynamic_cast (¶m)) { if (rel->text() == START) { relativeTo = Kolab::Start; } else if (rel->text() == END) { relativeTo = Kolab::End; } else { LOG("relativeTo not specified, default to start "); } } } } alarm.setRelativeStart(toDuration(*prop.trigger().duration()), relativeTo); } else { ERROR("no duration and not starttime "); continue; } if (prop.duration()) { int repeat = 0; if (prop.repeat()) { repeat = toInt(*prop.repeat()); } alarm.setDuration(toDuration((*prop.duration()).duration()), repeat); //TODO check duration? } alarms.push_back(alarm); } incidence.setAlarms(alarms); } //--- Alarms --- ///Trait for incidence properties specialized for Event/Todo/Journal template struct IncidenceTrait; template < > struct IncidenceTrait { typedef icalendar_2_0::KolabEvent KolabType; typedef Kolab::Event IncidenceType; typedef boost::shared_ptr IncidencePtr; static void writeIncidence(icalendar_2_0::KolabEvent& vevent, const Kolab::Event &event) { KolabType::components_type eventComponents; setAlarms(eventComponents, event); if (!eventComponents.valarm().empty()) { vevent.components(eventComponents); } icalendar_2_0::KolabEvent::properties_type &prop = vevent.properties(); getIncidenceProperties(prop, event); getTodoEventProperties(prop, event); if (event.end().isValid()) { prop.dtend(fromDate(event.end())); } else if (event.duration().isValid()) { prop.duration(icalendar_2_0::KolabEvent::properties_type::duration_type(fromDuration(event.duration()))); } if (event.transparency()) { prop.transp( icalendar_2_0::KolabEvent::properties_type::transp_type(TRANSPARENT)); } } static void addIncidence(icalendar_2_0::VcalendarType::components_type &components, icalendar_2_0::KolabEvent inc) //TODO to base trait { components.vevent().push_back(inc); } static void readIncidence(Kolab::Event &event, const icalendar_2_0::KolabEvent& vevent) { const icalendar_2_0::KolabEvent::properties_type &prop = vevent.properties(); if (!prop.dtstart()) { ERROR("Start date is missing, but is mandatory for events"); } setIncidenceProperties(event, prop); setTodoEventProperties(event, prop); if (prop.dtend()) { event.setEnd(*toDate(*prop.dtend())); } else if (prop.duration()) { event.setDuration(toDuration((*prop.duration()).duration())); } if (prop.transp()) { if (toString(*prop.transp()) == TRANSPARENT) { event.setTransparency(true); } else { event.setTransparency(false); if (toString(*prop.transp()) != OPAQUE) { ERROR("wrong transparency value " + toString(*prop.transp())); } } } if (vevent.components()) { getAlarms(event, *vevent.components()); } } static icalendar_2_0::VcalendarType::components_type::vevent_const_iterator begin(const icalendar_2_0::VcalendarType::components_type &components) { return components.vevent().begin(); } static icalendar_2_0::VcalendarType::components_type::vevent_const_iterator end(const icalendar_2_0::VcalendarType::components_type &components) { return components.vevent().end(); } static IncidencePtr resolveExceptions(const std::vector &list) { IncidencePtr incidence = *list.begin(); std::vector exceptions; for (std::vector < IncidencePtr >::const_iterator it = list.begin()+1; it != list.end(); it++) { exceptions.push_back(**it); } incidence->setExceptions(exceptions); return incidence; } static void addExceptions(icalendar_2_0::VcalendarType::components_type &components, const Kolab::Event &event, KolabType::properties_type props) { BOOST_FOREACH(const Kolab::Event &exception, event.exceptions()) { KolabType ex(props); writeIncidence(ex, exception); addIncidence(components, ex); } } }; template < > struct IncidenceTrait { typedef icalendar_2_0::KolabTodo KolabType; typedef Kolab::Todo IncidenceType; typedef boost::shared_ptr IncidencePtr; static void writeIncidence(icalendar_2_0::KolabTodo& vevent, const Kolab::Todo &todo) { KolabType::components_type eventComponents; setAlarms(eventComponents, todo); if (!eventComponents.valarm().empty()) { vevent.components(eventComponents); } icalendar_2_0::KolabTodo::properties_type &prop = vevent.properties(); getIncidenceProperties(prop, todo); getTodoEventProperties(prop, todo); if (!todo.relatedTo().empty()) { icalendar_2_0::KolabTodo::properties_type::related_to_sequence list; const std::vector &l = todo.relatedTo(); BOOST_FOREACH(const std::string &relatedTo, l) { list.push_back(icalendar_2_0::KolabTodo::properties_type::related_to_type(relatedTo)); } prop.related_to(list); } if (todo.due().isValid()) { prop.due(fromDate(todo.due())); } if (todo.percentComplete() > 0) { prop.percent_complete(icalendar_2_0::KolabTodo::properties_type::percent_complete_type(fromInt(todo.percentComplete()))); } } static void addIncidence(icalendar_2_0::VcalendarType::components_type &components, icalendar_2_0::KolabTodo inc) //TODO to base trait { components.vtodo().push_back(inc); } static void readIncidence(Kolab::Todo &todo, const icalendar_2_0::KolabTodo& vevent) { const icalendar_2_0::KolabTodo::properties_type &prop = vevent.properties(); setIncidenceProperties(todo, prop); setTodoEventProperties(todo, prop); if (!prop.related_to().empty()) { BOOST_FOREACH(icalendar_2_0::KolabTodo::properties_type::related_to_type p, prop.related_to()) { todo.addRelatedTo(p.text()); } } if (prop.due()) { todo.setDue(*toDate(*prop.due())); } if (prop.percent_complete()) { todo.setPercentComplete(toInt(*prop.percent_complete())); } if (vevent.components()) { getAlarms(todo, *vevent.components()); } } static icalendar_2_0::VcalendarType::components_type::vevent_const_iterator begin(const icalendar_2_0::VcalendarType::components_type &components) { return components.vtodo().begin(); } static icalendar_2_0::VcalendarType::components_type::vevent_const_iterator end(const icalendar_2_0::VcalendarType::components_type &components) { return components.vtodo().end(); } static IncidencePtr resolveExceptions(const std::vector &list) { IncidencePtr incidence = *list.begin(); std::vector exceptions; for (std::vector < IncidencePtr >::const_iterator it = list.begin()+1; it != list.end(); it++) { exceptions.push_back(**it); } incidence->setExceptions(exceptions); return incidence; } static void addExceptions(icalendar_2_0::VcalendarType::components_type &components, const Kolab::Todo &event, KolabType::properties_type props) { BOOST_FOREACH(const Kolab::Todo &exception, event.exceptions()) { KolabType ex(props); writeIncidence(ex, exception); addIncidence(components, ex); } } }; template < > struct IncidenceTrait { typedef icalendar_2_0::KolabJournal KolabType; typedef Kolab::Journal IncidenceType; typedef boost::shared_ptr IncidencePtr; static void writeIncidence(icalendar_2_0::KolabJournal& vjournal, const Kolab::Journal &journal) { icalendar_2_0::KolabJournal::properties_type &prop = vjournal.properties(); getIncidenceProperties(prop, journal); } static void addIncidence(icalendar_2_0::VcalendarType::components_type &components, icalendar_2_0::KolabJournal inc) { components.vjournal().push_back(inc); } static void readIncidence(Kolab::Journal &journal, const icalendar_2_0::KolabJournal& vjournal) { const icalendar_2_0::KolabJournal::properties_type &prop = vjournal.properties(); setIncidenceProperties(journal, prop); } static icalendar_2_0::VcalendarType::components_type::vjournal_const_iterator begin(const icalendar_2_0::VcalendarType::components_type &components) { return components.vjournal().begin(); } static icalendar_2_0::VcalendarType::components_type::vjournal_const_iterator end(const icalendar_2_0::VcalendarType::components_type &components) { return components.vjournal().end(); } static IncidencePtr resolveExceptions(const std::vector &list) { return *list.begin(); } static void addExceptions(icalendar_2_0::VcalendarType::components_type &, const Kolab::Journal &, KolabType::properties_type) { } }; template < > struct IncidenceTrait { typedef icalendar_2_0::KolabFreebusy KolabType; typedef Kolab::Freebusy IncidenceType; typedef boost::shared_ptr IncidencePtr; static void writeIncidence(icalendar_2_0::KolabFreebusy& vfreebusy, const Kolab::Freebusy &fb) { icalendar_2_0::KolabFreebusy::properties_type &prop = vfreebusy.properties(); if (fb.start().isValid() && fb.end().isValid()) { if ((fb.start().isUTC() || fb.start().isDateOnly()) && (fb.end().isUTC() || fb.end().isDateOnly())) { prop.dtstart(fromDate(fb.start())); prop.dtend(fromDate(fb.end())); } else { WARNING("Start/end is not in UTC, but it MUST be, skipping"); } } if (fb.organizer().isValid()) { prop.organizer(fromContactReference(fb.organizer())); } if (!fb.periods().empty()) { BOOST_FOREACH (const Kolab::FreebusyPeriod &fbPeriod, fb.periods()) { icalendar_2_0::KolabFreebusy::properties_type::freebusy_type fb; icalendar_2_0::BasePropertyType::parameters_type params; std::string fbtype; switch (fbPeriod.type()) { case FreebusyPeriod::Busy: fbtype = BUSY; break; case FreebusyPeriod::Tentative: fbtype = BUSY_TENTATIVE; break; case FreebusyPeriod::OutOfOffice: fbtype = BUSY_OUTOFOFFICE; break; case FreebusyPeriod::Invalid: WARNING("Invalid fb type"); continue; } params.baseParameter().push_back(icalendar_2_0::FbtypeParamType(fbtype)); if (!fbPeriod.eventUid().empty() || fbPeriod.eventSummary().empty() || fbPeriod.eventLocation().empty()) { params.baseParameter().push_back(icalendar_2_0::XFBevent(fbPeriod.eventUid(), fbPeriod.eventSummary(), fbPeriod.eventLocation())); } fb.parameters(params); BOOST_FOREACH (const Kolab::Period &period, fbPeriod.periods()) { if (period.start.isDateOnly() || period.end.isDateOnly()) { WARNING("Period is date-only but must be date-time"); continue; } if (!period.start.isUTC() || !period.end.isUTC()) { WARNING("Period is not in UTC, but it MUST be, skipping"); continue; } icalendar_2_0::PeriodType p(Shared::fromDateTime(period.start)); p.end(Shared::fromDateTime(period.end)); fb.period().push_back(p); } prop.freebusy().push_back(fb); } } } static void addIncidence(icalendar_2_0::VcalendarType::components_type &components, icalendar_2_0::KolabFreebusy inc) { components.vfreebusy().push_back(inc); } static void readIncidence(Kolab::Freebusy &freebusy, const icalendar_2_0::KolabFreebusy& vfreebusy) { const icalendar_2_0::KolabFreebusy::properties_type &prop = vfreebusy.properties(); freebusy.setUid(toString(prop.uid())); freebusy.setTimestamp(*toDate(prop.dtstamp())); if (prop.dtstart()) { freebusy.setStart(*toDate(*prop.dtstart())); } if (prop.dtend()) { freebusy.setEnd(*toDate(*prop.dtend())); } if (prop.organizer()) { freebusy.setOrganizer(toContactReference(*prop.organizer())); } if (!prop.freebusy().empty()) { std::vector fbperiods; BOOST_FOREACH(icalendar_2_0::FreebusyPropType aProp, prop.freebusy()) { Kolab::FreebusyPeriod fbPeriod; fbPeriod.setType(Kolab::FreebusyPeriod::Busy); if (aProp.parameters()) { const icalendar_2_0::FreebusyPropType::parameters_type ¶meters = *aProp.parameters(); for (icalendar_2_0::FreebusyPropType::parameters_type::baseParameter_const_iterator it(parameters.baseParameter().begin()); it != parameters.baseParameter().end(); it++) { if (const icalendar_2_0::FbtypeParamType * p = dynamic_cast (&*it)) { if (p->text() == BUSY) { fbPeriod.setType(Kolab::FreebusyPeriod::Busy); } else if (p->text() == BUSY_OUTOFOFFICE) { fbPeriod.setType(Kolab::FreebusyPeriod::OutOfOffice); } else if (p->text() == BUSY_TENTATIVE) { fbPeriod.setType(Kolab::FreebusyPeriod::Tentative); } else { WARNING("Invalid fb type, default to busy"); } } if (const icalendar_2_0::XFBevent * p = dynamic_cast (&*it)) { fbPeriod.setEvent(p->uid(), p->summary(), p->location()); } } } std::vector periods; BOOST_FOREACH(icalendar_2_0::FreebusyPropType::period_type period, aProp.period()) { if (!period.end()) { WARNING("Period end date is required and duration is not supported, skipping period"); continue; } periods.push_back(Kolab::Period(*Shared::toDate(period.start()), *Shared::toDate(*period.end()))); } fbPeriod.setPeriods(periods); fbperiods.push_back(fbPeriod); } freebusy.setPeriods(fbperiods); } } static icalendar_2_0::VcalendarType::components_type::vfreebusy_const_iterator begin(const icalendar_2_0::VcalendarType::components_type &components) { return components.vfreebusy().begin(); } static icalendar_2_0::VcalendarType::components_type::vfreebusy_const_iterator end(const icalendar_2_0::VcalendarType::components_type &components) { return components.vfreebusy().end(); } static IncidencePtr resolveExceptions(const std::vector &list) { return *list.begin(); } static void addExceptions(icalendar_2_0::VcalendarType::components_type &, const Kolab::Freebusy &, KolabType::properties_type) { } }; //////////////////////////////////========================================= template std::string serializeIncidence(const typename T::IncidenceType &incidence, const std::string productid = std::string()) { using namespace icalendar_2_0; typedef typename T::KolabType KolabType; try { typename KolabType::properties_type::uid_type uid( getUID(incidence.uid())); setCreatedUid(uid.text()); typename KolabType::properties_type::dtstamp_type dtstamp; if (incidence.lastModified().isValid()) { dtstamp.date_time(fromDateTime(incidence.lastModified())); } else { dtstamp.date_time(fromDateTime(timestamp())); } typename KolabType::properties_type::created_type created; if (incidence.created().isValid() && !incidence.created().isDateOnly()) { created.date_time(fromDateTime(incidence.created())); } else { created.date_time(fromDateTime(timestamp())); } typename KolabType::properties_type eventProps(uid, created, dtstamp); KolabType inc(eventProps); T::writeIncidence(inc, incidence); VcalendarType::components_type components; T::addIncidence(components, inc); T::addExceptions(components, incidence, eventProps); VcalendarType::properties_type::prodid_type prodid(getProductId(productid)); VcalendarType::properties_type::version_type version(XCAL_VERSION); VcalendarType::properties_type::x_kolab_version_type x_kolab_version(KOLAB_FORMAT_VERSION); VcalendarType::properties_type properties(prodid, version, x_kolab_version); VcalendarType vcalendar(properties, components); IcalendarType icalendar(vcalendar); xml_schema::namespace_infomap map; map[""].name = XCAL_NAMESPACE; std::ostringstream ostringstream; icalendar_2_0::icalendar(ostringstream, icalendar, map); return ostringstream.str(); } catch (const xml_schema::exception&) { CRITICAL("failed to write Incidence"); } catch (...) { CRITICAL("Unhandled exception"); } return std::string(); } template typename T::IncidencePtr deserializeIncidence(const std::string& s, bool isUrl) { using namespace icalendar_2_0; typedef typename T::IncidencePtr IncidencePtr; typedef typename T::IncidenceType IncidenceType; typedef typename T::KolabType KolabType; try { - std::auto_ptr icalendar; + std::unique_ptr icalendar; if (isUrl) { - xsd::cxx::xml::dom::auto_ptr doc = XMLParserWrapper::inst().parseFile(s); + std::unique_ptr doc = XMLParserWrapper::inst().parseFile(s); if (doc.get()) { - icalendar = icalendar_2_0::icalendar(doc); + icalendar = icalendar_2_0::icalendar(*doc); } } else { - xsd::cxx::xml::dom::auto_ptr doc = XMLParserWrapper::inst().parseString(s); + std::unique_ptr doc = XMLParserWrapper::inst().parseString(s); if (doc.get()) { - icalendar = icalendar_2_0::icalendar(doc); + icalendar = icalendar_2_0::icalendar(*doc); } } - + if (!icalendar.get()) { CRITICAL("Failed to parse calendar!"); return IncidencePtr(); } const icalendar_2_0::VcalendarType &vcalendar = icalendar->vcalendar(); std::vector < IncidencePtr > incidences; for (typename xsd::cxx::tree::sequence< KolabType >::const_iterator it(T::begin(vcalendar.components())); it != T::end(vcalendar.components()); it++) { IncidencePtr e = IncidencePtr(new IncidenceType); const KolabType &event = *it; T::readIncidence(*e, event); incidences.push_back(e); } setProductId( vcalendar.properties().prodid().text() ); setXCalVersion(vcalendar.properties().version().text()); setKolabVersion( vcalendar.properties().x_kolab_version().text() ); if (incidences.empty()) { CRITICAL("no incidence in object"); return IncidencePtr(); } return T::resolveExceptions(incidences); } catch (const xml_schema::exception& e) { std::cerr << e << std::endl; } catch (...) { CRITICAL("Unhandled exception"); } CRITICAL("Failed to read incidence!"); return IncidencePtr(); } template std::string serializeFreebusy(const Kolab::Freebusy &incidence, const std::string productid = std::string()) { using namespace icalendar_2_0; typedef typename T::KolabType KolabType; try { typename KolabType::properties_type::uid_type uid( getUID(incidence.uid())); setCreatedUid(uid.text()); typename KolabType::properties_type::dtstamp_type dtstamp; dtstamp.date_time(fromDateTime(timestamp())); typename KolabType::properties_type eventProps(uid, dtstamp); KolabType inc(eventProps); T::writeIncidence(inc, incidence); VcalendarType::components_type components; T::addIncidence(components, inc); VcalendarType::properties_type::prodid_type prodid(getProductId(productid)); VcalendarType::properties_type::version_type version(XCAL_VERSION); VcalendarType::properties_type::x_kolab_version_type x_kolab_version(KOLAB_FORMAT_VERSION); VcalendarType::properties_type properties(prodid, version, x_kolab_version); VcalendarType vcalendar(properties, components); IcalendarType icalendar(vcalendar); xml_schema::namespace_infomap map; map[""].name = XCAL_NAMESPACE; std::ostringstream ostringstream; icalendar_2_0::icalendar(ostringstream, icalendar, map); return ostringstream.str(); } catch (const xml_schema::exception& e) { std::cerr << e << std::endl; } catch (...) { CRITICAL("Unhandled exception"); } CRITICAL("failed to write Incidence"); return std::string(); } } }//Namespace #endif diff --git a/src/xcardconversions.h b/src/xcardconversions.h index 4f58aab..0d9575f 100644 --- a/src/xcardconversions.h +++ b/src/xcardconversions.h @@ -1,1191 +1,1191 @@ /* * Copyright (C) 2011 Christian Mollekopf * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef KOLABXCARDCONVERSION_H #define KOLABXCARDCONVERSION_H #include #include #include #include #include #include #include "kolabcontainers.h" #include "global_definitions.h" #include "libkolabxml-version.h" #include "utils.h" #include "kolabcontact.h" #include "shared_conversions.h" namespace Kolab { namespace XCARD { const char* const XCARD_NAMESPACE = "urn:ietf:params:xml:ns:vcard-4.0"; const char* const INDIVIDUAL = "individual"; const char* const GROUP = "group"; const char* const MIME_PGP_KEYS = "application/pgp-keys"; const char* const MIME_PKCS7_MIME = "application/pkcs7-mime"; using namespace Kolab::Utils; template std::string getType(); template <> std::string getType() { return INDIVIDUAL; } template <> std::string getType() { return GROUP; } template xsd::cxx::tree::sequence fromList(const std::vector &input) { xsd::cxx::tree::sequence list; BOOST_FOREACH(const std::string &s, input) { list.push_back(T(s)); } return list; } template xsd::cxx::tree::sequence fromList(const std::vector &input, int preferredIndex) { xsd::cxx::tree::sequence list; int index = 0; BOOST_FOREACH(const std::string &s, input) { T im(s); if(preferredIndex == index) { typename T::parameters_type parameters; parameters.baseParameter().push_back(vcard_4_0::prefParamType(vcard_4_0::prefParamType::integer_default_value())); im.parameters(parameters); } index++; list.push_back(im); } return list; } template std::vector toUriList(const xsd::cxx::tree::sequence &input) { std::vector list; BOOST_FOREACH(const vcard_4_0::UriPropertyType &s, input) { list.push_back(s.uri()); } return list; } template std::vector toTextList(const xsd::cxx::tree::sequence &input) { std::vector list; BOOST_FOREACH(const vcard_4_0::TextPropertyType &s, input) { list.push_back(s.text()); } return list; } std::vector toStringList(const ::xsd::cxx::tree::sequence< ::xml_schema::string > &s) { std::vector d; std::copy(s.begin(), s.end(), std::back_inserter(d)); return d; } ::xsd::cxx::tree::sequence< ::xml_schema::string > fromStringList(const std::vector &s) { ::xsd::cxx::tree::sequence< ::xml_schema::string > d; std::copy(s.begin(), s.end(), std::back_inserter(d)); return d; } std::string fromDate(const cDateTime &dt) { if (!dt.isDateOnly()) { WARNING("fromDate called on date time value"); } std::stringstream s; s.fill('0'); s.width(4); s << dt.year(); s.width(2); s << dt.month(); s.width(2); s << dt.day(); return s.str(); } std::string fromDateTime(const cDateTime &dt) { std::stringstream s; s.fill('0'); s << std::right; s.width(4); s << dt.year(); s.width(2); s << dt.month(); s.width(2); s << dt.day(); s.width(1); if (dt.isDateOnly()) { return s.str(); } s << "T"; s.width(2); s << dt.hour(); s.width(2); s << dt.minute(); s.width(2); s << dt.second(); if (dt.isUTC()) { s << "Z"; } return s.str(); } cDateTime toDateTime(const std::string &input) { int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0; bool isUtc = false; try { year = boost::lexical_cast(input.substr(0, 4)); month = boost::lexical_cast(input.substr(4, 2)); day = boost::lexical_cast(input.substr(6, 2)); if (input.size() >= 15) { //Minimum for time if (input.at(8) != 'T') { ERROR("Wrong demiliter"); return cDateTime(); } hour = boost::lexical_cast(input.substr(9, 2)); minute = boost::lexical_cast(input.substr(11, 2)); second = boost::lexical_cast(input.substr(13, 2)); } else { if (input.size() >= 9) { ERROR("Invalid dt " + input); return cDateTime(); } return cDateTime(year, month, day); } if (input.size() >= 16) { if (input.at(15) == 'Z') { isUtc = true; } else { std::ostringstream s; s << "wrong utc char? " << input.at(15); ERROR(s.str()); return cDateTime(); } } } catch (boost::bad_lexical_cast &c) { ERROR("failed to convert: "+std::string(c.what())); return cDateTime(); } catch (...) { ERROR("failed to convert: unknown exception"); return cDateTime(); } return cDateTime(year, month, day, hour, minute, second, isUtc); } cDateTime toDateTime(const vcard_4_0::DateDatetimePropertyType &prop) { if (prop.date_time()) { return toDateTime(*prop.date_time()); } else if (prop.date()) { return toDateTime(*prop.date()); } ERROR("no date and no datetime"); return cDateTime(); } template T fromDateTime(const Kolab::cDateTime &dt) { T prop; if (dt.isDateOnly()) { prop.date(fromDate(dt)); } else { prop.date_time(fromDateTime(dt)); } return prop; } vcard_4_0::PrefTypeValueType fromCryptoPref(Kolab::Crypto::CryptoPref pref) { switch (pref) { case Kolab::Crypto::Always: return vcard_4_0::CryptoType::encryptpref_type::text_type::Always; case Kolab::Crypto::Ask: return vcard_4_0::CryptoType::encryptpref_type::text_type::Ask; case Kolab::Crypto::IfPossible: return vcard_4_0::CryptoType::encryptpref_type::text_type::IfPossible; case Kolab::Crypto::Never: return vcard_4_0::CryptoType::encryptpref_type::text_type::Never; } return vcard_4_0::CryptoType::encryptpref_type::text_type::Ask; } Kolab::Crypto::CryptoPref toCryptoPref(vcard_4_0::PrefTypeValueType pref) { switch (pref) { case vcard_4_0::CryptoType::encryptpref_type::text_type::Always: return Kolab::Crypto::Always; case vcard_4_0::CryptoType::encryptpref_type::text_type::Ask: return Kolab::Crypto::Ask; case vcard_4_0::CryptoType::encryptpref_type::text_type::IfPossible: return Kolab::Crypto::IfPossible; case vcard_4_0::CryptoType::encryptpref_type::text_type::Never: return Kolab::Crypto::Never; } return Kolab::Crypto::Ask; } vcard_4_0::relatedPropType fromRelated(const Kolab::Related &r) { using namespace vcard_4_0; vcard_4_0::relatedPropType related; if (r.type() == Kolab::Related::Uid) { related.uri(r.uri()); } else { related.text(r.text()); } if (r.relationTypes() != Kolab::Related::NoRelation) { vcard::adr_type::parameters_type::baseParameter_sequence base; vcard::adr_type::parameters_type b; vcard_4_0::typeParamType::text_sequence seq; if (r.relationTypes() & Kolab::Related::Child) { seq.push_back(TypeValueType::child); } if (r.relationTypes() & Kolab::Related::Spouse) { seq.push_back(TypeValueType::spouse); } if (r.relationTypes() & Kolab::Related::Assistant) { seq.push_back(TypeValueType::x_assistant); } if (r.relationTypes() & Kolab::Related::Manager) { seq.push_back(TypeValueType::x_manager); } if (!seq.empty()) { vcard_4_0::typeParamType type; type.text(seq); b.baseParameter().push_back(type); } related.parameters(b); } return related; } Kolab::Related toRelated(const vcard_4_0::relatedPropType &r) { Kolab::Related::DescriptionType type = Kolab::Related::Invalid; std::string textOrUri; if (r.uri()) { type = Kolab::Related::Uid; textOrUri = *r.uri(); } else if (r.text()) { type = Kolab::Related::Text; textOrUri = *r.text(); } else { ERROR("no text and no uri"); return Kolab::Related(); } Kolab::Related related(type, textOrUri); if (r.parameters()) { BOOST_FOREACH(const vcard_4_0::ArrayOfParameters::baseParameter_type ¶m, (*r.parameters()).baseParameter()) { if (const vcard_4_0::typeParamType *rel = dynamic_cast (¶m)) { int types = 0; BOOST_FOREACH(const std::string &s, rel->text()) { if (s == vcard_4_0::TypeValueType(vcard_4_0::TypeValueType::child)) { types |= Kolab::Related::Child; } if (s == vcard_4_0::TypeValueType(vcard_4_0::TypeValueType::spouse)) { types |= Kolab::Related::Spouse; } if (s == vcard_4_0::TypeValueType(vcard_4_0::TypeValueType::x_assistant)) { types |= Kolab::Related::Assistant; } if (s == vcard_4_0::TypeValueType(vcard_4_0::TypeValueType::x_manager)) { types |= Kolab::Related::Manager; } } related.setRelationTypes(types); } } } return related; } vcard_4_0::vcard::adr_type fromAddress(const Kolab::Address &address) { using namespace vcard_4_0; vcard::adr_type a(vcard::adr_type::pobox_type(std::string()/*address.pobox()*/), vcard::adr_type::ext_type(std::string()/*address.ext()*/), vcard::adr_type::street_type(address.street()), vcard::adr_type::locality_type(address.locality()), vcard::adr_type::region_type(address.region()), address.code(), vcard::adr_type::country_type(address.country()) ); vcard::adr_type::parameters_type b; if (address.types()) { vcard_4_0::typeParamType::text_sequence seq; if (address.types() & Kolab::Address::Home) { seq.push_back(TypeValueType::home); } if (address.types() & Kolab::Address::Work) { seq.push_back(TypeValueType::work); } if (!seq.empty()) { vcard_4_0::typeParamType type; type.text(seq); b.baseParameter().push_back(type); } } if (!address.label().empty()) { b.baseParameter().push_back(vcard_4_0::labelParamType(address.label())); } a.parameters(b); return a; } Kolab::Address toAddress(const vcard_4_0::vcard::adr_type &adr, bool *isPreferred = 0) { using namespace vcard_4_0; Address address; if (adr.parameters()) { BOOST_FOREACH(const vcard_4_0::ArrayOfParameters::baseParameter_type ¶m, (*adr.parameters()).baseParameter()) { if (const vcard_4_0::labelParamType *rel = dynamic_cast (¶m)) { address.setLabel(rel->text()); } else if (isPreferred && dynamic_cast (¶m)) { *isPreferred = true; } else if (const vcard_4_0::typeParamType *rel = dynamic_cast (¶m)) { int types = 0; BOOST_FOREACH(const std::string &s, rel->text()) { if (s == TypeValueType(TypeValueType::work)) { types |= Kolab::Telephone::Work; } if (s == TypeValueType(TypeValueType::home)) { types |= Kolab::Telephone::Home; } } address.setTypes(types); } } } address.setCode(adr.code()); address.setCountry(adr.country()); address.setLocality(adr.locality()); address.setRegion(adr.region()); address.setStreet(adr.street()); return address; } std::string toGeoUri(double lat, double lon) { //lexical_cast doesn't work, so we're using stringstream std::stringstream s; s << "geo:"; s.precision(15); //can't use std::numeric_limits::max_digits10 because that's c++ 0x, it should be 17, but that seems to cause rounding problems... no idea why. s << lat << ","; s.precision(15); //Needed to get the right precision somehow... s << lon; return s.str(); } bool fromGeoUri(const std::string &uri, double &lat, double &lon) { if (uri.substr(0,4) != std::string("geo:")) { WARNING("not a geo uri"); return false; } std::size_t pos1 = uri.find(","); if (pos1 == std::string::npos) { WARNING("not a valid geo uri"); return false; } lat = boost::lexical_cast(uri.substr(4, pos1-4)); lon = boost::lexical_cast(uri.substr(pos1+1, uri.size()-pos1-1)); return true; } template void writeCard(vcard_4_0::vcard &vcard, const T &); template <> void writeCard(vcard_4_0::vcard &vcard, const Kolab::Contact &contact) { using namespace vcard_4_0; if (!contact.categories().empty()) { vcard_4_0::vcard::categories_type cat; vcard_4_0::vcard::categories_type::text_sequence seq; const std::vector &l = contact.categories(); BOOST_FOREACH(const std::string &s, l) { seq.push_back(s); } cat.text(seq); vcard.categories(cat); } if (contact.nameComponents().isValid()) { const NameComponents &nc = contact.nameComponents(); vcard::n_type n; n.surname(fromStringList(nc.surnames())); n.given(fromStringList(nc.given())); n.additional(fromStringList(nc.additional())); n.prefix(fromStringList(nc.prefixes())); n.suffix(fromStringList(nc.suffixes())); vcard.n(n); } if (!contact.note().empty()) { vcard.note(vcard::note_type(contact.note())); } if (!contact.freeBusyUrl().empty()) { vcard.fburl(vcard::fburl_type(contact.freeBusyUrl())); } if (!contact.titles().empty()) { vcard.title(fromList(contact.titles())); } if (!contact.affiliations().empty()) { vcard::group_sequence affiliations; const std::vector &l = contact.affiliations(); BOOST_FOREACH(const Affiliation &a, l) { if (a == Affiliation()) { //skip empty ones LOG("skipped empty affiliation"); continue; } affiliationPropType::org_type org; org.text().push_back(a.organisation()); const std::vector &orgUnits = a.organisationalUnits(); BOOST_FOREACH(const std::string &unit, orgUnits) { org.text().push_back(unit); } vcard::group_type group(org); if (!a.logo().empty()) { group.logo(affiliationPropType::logo_type(uriInlineEncoding(a.logo(), a.logoMimetype()))); } group.role(fromList(a.roles())); const std::vector &relateds = a.relateds(); BOOST_FOREACH(const Related &rel, relateds) { group.related().push_back(fromRelated(rel)); } const std::vector
&addersses = a.addresses(); BOOST_FOREACH(const Address &adr, addersses) { group.adr().push_back(fromAddress(adr)); } affiliations.push_back(group); } vcard.group(affiliations); } if (!contact.urls().empty()) { vcard_4_0::vcard::url_sequence urls; const std::vector &l = contact.urls(); BOOST_FOREACH(const Kolab::Url &url, l) { vcard::url_type u(url.url()); if (url.type() == Kolab::Url::Blog) { vcard::adr_type::parameters_type b; vcard_4_0::typeParamType p; p.text().push_back(vcard_4_0::TypeValueType::x_blog); b.baseParameter().push_back(p); u.parameters(b); } urls.push_back(u); } vcard.url(urls); } if (!contact.addresses().empty()) { vcard::adr_sequence adrs; int index = 0; const std::vector
&l = contact.addresses(); BOOST_FOREACH(const Kolab::Address &address, l) { vcard::adr_type a = fromAddress(address); if(contact.addressPreferredIndex() == index) { if (a.parameters()) { (*a.parameters()).baseParameter().push_back(vcard_4_0::prefParamType(vcard_4_0::prefParamType::integer_default_value())); } else { vcard::adr_type::parameters_type b; b.baseParameter().push_back(vcard_4_0::prefParamType(vcard_4_0::prefParamType::integer_default_value())); a.parameters(b); } } index++; adrs.push_back(a); } vcard.adr(adrs); } if (!contact.nickNames().empty()) { vcard::nickname_type::text_sequence textsequence; const std::vector &l = contact.nickNames(); BOOST_FOREACH(const std::string &s, l) { textsequence.push_back(s); } vcard::nickname_type nickName; nickName.text(textsequence); vcard.nickname(nickName); } if (!contact.relateds().empty()) { vcard::related_sequence seq; const std::vector &l = contact.relateds(); BOOST_FOREACH(const Kolab::Related &r, l) { seq.push_back(fromRelated(r)); } vcard.related(seq); } if (contact.bDay().isValid()) { Kolab::cDateTime dt = contact.bDay(); if (dt.isUTC() || !dt.timezone().empty()) { WARNING("Must be local time, local time assumed"); dt.setUTC(false); } vcard.bday(fromDateTime(dt)); } if (contact.anniversary().isValid()) { Kolab::cDateTime dt = contact.anniversary(); if (dt.isUTC() || !dt.timezone().empty()) { WARNING("Must be local time, local time assumed"); dt.setUTC(false); } vcard.anniversary(fromDateTime(dt)); } if (!contact.photo().empty()) { vcard::photo_type photo(vcard_4_0::UriPropertyType::uri_type(uriInlineEncoding(contact.photo(), contact.photoMimetype()))); vcard.photo(photo); } if (contact.gender() != Contact::NotSet) { switch (contact.gender()) { case Contact::NotSpecified: vcard.gender(vcard::gender_type(vcard::gender_type::sex_type::empty)); break; case Contact::Male: vcard.gender(vcard::gender_type(vcard::gender_type::sex_type::M)); break; case Contact::Female: vcard.gender(vcard::gender_type(vcard::gender_type::sex_type::F)); break; case Contact::NotSet: ERROR("Unhandled gender"); } } if (!contact.languages().empty()) { vcard.lang(fromList(contact.languages())); } if (!contact.telephones().empty()) { vcard::tel_sequence seq; int index = 0; const std::vector &l = contact.telephones(); BOOST_FOREACH(const Kolab::Telephone &t, l) { vcard::tel_type tel(t.number()); vcard_4_0::typeParamType telTypeParam; if (t.types() & Kolab::Telephone::Car) { telTypeParam.text().push_back(TypeValueType::x_car); } if (t.types() & Kolab::Telephone::Cell) { telTypeParam.text().push_back(TypeValueType::cell); } if (t.types() & Kolab::Telephone::Fax) { telTypeParam.text().push_back(TypeValueType::fax); } if (t.types() & Kolab::Telephone::Home) { telTypeParam.text().push_back(TypeValueType::home); } if (t.types() & Kolab::Telephone::Work) { telTypeParam.text().push_back(TypeValueType::work); } if (t.types() & Kolab::Telephone::Text) { telTypeParam.text().push_back(TypeValueType::text); } if (t.types() & Kolab::Telephone::Voice) { telTypeParam.text().push_back(TypeValueType::voice); } if (t.types() & Kolab::Telephone::Video) { telTypeParam.text().push_back(TypeValueType::video); } if (t.types() & Kolab::Telephone::Textphone) { telTypeParam.text().push_back(TypeValueType::textphone); } if (t.types() & Kolab::Telephone::Pager) { telTypeParam.text().push_back(TypeValueType::pager); } vcard::tel_type::parameters_type params; if(contact.telephonesPreferredIndex() == index) { params.baseParameter().push_back(vcard_4_0::prefParamType(vcard_4_0::prefParamType::integer_default_value())); } index++; if (!telTypeParam.text().empty()) { params.baseParameter().push_back(telTypeParam); tel.parameters(params); } seq.push_back(tel); } vcard.tel(seq); } if (!contact.imAddresses().empty()) { vcard.impp(fromList(contact.imAddresses(), contact.imAddressPreferredIndex())); } if (!contact.emailAddresses().empty()) { vcard::email_sequence seq; int index = 0; const std::vector &l = contact.emailAddresses(); BOOST_FOREACH(const Kolab::Email &e, l) { vcard::email_type email(e.address()); vcard_4_0::typeParamType emailTypeParam; if (e.types() & Kolab::Email::Home) { emailTypeParam.text().push_back(TypeValueType::home); } if (e.types() & Kolab::Email::Work) { emailTypeParam.text().push_back(TypeValueType::work); } vcard::tel_type::parameters_type params; if (!emailTypeParam.text().empty()) { params.baseParameter().push_back(emailTypeParam); } if(contact.emailAddressPreferredIndex() == index) { params.baseParameter().push_back(vcard_4_0::prefParamType(vcard_4_0::prefParamType::integer_default_value())); } index++; if (!params.baseParameter().empty()) { email.parameters(params); } seq.push_back(email); } vcard.email(seq); } if (!contact.gpsPos().empty()) { vcard_4_0::vcard::geo_sequence list; const std::vector &l = contact.gpsPos(); BOOST_FOREACH(const Kolab::Geo &g, l) { list.push_back(vcard_4_0::vcard::geo_type(toGeoUri(g.latitude, g.longitude))); } vcard.geo(list); } if (contact.crypto().isValid()) { vcard::x_crypto_type crypto; const Kolab::Crypto &c = contact.crypto(); if (c.allowed()) { vcard::x_crypto_type::allowed_type::text_sequence seq; if (c.allowed() & Kolab::Crypto::PGPinline) { seq.push_back(vcard::x_crypto_type::allowed_type::text_type::PGP_INLINE); } if (c.allowed() & Kolab::Crypto::PGPmime) { seq.push_back(vcard::x_crypto_type::allowed_type::text_type::PGP_MIME); } if (c.allowed() & Kolab::Crypto::SMIME) { seq.push_back(vcard::x_crypto_type::allowed_type::text_type::S_MIME); } if (c.allowed() & Kolab::Crypto::SMIMEopaque) { seq.push_back(vcard::x_crypto_type::allowed_type::text_type::S_MIMEOpaque); } vcard::x_crypto_type::allowed_type allowed; allowed.text(seq); crypto.allowed(allowed); } crypto.encryptpref(fromCryptoPref(c.encryptPref())); crypto.signpref(fromCryptoPref(c.signPref())); vcard.x_crypto(crypto); } if (!contact.keys().empty()) { vcard_4_0::vcard::key_sequence keys; const std::vector &l = contact.keys(); BOOST_FOREACH (const Kolab::Key &k, l) { switch (k.type()) { case Kolab::Key::PGP: keys.push_back(vcard_4_0::keyPropType(uriInlineEncoding(k.key(), MIME_PGP_KEYS))); break; case Kolab::Key::PKCS7_MIME: keys.push_back(vcard_4_0::keyPropType(uriInlineEncoding(k.key(), MIME_PKCS7_MIME))); break; case Kolab::Key::Invalid: LOG("Invalid keytype"); break; } } if (!keys.empty()) { vcard.key(keys); } } } template <> void writeCard(vcard_4_0::vcard &vcard, const Kolab::DistList &distlist) { if (!distlist.members().empty()) { vcard_4_0::vcard::member_sequence members; const std::vector &l = distlist.members(); BOOST_FOREACH (const Kolab::ContactReference &m, l) { if (!m.uid().empty()) { members.push_back(vcard_4_0::vcard::member_type(Shared::toURN(m.uid()))); } else { members.push_back(vcard_4_0::vcard::member_type(Shared::toMailto(m.email(), m.name()))); } } vcard.member(members); } } template std::string serializeCard(const T &card, const std::string prod = std::string()) { using namespace vcard_4_0; clearErrors(); try { vcard_4_0::vcard::uid_type uid(Shared::toURN(getUID(card.uid()))); setCreatedUid(Shared::fromURN(uid.uri())); vcard_4_0::vcard::x_kolab_version_type kolab_version(KOLAB_FORMAT_VERSION); vcard_4_0::vcard::prodid_type prodid(getProductId(prod)); vcard_4_0::vcard::rev_type rev(fromDateTime(timestamp())); vcard_4_0::vcard::kind_type kind(getType()); vcard_4_0::vcard::fn_type fn(card.name()); vcard_4_0::vcard vcard(uid, kolab_version, prodid, rev, kind, fn); writeCard(vcard, card); if (!card.customProperties().empty()) { const std::vector &l = card.customProperties(); BOOST_FOREACH(const Kolab::CustomProperty &a, l) { vcard.x_custom().push_back(vcard_4_0::CustomType(a.identifier, a.value)); } } VcardsType vcards(vcard); xml_schema::namespace_infomap map; map[""].name = XCARD_NAMESPACE; std::ostringstream ostringstream; vcard_4_0::vcards(ostringstream, vcards, map); return ostringstream.str(); } catch (const xml_schema::exception& e) { std::cerr << e << std::endl; } catch (...) { CRITICAL("Unhandled exception"); } CRITICAL("Failed to write vcard!"); return std::string(); } template boost::shared_ptr readCard(const vcard_4_0::VcardsType::vcard_type &vcard); template <> boost::shared_ptr readCard (const vcard_4_0::VcardsType::vcard_type &vcard) { using namespace vcard_4_0; boost::shared_ptr contact(new Kolab::Contact); if (vcard.categories()) { contact->setCategories(toStringList((*vcard.categories()).text())); } if (vcard.n()) { NameComponents nc; nc.setSurnames(toStringList((*vcard.n()).surname())); nc.setGiven(toStringList((*vcard.n()).given())); nc.setPrefixes(toStringList((*vcard.n()).prefix())); nc.setSuffixes(toStringList((*vcard.n()).suffix())); nc.setAdditional(toStringList((*vcard.n()).additional())); contact->setNameComponents(nc); } if (vcard.note()) { contact->setNote((*vcard.note()).text()); } if (vcard.fburl()) { contact->setFreeBusyUrl((*vcard.fburl()).uri()); } if (!vcard.title().empty()) { contact->setTitles(toTextList(vcard.title())); } if (!vcard.group().empty()) { std::vector list; BOOST_FOREACH (const vcard::group_type &group, vcard.group()) { Kolab::Affiliation aff; if (!group.org().text().empty()) { aff.setOrganisation(*group.org().text().begin()); std::vector units; for ( vcard_4_0::NonEmptyTextListPropertyType::text_const_iterator it = ++group.org().text().begin(); it != group.org().text().end(); it++) { units.push_back(*it); } aff.setOrganisationalUnits(units); } else { WARNING("No org present"); } std::string mimetype; if (group.logo()) { const std::string &logo = uriInlineDecoding((*group.logo()).uri(), mimetype); aff.setLogo(logo, mimetype); } aff.setRoles(toTextList(group.role())); std::vector relateds; BOOST_FOREACH(const vcard::group_type::related_type &rel, group.related()) { relateds.push_back(toRelated(rel)); } aff.setRelateds(relateds); std::vector
addresses; BOOST_FOREACH(const vcard::group_type::adr_type &adr, group.adr()) { addresses.push_back(toAddress(adr)); } aff.setAddresses(addresses); list.push_back(aff); } contact->setAffiliations(list); } if (!vcard.url().empty()) { std::vector urls; BOOST_FOREACH(const vcard_4_0::vcard::url_type &url, vcard.url()) { if (url.parameters()) { //We have only one fixed parameter (x-blog) urls.push_back(Kolab::Url(url.uri(), Kolab::Url::Blog)); } else { urls.push_back(Kolab::Url(url.uri())); } } contact->setUrls(urls); } if (!vcard.adr().empty()) { std::vector list; int preferredIndex = -1; int index = 0; BOOST_FOREACH(const vcard::adr_type &adr, vcard.adr()) { bool isPreferred = false; const Kolab::Address &address = toAddress(adr, &isPreferred); if (isPreferred) { preferredIndex = index; } index++; list.push_back(address); } contact->setAddresses(list, preferredIndex); } if (vcard.nickname()) { contact->setNickNames(toTextList((*vcard.nickname()).text())); } if (!vcard.related().empty()) { std::vector list; BOOST_FOREACH(const vcard_4_0::vcard::related_type &r, vcard.related()) { list.push_back(toRelated(r)); } contact->setRelateds(list); } if (vcard.bday()) { contact->setBDay(toDateTime(*vcard.bday())); } if (vcard.anniversary()) { contact->setAnniversary(toDateTime(*vcard.anniversary())); } if (vcard.photo()) { std::string mimetype; const std::string decodedPhoto = uriInlineDecoding((*vcard.photo()).uri(), mimetype); contact->setPhoto(decodedPhoto, mimetype); } if (vcard.gender()) { if ((*vcard.gender()).sex() == vcard::gender_type::sex_type::empty) { contact->setGender(Kolab::Contact::NotSpecified); } else if ((*vcard.gender()).sex() == vcard::gender_type::sex_type::M) { contact->setGender(Kolab::Contact::Male); } else if ((*vcard.gender()).sex() == vcard::gender_type::sex_type::F) { contact->setGender(Kolab::Contact::Female); } } if (!vcard.lang().empty()) { std::vector list; BOOST_FOREACH(const vcard::lang_type l, vcard.lang()) { list.push_back(l.language_tag()); } contact->setLanguages(list); } if (!vcard.tel().empty()) { std::vector list; int preferredIndex = -1; int index = 0; BOOST_FOREACH(const vcard::tel_type &tel, vcard.tel()) { Kolab::Telephone telephone; if (tel.parameters()) { BOOST_FOREACH(const vcard_4_0::ArrayOfParameters::baseParameter_type ¶m, (*tel.parameters()).baseParameter()) { if (dynamic_cast (¶m)) { preferredIndex = index; } else if (const vcard_4_0::typeParamType *rel = dynamic_cast (¶m)) { int types = 0; BOOST_FOREACH(const std::string &s, rel->text()) { if (s == TypeValueType(TypeValueType::work)) { types |= Kolab::Telephone::Work; } if (s == TypeValueType(TypeValueType::home)) { types |= Kolab::Telephone::Home; } if (s == TypeValueType(TypeValueType::text)) { types |= Kolab::Telephone::Text; } if (s == TypeValueType(TypeValueType::voice)) { types |= Kolab::Telephone::Voice; } if (s == TypeValueType(TypeValueType::fax)) { types |= Kolab::Telephone::Fax; } if (s == TypeValueType(TypeValueType::cell)) { types |= Kolab::Telephone::Cell; } if (s == TypeValueType(TypeValueType::video)) { types |= Kolab::Telephone::Video; } if (s == TypeValueType(TypeValueType::pager)) { types |= Kolab::Telephone::Pager; } if (s == TypeValueType(TypeValueType::textphone)) { types |= Kolab::Telephone::Textphone; } if (s == TypeValueType(TypeValueType::x_car)) { types |= Kolab::Telephone::Car; } } telephone.setTypes(types); } } } index++; telephone.setNumber(tel.text()); list.push_back(telephone); } contact->setTelephones(list, preferredIndex); } if (!vcard.impp().empty()) { int preferredIndex = -1; std::vector list; int i = 0; BOOST_FOREACH(const vcard_4_0::UriPropertyType &s, vcard.impp()) { if (s.parameters()) { BOOST_FOREACH(const vcard_4_0::ArrayOfParameters::baseParameter_type ¶m, (*s.parameters()).baseParameter()) { if (dynamic_cast (¶m)) { preferredIndex = i; } } } i++; list.push_back(s.uri()); } contact->setIMaddresses(list, preferredIndex); } if (!vcard.email().empty()) { int preferredIndex = -1; std::vector list; int i = 0; BOOST_FOREACH(const vcard_4_0::TextPropertyType &s, vcard.email()) { Kolab::Email email; if (s.parameters()) { BOOST_FOREACH(const vcard_4_0::ArrayOfParameters::baseParameter_type ¶m, (*s.parameters()).baseParameter()) { if (dynamic_cast (¶m)) { preferredIndex = i; } else if (const vcard_4_0::typeParamType *rel = dynamic_cast (¶m)) { int types = 0; BOOST_FOREACH(const std::string &s, rel->text()) { if (s == TypeValueType(TypeValueType::work)) { types |= Kolab::Email::Work; } if (s == TypeValueType(TypeValueType::home)) { types |= Kolab::Email::Home; } } email.setTypes(types); } } } i++; email.setAddress(s.text()); list.push_back(email); } contact->setEmailAddresses(list, preferredIndex); } if (!vcard.geo().empty()) { std::vector list; BOOST_FOREACH(const vcard_4_0::geoPropType &s, vcard.geo()) { double lon = 0.0; double lat = 0.0; if (fromGeoUri(s.uri(), lat, lon)) { list.push_back(Kolab::Geo(lat, lon)); } } contact->setGPSpos(list); } if (vcard.x_crypto()) { const vcard_4_0::vcard::x_crypto_type &crypto = *vcard.x_crypto(); Kolab::Crypto c; if (crypto.allowed()) { int allowed = 0; BOOST_FOREACH(const vcard_4_0::vcard::x_crypto_type::allowed_type::text_type &m, crypto.allowed()->text()) { if (m == vcard::x_crypto_type::allowed_type::text_type::PGP_INLINE) { allowed |= Kolab::Crypto::PGPinline; } else if (m == vcard::x_crypto_type::allowed_type::text_type::PGP_MIME) { allowed |= Kolab::Crypto::PGPmime; } else if (m == vcard::x_crypto_type::allowed_type::text_type::S_MIME) { allowed |= Kolab::Crypto::SMIME; } else if (m == vcard::x_crypto_type::allowed_type::text_type::S_MIMEOpaque) { allowed |= Kolab::Crypto::SMIMEopaque; } else { WARNING("unknown allowed property"); } } c.setAllowed(allowed); } if (crypto.encryptpref()) { c.setEncryptPref(toCryptoPref(crypto.encryptpref()->text())); } if (crypto.signpref()) { c.setSignPref(toCryptoPref(crypto.signpref()->text())); } contact->setCrypto(c); } if (!vcard.key().empty()) { std::string mimetype; std::vector keys; BOOST_FOREACH(const vcard_4_0::keyPropType &k, vcard.key()) { const std::string &key = uriInlineDecoding(k.uri(), mimetype); if (mimetype == MIME_PGP_KEYS) { keys.push_back(Kolab::Key(key, Kolab::Key::PGP)); } else if (mimetype == MIME_PKCS7_MIME) { keys.push_back(Kolab::Key(key, Kolab::Key::PKCS7_MIME)); } else { WARNING("wrong mimetype on key"); } } contact->setKeys(keys); } return contact; } template <> boost::shared_ptr readCard (const vcard_4_0::VcardsType::vcard_type &vcard) { using namespace vcard_4_0; boost::shared_ptr distlist(new Kolab::DistList); if (!vcard.member().empty()) { std::vector members; BOOST_FOREACH(const vcard_4_0::vcard::member_type & m, vcard.member()) { members.push_back(Shared::toContactReference(m.uri())); } distlist->setMembers(members); } return distlist; } template boost::shared_ptr deserializeCard(const std::string& s, bool isUrl) { clearErrors(); try { - std::auto_ptr vcards; + std::unique_ptr vcards; if (isUrl) { - xsd::cxx::xml::dom::auto_ptr doc = XMLParserWrapper::inst().parseFile(s); + std::unique_ptr doc = XMLParserWrapper::inst().parseFile(s); if (doc.get()) { - vcards = vcard_4_0::vcards(doc); + vcards = vcard_4_0::vcards(*doc); } } else { - xsd::cxx::xml::dom::auto_ptr doc = XMLParserWrapper::inst().parseString(s); + std::unique_ptr doc = XMLParserWrapper::inst().parseString(s); if (doc.get()) { - vcards = vcard_4_0::vcards(doc); + vcards = vcard_4_0::vcards(*doc); } } if (!vcards.get()) { CRITICAL("failed to parse card!"); return boost::shared_ptr(); } boost::shared_ptr card = readCard(vcards->vcard()); card->setUid(Shared::fromURN(vcards->vcard().uid().uri())); card->setName(vcards->vcard().fn().text()); card->setLastModified(toDateTime(vcards->vcard().rev().timestamp())); setProductId( vcards->vcard().prodid().text() ); // setFormatVersion( vcards->vcard().version().text() ); // global_xCardVersion = vcalendar.properties().version().text(); setKolabVersion( vcards->vcard().x_kolab_version().text() ); if (!vcards->vcard().x_custom().empty()) { std::vector customProperties; BOOST_FOREACH(const vcard_4_0::CustomType &p, vcards->vcard().x_custom()) { customProperties.push_back(CustomProperty(p.identifier(), p.value())); } card->setCustomProperties(customProperties); } return card; } catch (const xml_schema::exception& e) { std::cerr << e << std::endl; } catch (...) { CRITICAL("Unhandled exception"); } CRITICAL("Failed to read vcard!"); return boost::shared_ptr(); } } } //Namespace #endif