--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/messaging/win32wce/qmailnamespace.cpp Wed Aug 25 15:49:42 2010 +0300
@@ -0,0 +1,605 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qmailnamespace.h"
+#include <QApplication>
+#include <QDir>
+#include <QDebug>
+#include <QDir>
+#include <QtDebug>
+#include <QMutex>
+#include <QRegExp>
+#include <stdio.h>
+#if !defined(Q_OS_WIN) || !defined(_WIN32_WCE)
+// Not available for windows mobile?
+#include <QSqlDatabase>
+#endif
+
+#ifdef Q_OS_WIN
+#include <windows.h>
+#else
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#endif
+
+static const char* QMF_DATA_ENV="QMF_DATA";
+static const char* QMF_PLUGINS_ENV="QMF_PLUGINS";
+static const char* QMF_SERVER_ENV="QMF_SERVER";
+static const char* QMF_SETTINGS_ENV="QMF_SETTINGS";
+
+/*!
+ \namespace QMail
+
+ \brief The QMail namespace contains miscellaneous functionality used by the Messaging framework.
+*/
+
+/*!
+ \fn StringType QMail::unquoteString(const StringType& src)
+
+ If \a src has double-quote as the first and last characters, return the string between those characters;
+ otherwise, return the original string.
+*/
+
+/*!
+ \fn StringType QMail::quoteString(const StringType& src)
+
+ Returns \a src surrounded by double-quotes, which are added if not already present.
+*/
+
+#ifdef Q_OS_WIN
+static QMap<int, HANDLE> lockedFiles;
+#endif
+
+#if !defined(Q_OS_WIN) || !defined(_WIN32_WCE) // Not supported on windows mobile
+/*!
+ Convenience function that attempts to obtain a lock on a file with name \a lockFile.
+ It is not necessary to create \a lockFile as this file is created temporarily.
+
+ Returns the id of the lockFile if successful or \c -1 for failure.
+
+ \sa QMail::fileUnlock()
+*/
+int QMail::fileLock(const QString& lockFile)
+{
+ QString path = QDir::tempPath() + "/" + lockFile;
+
+#ifdef Q_OS_WIN
+ static int lockedCount = 0;
+
+ if (!QFile::exists(path)) {
+ QFile file(path);
+ file.open(QIODevice::WriteOnly);
+ file.close();
+ }
+
+ HANDLE handle = ::CreateFile(reinterpret_cast<const wchar_t*>(path.utf16()),
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (handle == INVALID_HANDLE_VALUE) {
+ qWarning() << "Unable to open file for locking:" << path;
+ } else {
+ if (::LockFile(handle, 0, 0, 1, 0) == FALSE) {
+ qWarning() << "Unable to lock file:" << path;
+ } else {
+ ++lockedCount;
+ lockedFiles.insert(lockedCount, handle);
+ return lockedCount;
+ }
+ }
+
+ return -1;
+#else
+ struct flock fl;
+
+ fl.l_type = F_WRLCK;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 0;
+ fl.l_len = 0;
+
+ int fdlock = -1;
+ if((fdlock = ::open(path.toLatin1(), O_WRONLY|O_CREAT, 0666)) == -1)
+ return -1;
+
+ if(::fcntl(fdlock, F_SETLK, &fl) == -1)
+ return -1;
+
+ return fdlock;
+#endif
+}
+
+/*!
+ Convenience function that attempts to unlock the file with identifier \a id that was locked by \c QMail::fileLock.
+
+ Returns \c true for success or \c false otherwise.
+
+ \sa QMail::fileLock()
+*/
+bool QMail::fileUnlock(int id)
+{
+#ifdef Q_OS_WIN
+ QMap<int, HANDLE>::iterator it = lockedFiles.find(id);
+ if (it != lockedFiles.end()) {
+ if (::UnlockFile(it.value(), 0, 0, 1, 0) == FALSE) {
+ qWarning() << "Unable to unlock file:" << lastSystemErrorMessage();
+ } else {
+ if (::CloseHandle(it.value()) == FALSE) {
+ qWarning() << "Unable to close handle:" << lastSystemErrorMessage();
+ }
+
+ lockedFiles.erase(it);
+ return true;
+ }
+ }
+
+ return false;
+#else
+ struct flock fl;
+
+ fl.l_type = F_UNLCK;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 0;
+ fl.l_len = 0;
+
+ int result = -1;
+
+ if((result = ::fcntl(id,F_SETLK, &fl)) == -1)
+ return false;
+
+ if((result = ::close(id)) == -1)
+ return false;
+
+ return true;
+#endif
+}
+#endif
+
+/*!
+ Returns the path to where the Messaging framework will store its data files.
+*/
+QString QMail::dataPath()
+{
+ static QString dataEnv(qgetenv(QMF_DATA_ENV));
+ if(!dataEnv.isEmpty())
+ return dataEnv + "/";
+ //default to ~/.qmf if not env set
+ return QDir::homePath() + "/.qmf/";
+}
+
+/*!
+ Returns the path to where the Messaging framework will store its temporary files.
+*/
+QString QMail::tempPath()
+{
+ return QDir::tempPath();
+}
+
+/*!
+ Returns the path to where the Messaging framework will look for its plugin directories
+*/
+QString QMail::pluginsPath()
+{
+ static QString pluginsEnv(qgetenv(QMF_PLUGINS_ENV));
+ if(!pluginsEnv.isEmpty())
+ return pluginsEnv + "/";
+ //default to "." if no env set
+ return pluginsEnv;
+}
+
+/*!
+ Returns the path to where the Messaging framework will search for SSL certificates.
+*/
+QString QMail::sslCertsPath()
+{
+ return "/etc/ssl/certs/";
+}
+
+/*!
+ Returns the path to where the Messaging framework will invoke the messageserver process.
+*/
+QString QMail::messageServerPath()
+{
+ static QString serverEnv(qgetenv(QMF_SERVER_ENV));
+ if(!serverEnv.isEmpty())
+ return serverEnv + "/";
+ return QApplication::applicationDirPath() + "/";
+}
+
+/*!
+ Returns the path to where the Messaging framework will search for settings information.
+*/
+QString QMail::messageSettingsPath()
+{
+ static QString settingsEnv(qgetenv(QMF_SETTINGS_ENV));
+ if(!settingsEnv.isEmpty())
+ return settingsEnv + "/";
+ return QApplication::applicationDirPath() + "/";
+}
+
+#if !defined(Q_OS_WIN) || !defined(_WIN32_WCE) // Not supported on windows mobile
+/*!
+ Returns the database where the Messaging framework will store its message meta-data.
+ If the database does not exist, it is created.
+*/
+QSqlDatabase QMail::createDatabase()
+{
+ static bool init = false;
+ QSqlDatabase db;
+ if(!init)
+ {
+ db = QSqlDatabase::addDatabase("QSQLITE");
+ QDir dp(dataPath());
+ if(!dp.exists())
+ if(!dp.mkpath(dataPath()))
+ qCritical() << "Cannot create data path";
+ db.setDatabaseName(dataPath() + "qmailstore.db");
+ if(!db.open())
+ qCritical() << "Cannot open database";
+ else
+ init = true;
+ }
+ return db;
+}
+#endif
+
+/*!
+ \internal
+ Returns the next word, given the input and starting position.
+*/
+static QString nextString( const char *line, int& posn )
+{
+ if ( line[posn] == '\0' )
+ return QString::null;
+ int end = posn;
+ char ch;
+ for (;;) {
+ ch = line[end];
+ if ( ch == '\0' || ch == ' ' || ch == '\t' ||
+ ch == '\r' || ch == '\n' ) {
+ break;
+ }
+ ++end;
+ }
+ const char *result = line + posn;
+ int resultLen = end - posn;
+ for (;;) {
+ ch = line[end];
+ if ( ch == '\0' )
+ break;
+ if ( ch != ' ' && ch != '\t' && ch != '\r' && ch != '\n' )
+ break;
+ ++end;
+ }
+ posn = end;
+ return QString::fromLocal8Bit(result, resultLen);
+}
+
+typedef QHash<QString, QString> typeForType;
+Q_GLOBAL_STATIC(typeForType, typeFor);
+typedef QHash<QString, QStringList> extForType;
+Q_GLOBAL_STATIC(extForType, extFor);
+
+/*!
+ \internal
+ Loads the mime type to extensions mapping
+*/
+static void loadExtensions()
+{
+ QMutex mutex;
+ mutex.lock();
+ static bool loaded = false;
+
+ if(loaded)
+ {
+ mutex.unlock();
+ return;
+ }
+
+ QFile file(":qtopiamail/mime.types");
+ if ( file.open(QIODevice::ReadOnly) ) {
+ char line[1024];
+
+ while (file.readLine(line, sizeof(line)) > 0) {
+ if (line[0] == '\0' || line[0] == '#')
+ continue;
+ int posn = 0;
+ QString id = nextString(line, posn);
+ if ( id.isEmpty() )
+ continue;
+ id = id.toLower();
+
+ QStringList exts = extFor()->value(id);
+
+ for( QString ext = nextString( line, posn ); !ext.isEmpty(); ext = nextString(line, posn).toLower() )
+ {
+ if( !exts.contains( ext ) )
+ {
+ exts.append( ext );
+
+ typeFor()->insert(ext, id);
+ }
+ }
+ (*extFor())[ id ] = exts;
+ }
+ loaded = true;
+ }
+ mutex.unlock();
+}
+
+/*!
+ Returns the string mime type based on the filename \a filename.
+*/
+QString QMail::mimeTypeFromFileName(const QString& filename)
+{
+ if (filename.isEmpty())
+ return QString();
+
+ loadExtensions();
+
+ // do a case insensitive search for a known mime type.
+ QString lwrExtOrId = filename.toLower();
+ QHash<QString,QStringList>::const_iterator it = extFor()->find(lwrExtOrId);
+ if (it != extFor()->end()) {
+ return lwrExtOrId;
+ }
+
+ // either it doesnt have exactly one mime-separator, or it has
+ // a path separator at the beginning
+ QString mime_sep = QLatin1String("/");
+ bool doesntLookLikeMimeString = (filename.count(mime_sep) != 1) || (filename[0] == QDir::separator());
+
+ if (doesntLookLikeMimeString || QFile::exists(filename)) {
+ int dot = filename.lastIndexOf('.');
+ QString ext = dot >= 0 ? filename.mid(dot+1) : filename;
+
+ QHash<QString,QString>::const_iterator it = typeFor()->find(ext.toLower());
+ if (it != typeFor()->end()) {
+ return *it;
+ }
+
+ const char elfMagic[] = { '\177', 'E', 'L', 'F', '\0' };
+ QFile ef(filename);
+ if (ef.exists() && (ef.size() > 5) && ef.open(QIODevice::ReadOnly) && (ef.peek(5) == elfMagic)) { // try to find from magic
+ return QLatin1String("application/x-executable"); // could be a shared library or an exe
+ } else {
+ return QLatin1String("application/octet-stream");
+ }
+ }
+
+ // could be something like application/vnd.oma.rights+object
+ return lwrExtOrId;
+}
+
+/*!
+ Returns a list of valid file extensions for the mime type string \a mimeType
+ or an empty list if the mime type is unrecognized.
+*/
+QStringList QMail::extensionsForMimeType(const QString& mimeType)
+{
+ loadExtensions();
+ return extFor()->value(mimeType);
+}
+
+/*!
+ Suspends the current process for \a usecs microseconds.
+*/
+void QMail::usleep(unsigned long usecs)
+{
+#ifdef Q_OS_WIN
+ ::Sleep((usecs + 500) / 1000);
+#else
+ static const int factor(1000 * 1000);
+
+ unsigned long seconds(usecs / factor);
+ usecs = (usecs % factor);
+
+ if (seconds) {
+ ::sleep(seconds);
+ }
+ if (!seconds || usecs) {
+ ::usleep(usecs);
+ }
+#endif
+}
+
+/*!
+ Returns the 'base' form of \a subject, using the transformation defined by RFC5256.
+ If the original subject contains any variant of the tokens "Re" or "Fwd" recognized by
+ RFC5256, then \a replyOrForward will be set to true.
+*/
+QString QMail::baseSubject(const QString& subject, bool *replyOrForward)
+{
+ // Implements the conversion from subject to 'base subject' defined by RFC 5256
+ int pos = 0;
+ QString result(subject);
+
+ bool repeat = false;
+ do {
+ repeat = false;
+
+ // Remove any subj-trailer
+ QRegExp subjTrailer("(?:"
+ "[ \\t]+" // WSP
+ "|"
+ "(\\([Ff][Ww][Dd]\\))" // "(fwd)"
+ ")$");
+ while ((pos = subjTrailer.indexIn(result)) != -1) {
+ if (!subjTrailer.cap(1).isEmpty()) {
+ *replyOrForward = true;
+ }
+ result = result.left(pos);
+ }
+
+ bool modified = false;
+ do {
+ modified = false;
+
+ // Remove any subj-leader
+ QRegExp subjLeader("^(?:"
+ "[ \\t]+" // WSP
+ "|"
+ "(?:\\[[^\\[\\]]*\\][ \\t]*)*" // ( '[' 'blobchar'* ']' WSP* )*
+ "([Rr][Ee]|[Ff][Ww][Dd]?)[ \\t]*" // ( "Re" | "Fw" | "Fwd") WSP*
+ "(?:\\[[^\\[\\]]*\\][ \\t]*)?" // optional: ( '[' 'blobchar'* ']' WSP* )
+ ":" // ':'
+ ")");
+ while ((pos = subjLeader.indexIn(result)) == 0) {
+ if (!subjLeader.cap(1).isEmpty()) {
+ *replyOrForward = true;
+ }
+ result = result.mid(subjLeader.cap(0).length());
+ modified = true;
+ }
+
+ // Remove subj-blob, if there would be a remainder
+ QRegExp subjBlob("^(\\[[^\\[\\]]*\\][ \\t]*)"); // '[' 'blobchar'* ']' WSP*
+ if ((subjBlob.indexIn(result) == 0) && (subjBlob.cap(0).length() < result.length())) {
+ result = result.mid(subjBlob.cap(0).length());
+ modified = true;
+ }
+ } while (modified);
+
+ // Remove subj-fwd-hdr and subj-fwd-trl if both are present
+ QRegExp subjFwdHdr("^\\[[Ff][Ww][Dd]:");
+ QRegExp subjFwdTrl("\\]$");
+ if ((subjFwdHdr.indexIn(result) == 0) && (subjFwdTrl.indexIn(result) != -1)) {
+ *replyOrForward = true;
+ result = result.mid(subjFwdHdr.cap(0).length(), result.length() - (subjFwdHdr.cap(0).length() + subjFwdTrl.cap(0).length()));
+ repeat = true;
+ }
+ } while (repeat);
+
+ return result;
+}
+
+static QString normaliseIdentifier(const QString& str)
+{
+ // Don't permit space, tab or quote marks
+ static const QChar skip[] = { QChar(' '), QChar('\t'), QChar('"') };
+
+ QString result;
+ result.reserve(str.length());
+
+ QString::const_iterator it = str.begin(), end = str.end();
+ while (it != end) {
+ if ((*it != skip[0]) && (*it != skip[1]) && (*it != skip[2])) {
+ result.append(*it);
+ }
+ ++it;
+ }
+
+ return result;
+}
+
+/*!
+ Returns the sequence of message identifiers that can be extracted from \a str.
+ Message identifiers must conform to the definition given by RFC 5256.
+*/
+QStringList QMail::messageIdentifiers(const QString& str)
+{
+ QStringList result;
+
+ QRegExp identifierPattern("("
+ "(?:[ \\t]*)" // Optional leading whitespace
+ "[^ \\t\\<\\>@]+" // Leading part
+ "(?:[ \\t]*)" // Optional whitespace allowed before '@'?
+ "@"
+ "(?:[ \\t]*)" // Optional whitespace allowed after '@'?
+ "[^ \\t\\<\\>]+" // Trailing part
+ ")");
+
+ // Extracts message identifiers from \a str, matching the definition used in RFC 5256
+ int index = str.indexOf('<');
+ if (index != -1) {
+ // This may contain other information besides the IDs delimited by < and >
+ do {
+ // Extract only the delimited content
+ if (str.indexOf(identifierPattern, index + 1) == (index + 1)) {
+ result.append(normaliseIdentifier(identifierPattern.cap(1)));
+ index += identifierPattern.cap(0).length();
+ } else {
+ index += 1;
+ }
+
+ index = str.indexOf('<', index);
+ } while (index != -1);
+ } else {
+ // No delimiters - consider the entirety as an identifier
+ if (str.indexOf(identifierPattern) != -1) {
+ result.append(normaliseIdentifier(identifierPattern.cap(1)));
+ }
+ }
+
+ return result;
+}
+
+/*!
+ Returns the text describing the last error reported by the underlying platform.
+*/
+QString QMail::lastSystemErrorMessage()
+{
+#ifdef Q_OS_WIN
+ LPVOID buffer;
+
+ ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ ::GetLastError(),
+ 0,
+ reinterpret_cast<LPTSTR>(&buffer),
+ 0,
+ NULL);
+
+ QString result(QString::fromUtf16(reinterpret_cast<const ushort*>(buffer)));
+ ::LocalFree(buffer);
+
+ return result;
+#else
+ return QString(::strerror(errno));
+#endif
+}
+