Commit 8150bb08 authored by Till Adam's avatar Till Adam
Browse files

Import prototype implementation of a multithreaded server which speaks

IMAP with Akonadi extensions. Unfinished, of course, but this is getting
too large to have it lying on my harddisk.

svn path=/trunk/KDE/kdepim/akonadiserver/; revision=508468
parent 2a8a4d12
# Doxyfile 1.4.1-KDevelop
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
PROJECT_NAME = akonadi.kdevelop
PROJECT_NUMBER = 0.1
OUTPUT_DIRECTORY =
CREATE_SUBDIRS = NO
OUTPUT_LANGUAGE = English
USE_WINDOWS_ENCODING = NO
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
ABBREVIATE_BRIEF = "The $name class" \
"The $name widget" \
"The $name file" \
is \
provides \
specifies \
contains \
represents \
a \
an \
the
ALWAYS_DETAILED_SEC = NO
INLINE_INHERITED_MEMB = NO
FULL_PATH_NAMES = YES
STRIP_FROM_PATH = /home/till/Code/KDAB/cvs/kdchart/
STRIP_FROM_INC_PATH =
SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
DETAILS_AT_TOP = NO
INHERIT_DOCS = YES
DISTRIBUTE_GROUP_DOC = NO
TAB_SIZE = 8
ALIASES =
OPTIMIZE_OUTPUT_FOR_C = NO
OPTIMIZE_OUTPUT_JAVA = NO
SUBGROUPING = YES
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
EXTRACT_ALL = NO
EXTRACT_PRIVATE = NO
EXTRACT_STATIC = NO
EXTRACT_LOCAL_CLASSES = YES
EXTRACT_LOCAL_METHODS = NO
HIDE_UNDOC_MEMBERS = NO
HIDE_UNDOC_CLASSES = NO
HIDE_FRIEND_COMPOUNDS = NO
HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
CASE_SENSE_NAMES = YES
HIDE_SCOPE_NAMES = NO
SHOW_INCLUDE_FILES = YES
INLINE_INFO = YES
SORT_MEMBER_DOCS = YES
SORT_BRIEF_DOCS = NO
SORT_BY_SCOPE_NAME = NO
GENERATE_TODOLIST = YES
GENERATE_TESTLIST = YES
GENERATE_BUGLIST = YES
GENERATE_DEPRECATEDLIST= YES
ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = YES
SHOW_DIRECTORIES = YES
FILE_VERSION_FILTER =
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
#---------------------------------------------------------------------------
QUIET = NO
WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = NO
WARN_FORMAT = "$file:$line: $text"
WARN_LOGFILE =
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = /home/till/Code/kde/svn/trunk/KDE/kdepim/akonadiserver/akonadi
FILE_PATTERNS = *.c \
*.cc \
*.cxx \
*.cpp \
*.c++ \
*.java \
*.ii \
*.ixx \
*.ipp \
*.i++ \
*.inl \
*.h \
*.hh \
*.hxx \
*.hpp \
*.h++ \
*.idl \
*.odl \
*.cs \
*.php \
*.php3 \
*.inc \
*.m \
*.mm \
*.dox \
*.C \
*.CC \
*.C++ \
*.II \
*.I++ \
*.H \
*.HH \
*.H++ \
*.CS \
*.PHP \
*.PHP3 \
*.M \
*.MM \
*.C \
*.H \
*.tlh \
*.diff \
*.patch \
*.moc \
*.xpm \
*.dox
RECURSIVE = yes
EXCLUDE =
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS =
EXAMPLE_PATH =
EXAMPLE_PATTERNS = *
EXAMPLE_RECURSIVE = NO
IMAGE_PATH =
INPUT_FILTER =
FILTER_PATTERNS =
FILTER_SOURCE_FILES = NO
#---------------------------------------------------------------------------
# configuration options related to source browsing
#---------------------------------------------------------------------------
SOURCE_BROWSER = NO
INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = YES
REFERENCED_BY_RELATION = YES
REFERENCES_RELATION = YES
VERBATIM_HEADERS = YES
#---------------------------------------------------------------------------
# configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
ALPHABETICAL_INDEX = NO
COLS_IN_ALPHA_INDEX = 5
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# configuration options related to the HTML output
#---------------------------------------------------------------------------
GENERATE_HTML = YES
HTML_OUTPUT = html
HTML_FILE_EXTENSION = .html
HTML_HEADER =
HTML_FOOTER =
HTML_STYLESHEET =
HTML_ALIGN_MEMBERS = YES
GENERATE_HTMLHELP = NO
CHM_FILE =
HHC_LOCATION =
GENERATE_CHI = NO
BINARY_TOC = NO
TOC_EXPAND = NO
DISABLE_INDEX = NO
ENUM_VALUES_PER_LINE = 4
GENERATE_TREEVIEW = NO
TREEVIEW_WIDTH = 250
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
#---------------------------------------------------------------------------
GENERATE_LATEX = YES
LATEX_OUTPUT = latex
LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex
COMPACT_LATEX = NO
PAPER_TYPE = a4wide
EXTRA_PACKAGES =
LATEX_HEADER =
PDF_HYPERLINKS = NO
USE_PDFLATEX = NO
LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO
#---------------------------------------------------------------------------
# configuration options related to the RTF output
#---------------------------------------------------------------------------
GENERATE_RTF = NO
RTF_OUTPUT = rtf
COMPACT_RTF = NO
RTF_HYPERLINKS = NO
RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
#---------------------------------------------------------------------------
# configuration options related to the man page output
#---------------------------------------------------------------------------
GENERATE_MAN = NO
MAN_OUTPUT = man
MAN_EXTENSION = .3
MAN_LINKS = NO
#---------------------------------------------------------------------------
# configuration options related to the XML output
#---------------------------------------------------------------------------
GENERATE_XML = yes
XML_OUTPUT = xml
XML_SCHEMA =
XML_DTD =
XML_PROGRAMLISTING = YES
#---------------------------------------------------------------------------
# configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
# configuration options related to the Perl module output
#---------------------------------------------------------------------------
GENERATE_PERLMOD = NO
PERLMOD_LATEX = NO
PERLMOD_PRETTY = YES
PERLMOD_MAKEVAR_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = NO
EXPAND_ONLY_PREDEF = NO
SEARCH_INCLUDES = YES
INCLUDE_PATH =
INCLUDE_FILE_PATTERNS =
PREDEFINED =
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
# Configuration::additions related to external references
#---------------------------------------------------------------------------
TAGFILES =
GENERATE_TAGFILE = akonadi.tag
ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
CLASS_DIAGRAMS = YES
HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = NO
CLASS_GRAPH = YES
COLLABORATION_GRAPH = YES
GROUP_GRAPHS = YES
UML_LOOK = NO
TEMPLATE_RELATIONS = NO
INCLUDE_GRAPH = YES
INCLUDED_BY_GRAPH = YES
CALL_GRAPH = NO
GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = YES
DOT_IMAGE_FORMAT = png
DOT_PATH =
DOTFILE_DIRS =
MAX_DOT_GRAPH_WIDTH = 1024
MAX_DOT_GRAPH_HEIGHT = 1024
MAX_DOT_GRAPH_DEPTH = 1000
DOT_TRANSPARENT = NO
DOT_MULTI_TARGETS = NO
GENERATE_LEGEND = YES
DOT_CLEANUP = YES
#---------------------------------------------------------------------------
# Configuration::additions related to the search engine
#---------------------------------------------------------------------------
SEARCHENGINE = NO
SUBDIRS += src
TEMPLATE = subdirs
CONFIG += release \
warn_on \
qt \
thread
QT += network
\ No newline at end of file
/***************************************************************************
* Copyright (C) 2006 by Till Adam <adam@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Library General Public License as *
* published by the Free Software Foundation; either version 2 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef AKONADISTORAGEBACKEND_H
#define AKONADISTORAGEBACKEND_H
#include "collection.h"
class QString;
namespace Akonadi {
/**
@brief The interface to the storage backend.
*/
class StorageBackend {
public:
StorageBackend() {};
virtual ~StorageBackend() {};
virtual CollectionList listCollections( const QString & root ) = 0;
};
}
#endif
/***************************************************************************
* Copyright (C) 2006 by Till Adam <adam@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Library General Public License as *
* published by the Free Software Foundation; either version 2 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <QThread>
#include "akonadi.h"
#include "akonadiconnection.h"
#include "storagebackend.h"
#include "teststoragebackend.h"
using namespace Akonadi;
static AkonadiServer *s_instance = 0;
AkonadiServer::AkonadiServer( QObject* parent )
: QTcpServer( parent )
, m_backend( 0 )
{
s_instance = this;
listen( QHostAddress::LocalHost, 4444 );
}
AkonadiServer::~AkonadiServer()
{
delete m_backend;
}
void AkonadiServer::incomingConnection( int socketDescriptor )
{
AkonadiConnection *thread = new AkonadiConnection(socketDescriptor, this);
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}
StorageBackend * Akonadi::AkonadiServer::storageBackend( )
{
if ( !m_backend ) {
m_backend = new TestStorageBackend();
}
return m_backend;
}
AkonadiServer * AkonadiServer::instance()
{
if ( !s_instance )
s_instance = new AkonadiServer();
return s_instance;
}
/***************************************************************************
* Copyright (C) 2006 by Till Adam <adam@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Library General Public License as *
* published by the Free Software Foundation; either version 2 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef AKONADISERVER_H
#define AKONADISERVER_H
#include <QTcpServer>
namespace Akonadi {
class StorageBackend;
class AkonadiServer: public QTcpServer
{
Q_OBJECT
public:
static AkonadiServer* instance();
AkonadiServer( QObject *parent = 0 );
~AkonadiServer();
StorageBackend* storageBackend();
protected:
/** reimpl */
void incomingConnection(int socketDescriptor);
private:
StorageBackend * m_backend;
};
}
#endif
/***************************************************************************
* Copyright (C) 2006 by Till Adam <adam@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Library General Public License as *
* published by the Free Software Foundation; either version 2 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <QDebug>
#include <QEventLoop>
#include "akonadiconnection.h"
#include "handler.h"
#include "response.h"
using namespace Akonadi;
AkonadiConnection::AkonadiConnection( int socketDescriptor, QObject *parent )
: QThread(parent)
, m_socketDescriptor(socketDescriptor)
, m_tcpSocket( 0 )
, m_currentHandler( 0 )
, m_connectionState( NonAuthenticated )
{
}
AkonadiConnection::~AkonadiConnection()
{
qDebug() << "Connection closed";
delete m_tcpSocket;
}
void AkonadiConnection::run()
{
m_tcpSocket = new QTcpSocket();
if ( !m_tcpSocket->setSocketDescriptor( m_socketDescriptor ) ) {
emit error(m_tcpSocket->error());
return;
}
writeOut( "* OK Akonadi Almost IMAP Server");
/* Start a local event loop and start processing incoming data. Whenever
* a full command has been read, it is delegated to the responsible
* handler and processed by that. If that command needs to do something
* asynchronous such as ask the db for data, it returns and the input
* queue can continue to be processed. Whenever there is something to
* be sent back to the user it is queued in the form of a Response object.
* All this is meant to make it possible to process large incoming or
* outgoing data transfers in a streaming manner, without having to
* hold them in memory 'en gros'. */
connect( m_tcpSocket, SIGNAL( readyRead() ),
this, SLOT( slotNewData() ) );
connect( m_tcpSocket, SIGNAL( disconnected() ),
this, SLOT( slotDisconnected() ) );
exec();
}
void AkonadiConnection::slotDisconnected()
{
quit();
}
void AkonadiConnection::slotNewData()
{
QByteArray line = m_tcpSocket->readLine().trimmed();
qDebug() << "GOT:" << line << endl;
if ( !m_currentHandler ) {
// this is a new command, which means the line must start with a tag
// followed by a non-empty command. First get the tag
int separator = line.indexOf(' ');
if ( separator == -1 || separator == line.size() ) {
writeOut( "* BAD Untagged client command cannot be processed" );
return;
}
// parse our the tag
const QByteArray tag = line.left( separator );
// and the command
int commandStart = line.indexOf( ' ', 0 ) + 1;
int commandEnd = line.indexOf( ' ', commandStart );
if ( commandEnd == -1 ) commandEnd = line.size();
const QByteArray command = line.mid( commandStart, commandEnd - commandStart ).toUpper();
m_currentHandler = findHandlerForCommand( command );
m_currentHandler->setTag( tag );
assert( m_currentHandler );
connect( m_currentHandler, SIGNAL( responseAvailable( const Response & ) ),
this, SLOT( slotResponseAvailable( const Response & ) ) );
connect( m_currentHandler, SIGNAL( connectionStateChange( ConnectionState ) ),
this, SLOT( slotConnectionStateChange( ConnectionState ) ) );
}
if ( m_currentHandler->handleLine( line ) )
m_currentHandler = 0;
}
void AkonadiConnection::writeOut( const char* str )
{
qDebug() << "writing out: " << str << endl;
QByteArray block;
QTextStream out(&block, QIODevice::WriteOnly);
out << str << endl;
out.flush();
m_tcpSocket->write(block);
m_tcpSocket->waitForBytesWritten();
}
Handler * AkonadiConnection::findHandlerForCommand( const QByteArray & command )
{
Handler * handler = Handler::findHandlerForCommandAlwaysAllowed( command );
if ( handler ) return handler;
switch ( m_connectionState ) {
case NonAuthenticated:
handler = Handler::findHandlerForCommandNonAuthenticated( command ); break;
case Authenticated:
handler = Handler::findHandlerForCommandAuthenticated( command );
break;
case Selected:
break;
case LoggingOut:
break;
}
// we didn't have a handler for this, let the default one do its thing
if ( !handler ) handler = new Handler();
return handler;
}
void AkonadiConnection::slotResponseAvailable( const Response& response )
{
// FIXME handle reentrancy in the presence of continuation. Something like:
// "if continuation pending, queue responses, once continuation is done, replay them"
writeOut( response.asString().data() );
}
void AkonadiConnection::slotConnectionStateChange( ConnectionState state )
{
if ( state == m_connectionState ) return;
m_connectionState = state;
switch ( m_connectionState ) {
case NonAuthenticated:
assert( 0 ); // can't happen, it's only the initial state, we can't go back to it
break;
case Authenticated:
break;
case Selected:
break;
case LoggingOut:
m_tcpSocket->disconnectFromHost();
break;
}
}
/***************************************************************************
* Copyright (C) 2006 by Till Adam <adam@kde.org> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Library General Public License as *
* published by the Free Software Foundation; either version 2 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef AKONADICONNECTION_H
#define AKONADICONNECTION_H