diff --git a/upgradetool/upgradetool.cpp b/upgradetool/upgradetool.cpp index cf45bb7..8c0ce0d 100644 --- a/upgradetool/upgradetool.cpp +++ b/upgradetool/upgradetool.cpp @@ -1,177 +1,183 @@ /* * Copyright (C) 2012 Christian Mollekopf * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include "upgradeutilities.h" #include "imapupgradejob.h" #include "kolabutils-version.h" +#include /** * Usage: * * IMAP: * ./upgradetool -u username -p password imap.server.com * * Read mimefile: * ./upgradetool -mime complex.ics.mime * * Read mimemessage from stdin: * cat complex.ics.mime | ./upgradetool -mime * */ int main(int argc, char *argv[]) { KCmdLineArgs::init(argc, argv, "upgradetool", "upgradetool",ki18n("upgradetool"), KOLABUTILS_VERSION); KCmdLineOptions options; options.add("mime", ki18n("Read mime from stdin or file")); options.add("u").add("user ", ki18n("Username for IMAP Account")); options.add("y").add("proxyauth ", ki18n("Username to be used for authentication together with password (optional, works with PLAIN/SASL authentication)")); options.add("p").add("password ", ki18n("Password for IMAP Account")); options.add("P").add("port ", ki18n("Port to be used on IMAP Server"), "143"); options.add("e").add("encrypt ", ki18n("Encryption mode to be used (NONE, TLS, SSL)"), "TLS"); options.add("f").add("folder ", ki18n("Upgrade only the specified folder")); options.add("t").add("type ", ki18n("force the type (EVENT, TODO, JOURNAL, CONTACT). Applies only when upgrading a single file or a specific folder.")); options.add("a").add("auth ", ki18n("Authentication mode to be used (PLAIN, LOGIN, CRAMMD5, DIGESTMD5, NTLM, GSSAPI, ANONYMOUS, CLEARTEXT)"), "PLAIN"); options.add("fix-utc-incidences", ki18n("Converts all incidences from UTC to floating time.")); // options.add("f").add options.add("fix-utc-incidences-offset ", ki18n("Uses a UTC offset to convert the times. If not provided the local timezone get's used instead. The offset is in seconds."), "0"); + options.add("fix-utc-incidences-timezone ", ki18n("Uses the specified timezone to convert the times. If not provided the local timezone get's used instead. Timezones are read from zone.tab")); options.add("+[server/file]", ki18n("IMAP Server/File")); KCmdLineArgs::addCmdLineOptions( options ); QCoreApplication app(argc, argv); KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); Kolab::ObjectType overrideType = Kolab::InvalidObject; if (args->isSet("type")) { const QString &type = args->getOption("type"); if (type == "EVENT") { overrideType = Kolab::EventObject; } else if (type == "TODO") { overrideType = Kolab::TodoObject; } else if (type == "JOURNAL") { overrideType = Kolab::JournalObject; } else if (type == "CONTACT") { overrideType = Kolab::ContactObject; } else { kWarning() << "unknown type mode"; return -1; } } const bool fixUtcIncidencesWithOffset = args->isSet("fix-utc-incidences-offset"); - const bool fixUtcIncidences = args->isSet("fix-utc-incidences") || fixUtcIncidencesWithOffset; + const bool fixUtcIncidencesWithTimezone = args->isSet("fix-utc-incidences-timezone"); + const bool fixUtcIncidences = args->isSet("fix-utc-incidences") || fixUtcIncidencesWithOffset || fixUtcIncidencesWithTimezone; Kolab::Upgrade::UpgradeOptions upgradeOptions; upgradeOptions.fixUtcIncidences = fixUtcIncidences; upgradeOptions.fixUtcIncidencesWithOffset = fixUtcIncidencesWithOffset; upgradeOptions.fixUtcIncidencesOffset = args->getOption("fix-utc-incidences-offset").toInt(); + if (fixUtcIncidencesWithTimezone) { + upgradeOptions.fixUtcIncidencesTimezone = KSystemTimeZones::readZone(args->getOption("fix-utc-incidences-timezone")); + } upgradeOptions.overrideObjectType = overrideType; QString folderToUpgrade; if (args->isSet("folder")) { folderToUpgrade = args->getOption("folder"); } if (!args->isSet("mime")) { if (args->count() == 0) { kWarning() << "specify imap server"; return -1; } ImapUpgradeJob *upgrader = new ImapUpgradeJob(&app); upgrader->setUpgradeOptions(upgradeOptions); upgrader->setFolderToUpgrade(folderToUpgrade); QObject::connect(upgrader, SIGNAL(result(KJob*)), &app, SLOT(quit())); KIMAP::LoginJob::EncryptionMode encryptionMode = KIMAP::LoginJob::TlsV1; const QString &encrypt = args->getOption("encrypt"); if (encrypt == "NONE") { encryptionMode = KIMAP::LoginJob::Unencrypted; } else if (encrypt == "SSL") { encryptionMode = KIMAP::LoginJob::AnySslVersion; } else if (encrypt == "TLS") { encryptionMode = KIMAP::LoginJob::TlsV1; } else { kWarning() << "unknown encryption mode"; return -1; } KIMAP::LoginJob::AuthenticationMode authenticationMode = KIMAP::LoginJob::Plain; const QString &auth = args->getOption("auth"); if (auth == "PLAIN") { authenticationMode = KIMAP::LoginJob::Plain; } else if (auth == "LOGIN") { authenticationMode = KIMAP::LoginJob::Login; } else if (auth == "CRAMMD5") { authenticationMode = KIMAP::LoginJob::CramMD5; } else if (auth == "DIGESTMD5") { authenticationMode = KIMAP::LoginJob::DigestMD5; } else if (auth == "NTLM") { authenticationMode = KIMAP::LoginJob::NTLM; } else if (auth == "GSSAPI") { authenticationMode = KIMAP::LoginJob::GSSAPI; } else if (auth == "ANONYMOUS") { authenticationMode = KIMAP::LoginJob::Anonymous; } else if (auth == "CLEARTEXT") { authenticationMode = KIMAP::LoginJob::ClearText; } else { kWarning() << "unknown authentication mode"; return -1; } upgrader->connectToAccount(args->arg(0), args->getOption("port").toInt(), args->getOption("user"), args->getOption("proxyauth"), args->getOption("password"), encryptionMode, authenticationMode); args->clear(); if (app.exec() || Kolab::ErrorHandler::instance().error() >= Kolab::ErrorHandler::Error) { return -1; } return 0; } QTextStream s(stdout); s.setCodec( "UTF-8" ); QTextStream stream(stdin); stream.setCodec( "UTF-8" ); if (args->isSet("mime")) { if (args->count() > 0) { const QString &filename = args->arg(0); QFile file( filename ); if (!file.open( QFile::ReadOnly )) { kWarning() << "failed to open the file: " << filename; return -1; } const QByteArray data = file.readAll(); Q_ASSERT( !data.isEmpty() ); s << Kolab::Upgrade::upgradeMime(data, upgradeOptions); } else { s << Kolab::Upgrade::upgradeMime(stream.readAll().toUtf8(), upgradeOptions); } } if (Kolab::ErrorHandler::instance().error() >= Kolab::ErrorHandler::Error) { return -1; } return 0; } diff --git a/upgradetool/upgradeutilities.cpp b/upgradetool/upgradeutilities.cpp index ecee6c3..44cc65e 100644 --- a/upgradetool/upgradeutilities.cpp +++ b/upgradetool/upgradeutilities.cpp @@ -1,138 +1,141 @@ /* * Copyright (C) 2012 Christian Mollekopf * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #include "upgradeutilities.h" #include #include #include #include #include #include -#include -#include +#include +#include +#include namespace Kolab { namespace Upgrade { static void fixupIncidence(const KCalCore::Incidence::Ptr &incidence, UpgradeOptions upgradeOptions) { if (upgradeOptions.fixUtcIncidences) { if (incidence->dtStart().isUtc()) { - if (upgradeOptions.fixUtcIncidencesWithOffset) { + if (upgradeOptions.fixUtcIncidencesTimezone.isValid()) { + incidence->shiftTimes(upgradeOptions.fixUtcIncidencesTimezone, KDateTime::Spec::ClockTime()); + } else if (upgradeOptions.fixUtcIncidencesWithOffset) { incidence->shiftTimes(KDateTime::Spec::OffsetFromUTC(upgradeOptions.fixUtcIncidencesOffset), KDateTime::Spec::ClockTime()); } else { incidence->shiftTimes(KDateTime::Spec::LocalZone(), KDateTime::Spec::ClockTime()); } } } } KMime::Message::Ptr upgradeMessage(KMime::Message::Ptr msg, UpgradeOptions upgradeOptions) { Kolab::ObjectType overrideObjectType = upgradeOptions.overrideObjectType; Kolab::KolabObjectReader reader; if (overrideObjectType != Kolab::InvalidObject) { reader.setObjectType(overrideObjectType); } const Kolab::ObjectType type = reader.parseMimeMessage(msg); if (Kolab::ErrorHandler::errorOccured()) { Error() << "Error while parsing message."; return KMime::Message::Ptr(); } KMime::Message::Ptr convertedMessage; switch (type) { case Kolab::EventObject: { KCalCore::Event::Ptr event = reader.getEvent(); fixupIncidence(event, upgradeOptions); convertedMessage = Kolab::KolabObjectWriter::writeEvent(event); } break; case Kolab::TodoObject: { KCalCore::Todo::Ptr todo = reader.getTodo(); fixupIncidence(todo, upgradeOptions); convertedMessage = Kolab::KolabObjectWriter::writeTodo(todo); } break; case Kolab::JournalObject: { KCalCore::Journal::Ptr journal = reader.getJournal(); fixupIncidence(journal, upgradeOptions); convertedMessage = Kolab::KolabObjectWriter::writeJournal(journal); } break; case Kolab::ContactObject: convertedMessage = Kolab::KolabObjectWriter::writeContact(reader.getContact()); break; case Kolab::DistlistObject: convertedMessage = Kolab::KolabObjectWriter::writeDistlist(reader.getDistlist()); break; case Kolab::NoteObject: convertedMessage = Kolab::KolabObjectWriter::writeNote(reader.getNote()); break; case Kolab::DictionaryConfigurationObject: { QString lang; const QStringList &dict = reader.getDictionary(lang); convertedMessage = Kolab::KolabObjectWriter::writeDictionary(dict, lang); } break; case Kolab::InvalidObject: default: //TODO handle configuration objects Error() << "failed to read mime file"; } if (Kolab::ErrorHandler::errorOccured()) { Error() << "Error while writing out converted message."; return KMime::Message::Ptr(); } return convertedMessage; } /** * Upgrades the format of a complete mime message containing a kolab object */ QString upgradeMime(const QByteArray &input, UpgradeOptions upgradeOptions) { KMime::Message::Ptr msg = KMime::Message::Ptr(new KMime::Message); msg->setContent( KMime::CRLFtoLF(input) ); msg->parse(); msg->content(KMime::ContentIndex()); KMime::Message::Ptr message = upgradeMessage(msg, upgradeOptions); if (!message) { return QString(); } QString result; QTextStream s(&result); message->toStream(s); return result; } QString upgradeEventXML(const QByteArray &xmlData, QStringList &attachments) { const KCalCore::Event::Ptr i = Kolab::readV2EventXML(xmlData, attachments); const Kolab::Event &event = Kolab::Conversion::fromKCalCore(*i); const std::string &v3String = Kolab::writeEvent(event); return QString::fromStdString(v3String); } } } diff --git a/upgradetool/upgradeutilities.h b/upgradetool/upgradeutilities.h index 7dc4c9b..cf2fdde 100644 --- a/upgradetool/upgradeutilities.h +++ b/upgradetool/upgradeutilities.h @@ -1,58 +1,60 @@ /* * Copyright (C) 2012 Christian Mollekopf * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #ifndef UPGRADEUTILITIES_H #define UPGRADEUTILITIES_H #include #include #include +#include namespace Kolab { namespace Upgrade { /** * Takes a v2 xml document and returns a v3 version */ // QString upgradeEventXML(const QByteArray &xmlData); struct UpgradeOptions { UpgradeOptions() :overrideObjectType(Kolab::InvalidObject), fixUtcIncidences(false), fixUtcIncidencesWithOffset(false), fixUtcIncidencesOffset(0) { } Kolab::ObjectType overrideObjectType; bool fixUtcIncidences; bool fixUtcIncidencesWithOffset; int fixUtcIncidencesOffset; + KTimeZone fixUtcIncidencesTimezone; }; /** * Takes a v2 mime message and returns a v3 version */ KMime::Message::Ptr upgradeMessage(KMime::Message::Ptr msg, UpgradeOptions upgradeOptions = UpgradeOptions()); QString upgradeMime(const QByteArray &, UpgradeOptions upgradeOptions = UpgradeOptions()); } } #endif