From: unknown
Date: Wed, 25 Mar 2009 22:58:10 +0000 (+0100)
Subject: - First commit!
X-Git-Url: https://gitweb.tyo.aptx.org/?a=commitdiff_plain;h=a2c6fcecf195bb2016e86318689486827981cab1;p=aniplayer-old.git
- First commit!
---
diff --git a/aniplayer.pro b/aniplayer.pro
new file mode 100644
index 0000000..03327aa
--- /dev/null
+++ b/aniplayer.pro
@@ -0,0 +1,8 @@
+CONFIG += ordered
+TEMPLATE = subdirs
+
+#CONFIG += browserplugin
+
+
+SUBDIRS += lib \
+ src
diff --git a/init b/init
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/anidbudpclient/abstractcommand.cpp b/lib/anidbudpclient/abstractcommand.cpp
new file mode 100644
index 0000000..a9cd0b5
--- /dev/null
+++ b/lib/anidbudpclient/abstractcommand.cpp
@@ -0,0 +1,38 @@
+#include "abstractcommand.h"
+
+AbstractCommand::AbstractCommand(QObject *parent) : QObject(parent)
+{
+ m_replyCode = UNKNOWN_REPLY;
+}
+
+AbstractCommand::~AbstractCommand()
+{
+
+}
+
+Command AbstractCommand::rawCommand() const
+{
+ return Command("", QVariantMap());
+}
+
+bool AbstractCommand::waitForResult() const
+{
+ return false;
+}
+
+void AbstractCommand::setRawReply(ReplyCode replyCode, const QString &reply, AniDBUdpClient *client)
+{
+ Q_UNUSED(client);
+ m_replyCode = replyCode;
+ m_rawReply = reply;
+}
+
+QString AbstractCommand::rawReply() const
+{
+ return m_rawReply;
+}
+
+AbstractCommand::ReplyCode AbstractCommand::replyCode() const
+{
+ return m_replyCode;
+}
diff --git a/lib/anidbudpclient/abstractcommand.h b/lib/anidbudpclient/abstractcommand.h
new file mode 100644
index 0000000..7f7fa4b
--- /dev/null
+++ b/lib/anidbudpclient/abstractcommand.h
@@ -0,0 +1,178 @@
+#ifndef ABSTRACTCOMMAND_H
+#define ABSTRACTCOMMAND_H
+
+#include "anidbudpclient_global.h"
+#include
+#include
+#include
+
+class AniDBUdpClient;
+
+typedef QPair Command;
+
+class ANIDBUDPCLIENTSHARED_EXPORT AbstractCommand : public QObject
+{
+ Q_OBJECT
+ Q_ENUMS(ReplyCode);
+
+public:
+ enum ReplyCode;
+
+ AbstractCommand(QObject *parent = 0);
+ virtual ~AbstractCommand();
+
+ virtual Command rawCommand() const;
+
+ virtual bool waitForResult() const;
+
+ virtual void setRawReply(ReplyCode replyCode, const QString &reply, AniDBUdpClient *client);
+ virtual QString rawReply() const;
+
+ virtual ReplyCode replyCode() const;
+
+signals:
+ void replyReady(bool success = false);
+
+public:
+ enum ReplyCode
+ {
+ CLIENT_DESTROYED = -1,
+ UNKNOWN_REPLY = 0,
+ // POSITIVE 2XX
+ LOGIN_ACCEPTED = 200, //a
+ LOGIN_ACCEPTED_NEW_VER = 201, //a
+ LOGGED_OUT = 203, //a
+ RESOURCE = 205, //d
+ STATS = 206, //b
+ TOP = 207, //b
+ UPTIME = 208, //b
+ ENCRYPTION_ENABLED = 209, //c
+
+ MYLIST_ENTRY_ADDED = 210, //a
+ MYLIST_ENTRY_DELETED = 211, //a
+
+ ADDED_FILE = 214, //e
+ ADDED_STREAM = 215, //e
+
+ ENCODING_CHANGED = 219, //c
+
+ FILE = 220, //a
+ MYLIST = 221, //a
+ MYLIST_STATS = 222, //b
+
+ ANIME = 230, //b
+ ANIME_BEST_MATCH = 231, //b
+ RANDOMANIME = 232, //b
+ ANIME_DESCRIPTION = 233, //b
+
+ EPISODE = 240, //b
+ PRODUCER = 245, //b
+ GROUP = 250, //b
+
+ BUDDY_LIST = 253, //c
+ BUDDY_STATE = 254, //c
+ BUDDY_ADDED = 255, //c
+ BUDDY_DELETED = 256, //c
+ BUDDY_ACCEPTED = 257, //c
+ BUDDY_DENIED = 258, //c
+
+ VOTED = 260, //b
+ VOTE_FOUND = 261, //b
+ VOTE_UPDATED = 262, //b
+ VOTE_REVOKED = 263, //b
+
+ NOTIFICATION_ENABLED = 270, //a
+ NOTIFICATION_NOTIFY = 271, //a
+ NOTIFICATION_MESSAGE = 272, //a
+ NOTIFICATION_BUDDY = 273, //c
+ NOTIFICATION_SHUTDOWN = 274, //c
+ PUSHACK_CONFIRMED = 280, //a
+ NOTIFYACK_SUCCESSFUL_M = 281, //a
+ NOTIFYACK_SUCCESSFUL_N = 282, //a
+ NOTIFICATION = 290, //a
+ NOTIFYLIST = 291, //a
+ NOTIFYGET_MESSAGE = 292, //a
+ NOTIFYGET_NOTIFY = 293, //a
+
+ SENDMSG_SUCCESSFUL = 294, //a
+ USER = 295, //d
+
+ // AFFIRMATIVE/NEGATIVE 3XX
+ PONG = 300, //a
+ AUTHPONG = 301, //c
+ NO_SUCH_RESOURCE = 305, //d
+ API_PASSWORD_NOT_DEFINED = 309, //c
+
+ FILE_ALREADY_IN_MYLIST = 310, //a
+ MYLIST_ENTRY_EDITED = 311, //a
+ MULTIPLE_MYLIST_ENTRIES = 312, //e
+
+ SIZE_HASH_EXISTS = 314, //c
+ INVALID_DATA = 315, //c
+ STREAMNOID_USED = 316, //c
+
+ NO_SUCH_FILE = 320, //a
+ NO_SUCH_ENTRY = 321, //a
+ MULTIPLE_FILES_FOUND = 322, //b
+
+ NO_SUCH_ANIME = 330, //b
+ NO_SUCH_ANIME_DESCRIPTION = 333, //b
+ NO_SUCH_EPISODE = 340, //b
+ NO_SUCH_PRODUCER = 345, //b
+ NO_SUCH_GROUP = 350, //b
+
+ BUDDY_ALREADY_ADDED = 355, //c
+ NO_SUCH_BUDDY = 356, //c
+ BUDDY_ALREADY_ACCEPTED = 357, //c
+ BUDDY_ALREADY_DENIED = 358, //c
+
+ NO_SUCH_VOTE = 360, //b
+ INVALID_VOTE_TYPE = 361, //b
+ INVALID_VOTE_VALUE = 362, //b
+ PERMVOTE_NOT_ALLOWED = 363, //b
+ ALREADY_PERMVOTED = 364, //b
+
+ NOTIFICATION_DISABLED = 370, //a
+ NO_SUCH_PACKET_PENDING = 380, //a
+ NO_SUCH_ENTRY_M = 381, //a
+ NO_SUCH_ENTRY_N = 382, //a
+
+ NO_SUCH_MESSAGE = 392, //a
+ NO_SUCH_NOTIFY = 393, //a
+ NO_SUCH_USER = 394, //a
+
+ // NEGATIVE 4XX
+ NOT_LOGGED_IN = 403, //a
+
+ NO_SUCH_MYLIST_FILE = 410, //a
+ NO_SUCH_MYLIST_ENTRY = 411, //a
+
+
+ // CLIENT SIDE FAILURE 5XX
+ LOGIN_FAILED = 500, //a
+ LOGIN_FIRST = 501, //a
+ ACCESS_DENIED = 502, //a
+ CLIENT_VERSION_OUTDATED = 503, //a
+ CLIENT_BANNED = 504, //a
+ ILLEGAL_INPUT_OR_ACCESS_DENIED = 505, //a
+ INVALID_SESSION = 506, //a
+ NO_SUCH_ENCRYPTION_TYPE = 509, //c
+ ENCODING_NOT_SUPPORTED = 519, //c
+
+ BANNED = 555, //a
+ UNKNOWN_COMMAND = 598, //a
+
+
+ // SERVER SIDE FAILURE 6XX
+ INTERNAL_SERVER_ERROR = 600, //a
+ ANIDB_OUT_OF_SERVICE = 601, //a
+ SERVER_BUSY = 602, //d
+ API_VIOLATION = 666, //a
+ };
+
+protected:
+ QString m_rawReply;
+ ReplyCode m_replyCode;
+};
+
+#endif // ABSTRACTCOMMAND_H
diff --git a/lib/anidbudpclient/anidbudpclient.cpp b/lib/anidbudpclient/anidbudpclient.cpp
new file mode 100644
index 0000000..3ab0057
--- /dev/null
+++ b/lib/anidbudpclient/anidbudpclient.cpp
@@ -0,0 +1,555 @@
+#include "anidbudpclient.h"
+
+#include
+#include
+
+#include
+
+#include
+
+const QByteArray AniDBUdpClient::clientName = CLIENT_NAME;
+const int AniDBUdpClient::clientVersion = CLIENT_VERSION;
+const int AniDBUdpClient::protocolVersion = PROTOCOL_VERSION;
+
+AniDBUdpClient::AniDBUdpClient(QObject *parent) : QObject(parent)
+{
+qDebug() << "Api instance init!";
+ m_state = DisconnectedState;
+ m_error = NoError;
+ m_errorString;
+ m_idlePolicy = DoNothingIdlePolicy;
+
+ disconnecting = false;
+ authCommand = 0;
+ authenticateOnConnect = false;
+
+ socket = new QUdpSocket(this);
+ QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(readReplies()));
+
+ commandTimer = new QTimer(this);
+ QObject::connect(commandTimer, SIGNAL(timeout()), this, SLOT(sendNextCommand()));
+
+ idleTimer = new QTimer(this);
+ QObject::connect(idleTimer, SIGNAL(timeout()), this, SLOT(idleTimeout()));
+
+ m_localPort = 9001;
+ m_host = "api.anidb.info";
+ m_hostPort = 9000;
+
+ authCommand = new AuthCommand(this);
+ QObject::connect(authCommand, SIGNAL(replyReady(bool)), this, SLOT(doAuthenticate(bool)));
+
+ commandTimer->setSingleShot(false);
+ setFloodInterval(5);
+}
+
+AniDBUdpClient::~AniDBUdpClient()
+{
+ disconnect();
+ clearCommandQueue();
+}
+
+QString AniDBUdpClient::host() const
+{
+ return m_host;
+}
+
+void AniDBUdpClient::setHost(const QString &host, quint16 port)
+{
+ m_host = host;
+ if (port)
+ m_hostPort = port;
+ m_hostAddress = QHostAddress();
+}
+
+quint16 AniDBUdpClient::hostPort() const
+{
+ return m_hostPort;
+}
+
+void AniDBUdpClient::setHostPort(quint16 port)
+{
+ m_hostPort = port;
+}
+
+quint16 AniDBUdpClient::localPort() const
+{
+ return m_localPort;
+}
+
+void AniDBUdpClient::setLocalPort(quint16 port)
+{
+ m_localPort = port;
+}
+
+QString AniDBUdpClient::user() const
+{
+ return m_user;
+}
+
+void AniDBUdpClient::setUser(const QString &user)
+{
+ // All usernames are lowercaase
+ m_user = user.toLower();
+}
+
+QString AniDBUdpClient::pass() const
+{
+ return m_pass;
+}
+
+void AniDBUdpClient::setPass(const QString &pass)
+{
+ m_pass = pass;
+}
+
+bool AniDBUdpClient::compression() const
+{
+ return m_compression;
+}
+
+void AniDBUdpClient::setCompression(bool compress)
+{
+ m_compression = compress;
+}
+
+int AniDBUdpClient::floodInterval() const
+{
+ return m_floodInterval;
+}
+
+void AniDBUdpClient::setFloodInterval(int interval)
+{
+ m_floodInterval = interval;
+ commandTimer->setInterval(m_floodInterval * 1000);
+}
+
+AniDBUdpClient::IdlePolicy AniDBUdpClient::idlePolicy() const
+{
+ return m_idlePolicy;
+}
+
+void AniDBUdpClient::setIdlePolicy(IdlePolicy policy)
+{
+ m_idlePolicy = policy;
+}
+
+
+AniDBUdpClient::State AniDBUdpClient::state() const
+{
+ return m_state;
+}
+
+AniDBUdpClient::Error AniDBUdpClient::error() const
+{
+ return m_error;
+}
+
+QString AniDBUdpClient::errorString() const
+{
+ return m_errorString;
+}
+
+bool AniDBUdpClient::isIdle()
+{
+ return m_idle;
+}
+
+void AniDBUdpClient::clearCommandQueue()
+{
+ // Delete all unsent commands that are managed by the client.
+ while (!commandQueue.empty())
+ {
+ AbstractCommand *cmd = commandQueue.dequeue();
+ if (!cmd->waitForResult())
+ {
+ // These would be deleted anyway
+ delete cmd;
+ }
+ else
+ {
+ // Send CLIENT_DESTROYED to indicate that no real reply will come.
+ cmd->setRawReply(AbstractCommand::CLIENT_DESTROYED, "", this);
+ }
+ }
+}
+
+void AniDBUdpClient::connect()
+{
+qDebug() << "Conneting";
+ if (state() == ReconnectingState)
+ {
+ authenticate();
+ return;
+ }
+
+ if (state() != DisconnectedState)
+ return;
+
+ changeState(ConnectingState);
+
+ if (!m_hostAddress.isNull())
+ {
+ doConnect();
+ return;
+ }
+ QHostInfo::lookupHost(m_host, this, SLOT(lookedUp(QHostInfo)));
+}
+
+void AniDBUdpClient::disconnect(bool graceful)
+{
+qDebug() << "Disconneting" << (graceful ? "gracefully" : "");
+ if (graceful)
+ {
+ disconnecting = true;
+ return;
+ }
+ changeState(DisconnectedState);
+}
+
+void AniDBUdpClient::send(AbstractCommand *command)
+{
+ if (state() < ConnectingState)
+ connect();
+
+ enqueueCommand(command);
+}
+
+void AniDBUdpClient::sendRaw(QByteArray command)
+{
+qDebug() << QString("Sending RAW command: %1").arg(command.constData());
+ enqueueCommand(new RawCommand(command));
+}
+
+void AniDBUdpClient::lookedUp(QHostInfo hostInfo)
+{
+qDebug() << "Host lookup finished";
+ if (hostInfo.error() != QHostInfo::NoError)
+ {
+ qDebug() << "Lookup failed:" << hostInfo.errorString();
+ changeState(ErrorState);
+ m_error = HostLookupError;
+ m_errorString = hostInfo.errorString();
+ return;
+ }
+ m_hostAddress = hostInfo.addresses()[0];
+ doConnect();
+}
+
+
+void AniDBUdpClient::doConnect()
+{
+ if (socket->bind(QHostAddress::Any, m_localPort))
+ {
+qDebug() << "Successful connection";
+ authenticate();
+ }
+ else
+ {
+ changeState(ErrorState);
+ m_error = BindError;
+ m_errorString = socket->errorString();
+qDebug() << QString("Bind on Address: %1 port: %2 failed").arg(m_hostAddress.toString()).arg(m_localPort);
+ }
+}
+
+void AniDBUdpClient::authenticate()
+{
+ authCommand->setUser(m_user);
+ authCommand->setPass(m_pass);
+
+ enqueueCommand(authCommand, true);
+ changeState(ReconnectingState);
+}
+
+void AniDBUdpClient::doAuthenticate(bool success)
+{
+qDebug() << "doAuthenticate init";
+ if (success)
+ {
+qDebug() << "success!";
+ m_sessionId = authCommand->sessionId().toUtf8();
+ changeState(ConnectedState);
+ }
+ else
+ {
+ changeState(ErrorState);
+ m_error = AuthenticationError;
+ }
+
+ authenticateOnConnect = false;
+}
+
+void AniDBUdpClient::logout()
+{
+ if (state() != ConnectedState)
+ // We are not logged in other states, don't try to logout again.
+ return;
+
+ enqueueCommand(new RawCommand("LOGOUT"), true);
+ changeState(ReconnectingState);
+ m_sessionId = "";
+}
+
+void AniDBUdpClient::enqueueCommand(AbstractCommand *command, bool first)
+{
+ if (first)
+ {
+ commandQueue.push_front(command);
+ }
+ else
+ {
+ commandQueue.enqueue(command);
+ }
+
+ leaveIdleState();
+}
+
+void AniDBUdpClient::sendNextCommand()
+{
+ if (commandQueue.isEmpty())
+ {
+ enterIdleState();
+ return;
+ }
+
+ sendCommand(commandQueue.dequeue());
+}
+
+void AniDBUdpClient::sendCommand(AbstractCommand *command)
+{
+ Command cmdPair = command->rawCommand();
+ QByteArray datagram = buildCmd(cmdPair.first, cmdPair.second);
+
+ QByteArray commandId = nextCommandId();
+
+ datagram += datagram.contains(" ") ? "&" : " ";
+ datagram += "tag=" + commandId;
+
+ if (m_sessionId.length())
+ datagram += "&s=" + m_sessionId;
+
+ if (command->waitForResult())
+ {
+ sentCommands[commandId] = command;
+ }
+ else
+ {
+ command->deleteLater();
+ }
+
+qDebug() << QString("SENDING datagram:\n\t%1\nto: %2 ([%3]:%4)")
+ .arg(datagram.constData())
+ .arg(m_host)
+ .arg(m_hostAddress.toString())
+ .arg(m_hostPort);
+
+ socket->writeDatagram(datagram, m_hostAddress, m_hostPort);
+}
+
+void AniDBUdpClient::readReplies()
+{
+ while (socket->hasPendingDatagrams())
+ {
+ char data[UDP_DATAGRAM_MAXIMUM_SIZE];
+ int size;
+ QHostAddress sender;
+ quint16 senderPort;
+ size = socket->readDatagram(data, UDP_DATAGRAM_MAXIMUM_SIZE, &sender, &senderPort);
+
+ QByteArray tmp(data, size);
+
+ if (sender != m_hostAddress)
+ {
+ qDebug() << QString("Recieved datagram from unknown host: %1 port: %2\nRaw datagram contents:%3\nDiscarding datagram.")
+ .arg(sender.toString())
+ .arg(senderPort)
+ .arg(tmp.constData());
+ continue;
+ }
+
+ if (m_compression && tmp.mid(0, 2) == "00")
+ {
+qDebug() << "COMPRESSED DATAGRAM = " << tmp;
+ tmp = qUncompress(tmp);
+ }
+
+ QString reply = QString::fromUtf8(tmp);
+
+ qDebug() << QString("Recieved datagram from [%1]:%2\nRaw datagram contents:%3")
+ .arg(m_host)
+ .arg(senderPort)
+ .arg(reply);
+
+ QByteArray commandId = tmp.mid(0, 5);
+
+ // Do not parse reply for commands not waiting for a reply.
+ if (!sentCommands.contains(commandId))
+ {
+qDebug() << QString("Command with id: %1 is not waiting for a reply, discarding").arg(commandId.constData());
+ continue;
+ }
+qDebug() << QString("Sending reply to command with id: %1").arg(commandId.constData());
+
+ // tag + space = 5 + 1
+ QByteArray replyCodeText = tmp.mid(6, 3);
+
+ bool ok;
+ int replyCodeInt = replyCodeText.toInt(&ok);
+ AbstractCommand::ReplyCode replyCode = AbstractCommand::UNKNOWN_REPLY;
+ if (ok)
+ {
+ replyCode = AbstractCommand::ReplyCode(replyCodeInt);
+ }
+
+ AbstractCommand *cmd = sentCommands.take(commandId);
+
+ // Requeue command and reauthenticate if not logged in.
+ if (replyCode == AbstractCommand::LOGIN_FIRST
+ || replyCode == AbstractCommand::INVALID_SESSION)
+ {
+qDebug() << "LOGIN FIRST required, authing";
+ enqueueCommand(cmd);
+ authenticate();
+ continue;
+ }
+ // tag + space + replyCode + space = 5 + 1 + 3 + 1
+ reply = reply.mid(10);
+
+ cmd->setRawReply(replyCode, reply, this);
+ }
+}
+
+void AniDBUdpClient::enterIdleState()
+{
+ if (m_idle)
+ return;
+qDebug() << "Entering idle state";
+ m_idle = true;
+
+ switch (m_idlePolicy)
+ {
+ case DoNothingIdlePolicy:
+ case KeepAliveIdlePolicy:
+ commandTimer->stop();
+ idleTimer->start();
+ break;
+ case LogoutIdlePolicy:
+ default:
+ idleTimeout();
+ break;
+ }
+
+}
+
+void AniDBUdpClient::leaveIdleState()
+{
+ // Don't do anything untill connected!
+ if (state() < ReconnectingState)
+ return;
+
+ if (!m_idle)
+ return;
+qDebug() << "Leaving idle state";
+ m_idle = false;
+
+ idleTimer->stop();
+
+ sendNextCommand();
+ commandTimer->start();
+}
+
+void AniDBUdpClient::idleTimeout()
+{
+ logout();
+}
+
+
+QByteArray AniDBUdpClient::buildCmd(const QString &cmd, const QVariantMap &args)
+{
+ QString result = cmd;
+ for (QVariantMap::const_iterator it = args.constBegin(); it != args.constEnd(); ++it)
+ {
+ if (!it.value().canConvert(QVariant::String))
+ {
+ qWarning("Passed value cannot be converted to string!");
+ continue;
+ }
+
+ // The string version of bool is "true" or "false", but hte API expects 1 or 0
+ QString value;
+ if (it.value().type() == QVariant::Bool)
+ {
+ value = it.value().toBool() ? "1" : "0";
+ }
+ else
+ {
+ value = it.value().toString();
+ }
+
+ if (it == args.constBegin())
+ result += QString(" %1=%2").arg(it.key(), value);
+ else
+ result += QString("&%1=%2").arg(it.key(), value);
+ }
+ return result.toUtf8();
+}
+
+void AniDBUdpClient::changeState(State newState)
+{
+ if (newState == m_state)
+ return;
+
+ State oldState = m_state;
+
+ // BEFORE statechange
+ switch(newState)
+ {
+ case DisconnectedState:
+
+ if (m_sessionId.length())
+ logout();
+
+ socket->close();
+ m_sessionId = "";
+ emit disconnected();
+// break;
+ case ErrorState:
+ commandTimer->stop();
+ break;
+ default:
+ break;
+ }
+
+ m_state = newState;
+
+ // AFTER statechange
+ switch (newState)
+ {
+ case ReconnectingState:
+ leaveIdleState();
+ break;
+ case ConnectedState:
+ // Do not wait for the timer floodInterval seconds for the first command.
+ emit connected();
+ break;
+ default:
+ break;
+ }
+
+qDebug() << "State changed from" << oldState << "to" << newState;
+ emit stateChanged(newState, oldState);
+}
+
+QByteArray AniDBUdpClient::nextCommandId(int len)
+{
+ static const char chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789";
+ static const int numChars = sizeof(chars) - 1;
+
+ QByteArray result(len, '-');
+ while (len--)
+ result[len] = chars[qrand() % numChars];
+
+qDebug() << QString("Generated id %1").arg(result.constData());
+ return result;
+}
diff --git a/lib/anidbudpclient/anidbudpclient.h b/lib/anidbudpclient/anidbudpclient.h
new file mode 100644
index 0000000..28c681a
--- /dev/null
+++ b/lib/anidbudpclient/anidbudpclient.h
@@ -0,0 +1,205 @@
+#ifndef ANIDBUDPCLIENT_H
+#define ANIDBUDPCLIENT_H
+
+#include "anidbudpclient_global.h"
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "authcommand.h"
+
+class QUdpSocket;
+class QTimer;
+
+class AbstractCommand;
+class AuthCommand;
+
+
+#define CLIENT_NAME "anidbudpclient"
+#define CLIENT_VERSION 0x000001
+#define PROTOCOL_VERSION 3
+
+class ANIDBUDPCLIENTSHARED_EXPORT AniDBUdpClient : public QObject
+{
+ Q_OBJECT
+ Q_ENUMS(State Error IdlePolicy AbstractCommand::ReplyCode);
+
+ Q_PROPERTY(QString host READ host WRITE setHost);
+ Q_PROPERTY(quint16 hostPort READ hostPort WRITE setHostPort);
+ Q_PROPERTY(quint16 localPort READ localPort WRITE setLocalPort);
+
+ Q_PROPERTY(QString user READ user WRITE setUser);
+ Q_PROPERTY(QString pass READ pass WRITE setPass);
+
+ /*
+ Send commands in \interval seconds intervals
+ */
+ Q_PROPERTY(int floodInterval READ floodInterval WRITE setFloodInterval);
+
+ Q_PROPERTY(IdlePolicy idlePolicy READ idlePolicy WRITE setIdlePolicy);
+ Q_PROPERTY(State state READ state);
+ Q_PROPERTY(Error error READ error);
+ Q_PROPERTY(QString errorString READ errorString);
+
+public:
+ static const QByteArray clientName;
+ static const int clientVersion;
+ static const int protocolVersion;
+
+ enum State
+ {
+ ErrorState = -1,
+ DisconnectedState,
+ ConnectingState,
+ ReconnectingState,
+ ConnectedState,
+ };
+
+ enum Error
+ {
+ NoError,
+ BindError,
+ HostLookupError,
+ HostUnreachableError,
+ AuthenticationError,
+ BannedError,
+ UnknownError,
+ };
+
+ enum IdlePolicy
+ {
+ DoNothingIdlePolicy,
+ LogoutIdlePolicy,
+ KeepAliveIdlePolicy,
+ };
+
+ AniDBUdpClient(QObject *parent = 0);
+ virtual ~AniDBUdpClient();
+
+ // ------------------ Properties ------------------
+ QString host() const;
+ void setHost(const QString &host, quint16 port = 0);
+ quint16 hostPort() const;
+ void setHostPort(quint16 port);
+ quint16 localPort() const;
+ void setLocalPort(quint16 port);
+
+ QString user() const;
+ void setUser(const QString &user);
+ QString pass() const;
+ void setPass(const QString &user);
+
+ bool compression() const;
+ void setCompression(bool compress);
+
+ int floodInterval() const;
+ void setFloodInterval(int interval);
+
+ IdlePolicy idlePolicy() const;
+ void setIdlePolicy(IdlePolicy policy);
+
+ State state() const;
+ Error error() const;
+ QString errorString() const;
+
+ bool isIdle();
+
+ // ---------------- END Properties ----------------
+
+ void clearCommandQueue();
+
+public slots:
+ void connect();
+
+ /*
+ Disconnect from host.
+ If \graceful is true send all enququed messages first.
+ */
+ void disconnect(bool graceful = false);
+
+ void authenticate();
+
+ void send(AbstractCommand *command);
+ void sendRaw(QByteArray command);
+
+signals:
+ void connected();
+ void disconnected();
+
+ void pong();
+ void uptime();
+
+ void stateChanged(State newState, State oldState);
+
+private slots:
+ void lookedUp(QHostInfo hostInfo);
+ void doConnect();
+ void doAuthenticate(bool success);
+
+ void logout();
+
+
+ void enqueueCommand(AbstractCommand *command, bool first = false);
+ void sendNextCommand();
+ void sendCommand(AbstractCommand *command);
+
+ void readReplies();
+
+ void enterIdleState();
+ void leaveIdleState();
+
+ void idleTimeout();
+
+private:
+ QByteArray buildCmd(const QString &cmd, const QVariantMap &args);
+
+ void changeState(State newState);
+ QByteArray nextCommandId(int len = 5);
+
+ QTimer *commandTimer;
+ QTimer *idleTimer;
+ QTimer *replyTimeoutTimer;
+
+ QQueue commandQueue;
+ QMap sentCommands;
+ QUdpSocket *socket;
+
+
+
+ // Connection params
+ QString m_host;
+ QHostAddress m_hostAddress;
+ quint16 m_hostPort;
+ quint16 m_localPort;
+
+ int m_floodInterval;
+
+ // Auth params
+ QString m_user;
+ QString m_pass;
+
+ bool m_compression;
+
+ QByteArray m_sessionId;
+
+ // Misc params
+ IdlePolicy m_idlePolicy;
+ State m_state;
+ Error m_error;
+ QString m_errorString;
+
+ bool disconnecting;
+ bool m_idle;
+
+ AuthCommand *authCommand;
+ bool authenticateOnConnect;
+
+
+ static const int UDP_DATAGRAM_MAXIMUM_SIZE = 1400;
+ static const int UDP_API_INACTIVITY_LOGOUT = 30 * 60;
+};
+
+#endif // ANIDBUDPCLIENT_H
diff --git a/lib/anidbudpclient/anidbudpclient.pri b/lib/anidbudpclient/anidbudpclient.pri
new file mode 100644
index 0000000..8af8ec6
--- /dev/null
+++ b/lib/anidbudpclient/anidbudpclient.pri
@@ -0,0 +1,5 @@
+QT *= network
+INCLUDEPATH += $$PWD
+DEPENDPATH += $$PWD
+LIBS += -lanidbudpclient
+LIBS += -L$$DESTDIR
diff --git a/lib/anidbudpclient/anidbudpclient.pro b/lib/anidbudpclient/anidbudpclient.pro
new file mode 100644
index 0000000..75e6829
--- /dev/null
+++ b/lib/anidbudpclient/anidbudpclient.pro
@@ -0,0 +1,23 @@
+# -------------------------------------------------
+# Project created by QtCreator 2009-03-22T14:53:52
+# -------------------------------------------------
+QT += network
+QT -= gui
+TEMPLATE = lib
+TARGET = anidbudpclient
+DESTDIR = ../../build
+INCLUDEPATH += $$PWD
+DEPENDPATH += $$PWD
+QT *= network
+DEFINES += ANIDBUDPCLIENT_LIBRARY
+SOURCES += anidbudpclient.cpp \
+ abstractcommand.cpp \
+ authcommand.cpp \
+ rawcommand.cpp \
+ mylistaddcommand.cpp
+HEADERS += anidbudpclient.h \
+ anidbudpclient_global.h \
+ abstractcommand.h \
+ authcommand.h \
+ rawcommand.h \
+ mylistaddcommand.h
diff --git a/lib/anidbudpclient/anidbudpclient_global.h b/lib/anidbudpclient/anidbudpclient_global.h
new file mode 100644
index 0000000..2b578d2
--- /dev/null
+++ b/lib/anidbudpclient/anidbudpclient_global.h
@@ -0,0 +1,12 @@
+#ifndef ANIDBUDPCLIENT_GLOBAL_H
+#define ANIDBUDPCLIENT_GLOBAL_H
+
+#include
+
+#if defined(ANIDBUDPCLIENT_LIBRARY)
+# define ANIDBUDPCLIENTSHARED_EXPORT Q_DECL_EXPORT
+#else
+# define ANIDBUDPCLIENTSHARED_EXPORT Q_DECL_IMPORT
+#endif
+
+#endif // ANIDBUDPCLIENT_GLOBAL_H
diff --git a/lib/anidbudpclient/authcommand.cpp b/lib/anidbudpclient/authcommand.cpp
new file mode 100644
index 0000000..871aba6
--- /dev/null
+++ b/lib/anidbudpclient/authcommand.cpp
@@ -0,0 +1,73 @@
+#include "authcommand.h"
+
+#include "anidbudpclient.h"
+
+AuthCommand::AuthCommand(QObject *parent) : AbstractCommand(parent)
+{
+ m_compression = false;
+}
+
+AuthCommand::AuthCommand(QString user, QString pass, QObject *parent) : AbstractCommand(parent)
+{
+ m_user = user;
+ m_pass = pass;
+}
+
+void AuthCommand::setUser(const QString &user)
+{
+ m_user = user;
+}
+
+void AuthCommand::setPass(const QString &pass)
+{
+ m_pass = pass;
+}
+
+void AuthCommand::setCompression(bool compress)
+{
+ m_compression = compress;
+}
+
+bool AuthCommand::waitForResult() const
+{
+ return true;
+}
+
+Command AuthCommand::rawCommand() const
+{
+ Command command;
+
+ command.first = "AUTH";
+
+ command.second["user"] = m_user;
+ command.second["pass"] = m_pass;
+ command.second["protover"] = AniDBUdpClient::protocolVersion;
+ command.second["client"] = AniDBUdpClient::clientName.constData();
+ command.second["clientver"] = AniDBUdpClient::clientVersion;
+ command.second["enc"] = "UTF8";
+ command.second["comp"] = m_compression;
+ return command;
+}
+
+QString AuthCommand::sessionId() const
+{
+ return m_sessionId;
+}
+
+void AuthCommand::setRawReply(ReplyCode replyCode, const QString &reply, AniDBUdpClient *client)
+{
+qDebug() << replyCode;
+ AbstractCommand::setRawReply(replyCode, reply, client);
+
+ switch(replyCode)
+ {
+ case LOGIN_ACCEPTED:
+ case LOGIN_ACCEPTED_NEW_VER:
+ m_sessionId = m_rawReply.mid(0, m_rawReply.indexOf(" "));
+ emit replyReady(true);
+ break;
+ default:
+qDebug() << "ERROR CODE: " << replyCode;
+ emit replyReady(false);
+ }
+}
diff --git a/lib/anidbudpclient/authcommand.h b/lib/anidbudpclient/authcommand.h
new file mode 100644
index 0000000..ab88016
--- /dev/null
+++ b/lib/anidbudpclient/authcommand.h
@@ -0,0 +1,36 @@
+#ifndef AUTHCOMMAND_H
+#define AUTHCOMMAND_H
+
+#include "abstractcommand.h"
+
+class AuthCommand : public AbstractCommand
+{
+ Q_OBJECT
+
+public:
+ AuthCommand(QObject *parent = 0);
+ AuthCommand(QString user, QString pass, QObject *parent = 0);
+
+ void setUser(const QString &user);
+ void setPass(const QString &pass);
+
+ void setCompression(bool compress);
+
+ bool waitForResult() const;
+
+ Command rawCommand() const;
+ QString sessionId() const;
+
+ void setRawReply(ReplyCode replyCode, const QString &reply, AniDBUdpClient *client);
+
+
+
+private:
+ QString m_user;
+ QString m_pass;
+ QString m_sessionId;
+
+ bool m_compression;
+};
+
+#endif // AUTHCOMMAND_H
diff --git a/lib/anidbudpclient/mylistaddcommand.cpp b/lib/anidbudpclient/mylistaddcommand.cpp
new file mode 100644
index 0000000..e8fa659
--- /dev/null
+++ b/lib/anidbudpclient/mylistaddcommand.cpp
@@ -0,0 +1,163 @@
+#include "mylistaddcommand.h"
+
+#include
+#include
+#include
+#include
+
+#include "anidbudpclient.h"
+
+MylistAddCommand::MylistAddCommand(QString file, QObject *parent) : AbstractCommand(parent)
+{
+ m_file = file;
+ m_size = QFileInfo(file).size();
+ mylistId = 0;
+
+ connect(&futureWatcher, SIGNAL(finished()), this, SLOT(completeHash()));
+}
+
+QString MylistAddCommand::file() const
+{
+ return m_file;
+}
+
+QByteArray MylistAddCommand::ed2kHash() const
+{
+ return m_ed2k;
+}
+
+int MylistAddCommand::fileSize() const
+{
+ return m_size;
+}
+
+bool MylistAddCommand::markWatched() const
+{
+ return m_markWatched;
+}
+
+void MylistAddCommand::setMarkWatched(bool mark)
+{
+ m_markWatched = mark;
+}
+
+bool MylistAddCommand::waitForResult() const
+{
+ return true;
+}
+
+Command MylistAddCommand::rawCommand() const
+{
+ Command command;
+ switch (mylistId)
+ {
+ case 0:
+ command.first = "MYLIST";
+ command.second["size"] = m_size;
+ command.second["ed2k"] = m_ed2k.constData();
+ return command;
+ break;
+ case -1:
+ command.first = "MYLISTADD";
+ command.second["size"] = m_size;
+ command.second["ed2k"] = m_ed2k.constData();
+ command.second["state"] = 1;
+ command.second["viewed"] = m_markWatched;
+ return command;
+ break;
+ default:
+ command.first = "MYLISTADD";
+ command.second["lid"] = mylistId;
+ command.second["viewed"] = m_markWatched;
+ command.second["edit"] = 1;
+ return command;
+ break;
+ }
+}
+
+void MylistAddCommand::setRawReply(ReplyCode replyCode, const QString &reply, AniDBUdpClient *client)
+{
+ AbstractCommand::setRawReply(replyCode, reply, client);
+
+ switch (mylistId)
+ {
+ case 0:
+ switch(replyCode)
+ {
+ case MYLIST:
+ {
+ QString reply = m_rawReply.mid(m_rawReply.indexOf("\n"));
+ QStringList parts = reply.split('|', QString::KeepEmptyParts);
+qDebug() << "PARTS" << parts;
+ mylistId = parts[0].toInt();
+qDebug() << "Mylist ID: " << mylistId;
+ if (!mylistId)
+ {
+qDebug() << "FAILED to read Mylist ID";
+ emit replyReady(false);
+ }
+ client->send(this);
+ }
+ break;
+ default:
+ mylistId = -1;
+ client->send(this);
+ break;
+ }
+ break;
+ default:
+ switch(replyCode)
+ {
+ case MYLIST_ENTRY_ADDED:
+ case MYLIST_ENTRY_EDITED:
+ case FILE_ALREADY_IN_MYLIST:
+ emit replyReady(true);
+ break;
+ default:
+ emit replyReady(false);
+ break;
+ }
+ break;
+ }
+
+
+}
+
+void MylistAddCommand::hash()
+{
+ future = QtConcurrent::run(this, &MylistAddCommand::doHash, m_file);
+ futureWatcher.setFuture(future);
+}
+
+void MylistAddCommand::completeHash()
+{
+ if (!future.isFinished())
+ {
+qDebug() << "WTF?";
+ return;
+ }
+ m_ed2k = QByteArray(future);
+ emit hashComplete();
+}
+
+QByteArray MylistAddCommand::doHash(QString file)
+{
+qDebug() << "hash thread init";
+ QFile f(file);
+ if (!f.open(QIODevice::ReadOnly))
+ return QByteArray();
+
+ QCryptographicHash ed2k(QCryptographicHash::Md4);
+ char *data = new char[ED2K_PART_SIZE];
+ int size;
+ while (!f.atEnd())
+ {
+ size = f.read(data, ED2K_PART_SIZE);
+ ed2k.addData(QCryptographicHash::hash(QByteArray(data, size), QCryptographicHash::Md4));
+qDebug() << "hashing...";
+ }
+ f.close();
+ delete[] data;
+qDebug() << "hashing... complete!";
+ return ed2k.result().toHex();
+}
diff --git a/lib/anidbudpclient/mylistaddcommand.h b/lib/anidbudpclient/mylistaddcommand.h
new file mode 100644
index 0000000..122921f
--- /dev/null
+++ b/lib/anidbudpclient/mylistaddcommand.h
@@ -0,0 +1,56 @@
+#ifndef MYLISTADDCOMMAND_H
+#define MYLISTADDCOMMAND_H
+
+#include "anidbudpclient_global.h"
+#include "abstractcommand.h"
+
+#include
+#include
+
+
+class ANIDBUDPCLIENTSHARED_EXPORT MylistAddCommand : public AbstractCommand
+{
+ Q_OBJECT
+
+public:
+ MylistAddCommand(QString file, QObject *parent = 0);
+
+ QString file() const;
+ QByteArray ed2kHash() const;
+ int fileSize() const;
+
+ bool markWatched() const;
+ void setMarkWatched(bool mark);
+
+
+ bool waitForResult() const;
+
+ Command rawCommand() const;
+
+ void setRawReply(ReplyCode replyCode, const QString &reply, AniDBUdpClient *client);
+
+ void hash();
+
+signals:
+ void hashComplete();
+
+private slots:
+ void completeHash();
+
+private:
+ QByteArray doHash(QString file);
+ QFuture future;
+ QFutureWatcher futureWatcher;
+
+ bool m_markWatched;
+
+ int m_size;
+ QByteArray m_ed2k;
+ QString m_file;
+
+ int mylistId;
+
+ static const qint64 ED2K_PART_SIZE = 9728000;
+};
+
+#endif // MYLISTADDCOMMAND_H
diff --git a/lib/anidbudpclient/rawcommand.cpp b/lib/anidbudpclient/rawcommand.cpp
new file mode 100644
index 0000000..2b3ebf9
--- /dev/null
+++ b/lib/anidbudpclient/rawcommand.cpp
@@ -0,0 +1,11 @@
+#include "rawcommand.h"
+
+RawCommand::RawCommand(const QString &command, QObject *parent) : AbstractCommand(parent)
+{
+ m_command = command;
+}
+
+Command RawCommand::rawCommand() const
+{
+ return Command(m_command, QVariantMap());
+}
diff --git a/lib/anidbudpclient/rawcommand.h b/lib/anidbudpclient/rawcommand.h
new file mode 100644
index 0000000..990ffa4
--- /dev/null
+++ b/lib/anidbudpclient/rawcommand.h
@@ -0,0 +1,20 @@
+#ifndef RAWCOMMAND_H
+#define RAWCOMMAND_H
+
+#include "anidbudpclient_global.h"
+#include "abstractcommand.h"
+
+class ANIDBUDPCLIENTSHARED_EXPORT RawCommand : public AbstractCommand
+{
+ Q_OBJECT
+
+public:
+
+ RawCommand(const QString &command, QObject *parent = 0);
+
+ Command rawCommand() const;
+private:
+ QString m_command;
+};
+
+#endif // RAWCOMMAND_H
diff --git a/lib/browserplugin-solution/INSTALL.TXT b/lib/browserplugin-solution/INSTALL.TXT
new file mode 100644
index 0000000..3b6c155
--- /dev/null
+++ b/lib/browserplugin-solution/INSTALL.TXT
@@ -0,0 +1,182 @@
+INSTALLATION INSTRUCTIONS
+
+These instructions refer to the package you are installing as
+some-package.tar.gz or some-package.zip. The .zip file is intended for use
+on Windows.
+
+The directory you choose for the installation will be referred to as
+your-install-dir.
+
+Note to Qt Visual Studio Integration users: In the instructions below,
+instead of building from command line with nmake, you can use the menu
+command 'Qt->Open Solution from .pro file' on the .pro files in the
+example and plugin directories, and then build from within Visual
+Studio.
+
+Unpacking and installation
+--------------------------
+
+1. Unpack the archive if you have not done so already.
+
+ On Unix and Mac OS X (in a terminal window):
+
+ cd your-install-dir
+ gunzip some-package.tar.gz
+ tar xvf some-package.tar
+
+ This creates the subdirectory some-package containing the files.
+
+ On Windows:
+
+ Unpack the .zip archive by right-clicking it in explorer and
+ choosing "Extract All...". If your version of Windows does not
+ have zip support, you can use the infozip tools available
+ from:
+
+ ftp://ftp.trolltech.com/util/infozip.exe
+
+ If you are using the infozip tools (in a command prompt window):
+
+ cd your-install-dir
+ unzip some-package.zip
+
+2. Enter the package directory and configure the package:
+
+ cd some-package
+ qmake
+
+ The qmake command will prompt you in some cases for further
+ information. Answer these questions and carefully read the license text
+ before accepting the license conditions. The package can't be used if
+ you don't accept the license conditions.
+
+3. To build the examples (for Qt Solutions components) or the application
+ (for Qt Solutions tools):
+
+ make
+
+ Or if you are using Microsoft Visual C++:
+
+ nmake
+
+ The example programs are located in the example or examples
+ subdirectory.
+
+ For Qt Solutions plugins (e.g. image formats), both debug and
+ release versions of the plugin are built by default when
+ appropriate, since in some cases the release Qt library will not
+ load a debug plugin, and vice versa. The plugins are automatically
+ installed into the plugins directory of your Qt installation.
+
+ Plugins may be built statically, i.e. as a library that will be
+ linked into your application executable, and so will not need to
+ be redistributed as a separate plugin DLL to end users. Static
+ building is required if Qt itself is built statically. To do it,
+ just add "static" to the CONFIG variable in the plugin/plugin.pro
+ file before building. Refer to the "Static Plugins" section in the
+ chapter "How to Create Qt Plugins" for explanation of how to use a
+ static plugin in your application. The source code of the example
+ program(s) will also typically contain the relevant instructions
+ as comments.
+
+4. Some of the widget components are provided with plugins for Qt
+ Designer. To build and install the plugin, cd into the
+ some-package/plugin directory and give the commands
+
+ qmake
+ make [or nmake if your are using Microsoft Visual Studio]
+
+ Restart Qt Designer to make it load the new widget plugin.
+
+ Note: If you are using the built-in Qt Designer from the Qt Visual
+ Studio Integration, you will need to manually copy the plugin DLL
+ file, i.e. copy
+ %QTDIR%\plugins\designer\some-component.dll
+ to the Qt Visual Studio Integration plugin path, typically:
+ C:\Program Files\Trolltech\Qt VS Integration\plugins
+
+ Note: If you for some reason are using a Qt Designer that is built
+ in debug mode, you will need to build the plugin in debug mode
+ also. Edit the file plugin.pro in the plugin directory, changing
+ 'release' to 'debug' in the CONFIG line, before running qmake.
+
+
+Using a component in your project
+---------------------------------
+
+The directory your-install-dir/some-package/src includes all the
+source code for the component. To use this component in your project:
+
+1. Add the following line
+
+ include(your-install-dir/some-package/src/some-package.pri)
+
+ to the project's .pro file.
+
+2. Run qmake on the project's .pro file.
+
+This adds the package's sources and headers to the SOURCES and HEADERS
+qmake variables respectively, and update INCLUDEPATH to contain the
+package's src directory. Additionally, the .pri file may include some
+dependencies needed by the package.
+
+To include a header file from the package in your sources, you can now
+simply use:
+
+ #include
+
+or alternatively, in Qt 4 style:
+
+ #include
+
+
+Install documentation
+---------------------
+
+The HTML documentation for the package's classes is located in the
+your-install-dir/some-package/doc/html/index.html. You can open this
+file with any web browser.
+
+To install the documentation into Qt Assistant (for Qt version 4.4 and
+later):
+
+1. In Assistant, open the Edit->Preferences dialog and choose the
+ Documentation tab. Click the Add... button and select the file
+ your-install-dir/some-package/doc/html/some-package.qch
+
+For Qt versions prior to 4.4, do instead the following:
+
+1. The directory your-install-dir/some-package/doc/html contains a
+ file called some-package.dcf. Execute the following commands in a
+ shell, command prompt or terminal window:
+
+ cd your-install-dir/some-package/doc/html/
+ assistant -addContentFile some-package.dcf
+
+The next time you start Qt Assistant, you can access the package's
+documentation.
+
+
+Removing the documentation from assistant
+-----------------------------------------
+
+If you want to remove the documentation from Qt Assistant, do as
+follows, for Qt version 4.4 and later:
+
+1. In Assistant, open the Edit->Preferences dialog and choose the
+ Documentation tab. In the list of Registered Documentation, select
+ the item com.trolltech.qtsolutions.some-package_version, and click
+ the Remove button.
+
+For Qt versions prior to 4.4, do instead the following:
+
+1. The directory your-install-dir/some-package/doc/html contains a
+ file called some-package.dcf. Execute the following commands in a
+ shell, command prompt or terminal window:
+
+ cd your-install-dir/some-package/doc/html/
+ assistant -removeContentFile some-package.dcf
+
+
+Enjoy! :)
+- The Qt Solutions Team.
diff --git a/lib/browserplugin-solution/LICENSE.GPL b/lib/browserplugin-solution/LICENSE.GPL
new file mode 100644
index 0000000..7daa506
--- /dev/null
+++ b/lib/browserplugin-solution/LICENSE.GPL
@@ -0,0 +1,349 @@
+The Qt Solutions are copyright (C) 2003-2005 Trolltech AS
+
+You may use, distribute and copy the Qt Solution(s) under the terms of
+GNU General Public License version 2, which is displayed below.
+
+-------------------------------------------------------------------------
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 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 General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ , 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
+-------------------------------------------------------------------------
diff --git a/lib/browserplugin-solution/Makefile b/lib/browserplugin-solution/Makefile
new file mode 100644
index 0000000..74140da
--- /dev/null
+++ b/lib/browserplugin-solution/Makefile
@@ -0,0 +1,126 @@
+#############################################################################
+# Makefile for building: browserplugin-solution
+# Generated by qmake (2.01a) (Qt 4.5.0) on: Sun Mar 22 15:03:18 2009
+# Project: browserplugin-solution.pro
+# Template: app
+# Command: c:\Qt\4.5.0\bin\qmake.exe -spec c:\Qt\4.5.0\mkspecs\win32-msvc2008 -win32 CONFIG+=debug_and_release -o Makefile browserplugin-solution.pro
+#############################################################################
+
+####### Compiler, tools and options
+
+CC = cl
+CXX = cl
+DEFINES = -DUNICODE -DWIN32 -DQT_LARGEFILE_SUPPORT
+CFLAGS = -nologo -Zm200 -Zc:wchar_t- -MP5 $(DEFINES)
+CXXFLAGS = -nologo -Zm200 -Zc:wchar_t- -MP5 $(DEFINES)
+INCPATH = -I"c:\Qt\4.5.0\mkspecs\win32-msvc2008"
+LINK = link
+LFLAGS = /NOLOGO
+LIBS =
+QMAKE = c:\Qt\4.5.0\bin\qmake.exe
+IDC = c:\Qt\4.5.0\bin\idc.exe
+IDL = midl
+ZIP = zip -r -9
+DEF_FILE =
+RES_FILE =
+COPY = copy /y
+COPY_FILE = $(COPY)
+COPY_DIR = xcopy /s /q /y /i
+DEL_FILE = del
+DEL_DIR = rmdir
+MOVE = move
+CHK_DIR_EXISTS= if not exist
+MKDIR = mkdir
+INSTALL_FILE = $(COPY_FILE)
+INSTALL_PROGRAM = $(COPY_FILE)
+INSTALL_DIR = $(COPY_DIR)
+
+####### Output directory
+
+OBJECTS_DIR = .
+
+####### Files
+
+SOURCES =
+OBJECTS =
+DIST =
+QMAKE_TARGET = browserplugin-solution
+DESTDIR = #avoid trailing-slash linebreak
+TARGET = browserplugin-solution.exe
+DESTDIR_TARGET = browserplugin-solution.exe
+
+####### Implicit rules
+
+.SUFFIXES: .c .cpp .cc .cxx
+
+{.}.cpp{}.obj::
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -Fo @<<
+ $<
+<<
+
+{.}.cc{}.obj::
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -Fo @<<
+ $<
+<<
+
+{.}.cxx{}.obj::
+ $(CXX) -c $(CXXFLAGS) $(INCPATH) -Fo @<<
+ $<
+<<
+
+{.}.c{}.obj::
+ $(CC) -c $(CFLAGS) $(INCPATH) -Fo @<<
+ $<
+<<
+
+####### Build rules
+
+first: all
+all: Makefile $(DESTDIR_TARGET)
+
+$(DESTDIR_TARGET): $(OBJECTS)
+ $(LINK) $(LFLAGS) /OUT:$(DESTDIR_TARGET) @<<
+ $(OBJECTS) $(LIBS)
+<<
+
+
+Makefile: browserplugin-solution.pro c:\Qt\4.5.0\mkspecs\win32-msvc2008\qmake.conf c:\Qt\4.5.0\mkspecs\qconfig.pri \
+ c:\Qt\4.5.0\mkspecs\features\qt_functions.prf \
+ c:\Qt\4.5.0\mkspecs\features\qt_config.prf \
+ c:\Qt\4.5.0\mkspecs\features\exclusive_builds.prf \
+ c:\Qt\4.5.0\mkspecs\features\default_pre.prf \
+ c:\Qt\4.5.0\mkspecs\features\win32\default_pre.prf
+ $(QMAKE) -spec c:\Qt\4.5.0\mkspecs\win32-msvc2008 -win32 CONFIG+=debug_and_release -o Makefile browserplugin-solution.pro
+c:\Qt\4.5.0\mkspecs\qconfig.pri:
+c:\Qt\4.5.0\mkspecs\features\qt_functions.prf:
+c:\Qt\4.5.0\mkspecs\features\qt_config.prf:
+c:\Qt\4.5.0\mkspecs\features\exclusive_builds.prf:
+c:\Qt\4.5.0\mkspecs\features\default_pre.prf:
+c:\Qt\4.5.0\mkspecs\features\win32\default_pre.prf:
+qmake: FORCE
+ @$(QMAKE) -spec c:\Qt\4.5.0\mkspecs\win32-msvc2008 -win32 CONFIG+=debug_and_release -o Makefile browserplugin-solution.pro
+
+dist:
+ $(ZIP) browserplugin-solution.zip $(SOURCES) $(DIST) ..\..\aniplayer.pro c:\Qt\4.5.0\mkspecs\qconfig.pri c:\Qt\4.5.0\mkspecs\features\qt_functions.prf c:\Qt\4.5.0\mkspecs\features\qt_config.prf c:\Qt\4.5.0\mkspecs\features\exclusive_builds.prf c:\Qt\4.5.0\mkspecs\features\default_pre.prf c:\Qt\4.5.0\mkspecs\features\win32\default_pre.prf
+
+clean: compiler_clean
+ -$(DEL_FILE) browserplugin-solution.exp browserplugin-solution.pdb browserplugin-solution.ilk vc*.pdb vc*.idb
+
+distclean: clean
+ -$(DEL_FILE) $(DESTDIR_TARGET)
+ -$(DEL_FILE) Makefile
+
+compiler_clean:
+
+
+
+####### Compile
+
+####### Install
+
+install: FORCE
+
+uninstall: FORCE
+
+FORCE:
+
diff --git a/lib/browserplugin-solution/README.TXT b/lib/browserplugin-solution/README.TXT
new file mode 100644
index 0000000..df36182
--- /dev/null
+++ b/lib/browserplugin-solution/README.TXT
@@ -0,0 +1,7 @@
+Browser Plugin v2.3
+
+The QtBrowserPlugin solution is useful for implementing plugins
+for web browser.
+
+
+
diff --git a/lib/browserplugin-solution/doc/html/classic.css b/lib/browserplugin-solution/doc/html/classic.css
new file mode 100644
index 0000000..0ff9e7d
--- /dev/null
+++ b/lib/browserplugin-solution/doc/html/classic.css
@@ -0,0 +1,131 @@
+h3.fn,span.fn
+{
+ margin-left: 1cm;
+ text-indent: -1cm;
+}
+
+a:link
+{
+ color: #004faf;
+ text-decoration: none
+}
+
+a:visited
+{
+ color: #672967;
+ text-decoration: none
+}
+
+a.obsolete
+{
+ color: #661100;
+ text-decoration: none
+}
+
+a.compat
+{
+ color: #661100;
+ text-decoration: none
+}
+
+a.obsolete:visited
+{
+ color: #995500;
+ text-decoration: none
+}
+
+a.compat:visited
+{
+ color: #995500;
+ text-decoration: none
+}
+
+td.postheader
+{
+ font-family: sans-serif
+}
+
+tr.address
+{
+ font-family: sans-serif
+}
+
+body
+{
+ background: #ffffff;
+ color: black
+}
+
+table tr.odd {
+ background: #f0f0f0;
+ color: black;
+}
+
+table tr.even {
+ background: #e4e4e4;
+ color: black;
+}
+
+table.annotated th {
+ padding: 3px;
+ text-align: left
+}
+
+table.annotated td {
+ padding: 3px;
+}
+
+table tr pre
+{
+ padding-top: none;
+ padding-bottom: none;
+ padding-left: none;
+ padding-right: none;
+ border: none;
+ background: none
+}
+
+tr.qt-style
+{
+ background: #a2c511;
+ color: black
+}
+
+body pre
+{
+ padding: 0.2em;
+ border: #e7e7e7 1px solid;
+ background: #f1f1f1;
+ color: black
+}
+
+span.preprocessor, span.preprocessor a
+{
+ color: darkblue;
+}
+
+span.comment
+{
+ color: darkred;
+ font-style: italic
+}
+
+span.string,span.char
+{
+ color: darkgreen;
+}
+
+.title
+{
+ text-align: center
+}
+
+.subtitle
+{
+ font-size: 0.8em
+}
+
+.small-subtitle
+{
+ font-size: 0.65em
+}
diff --git a/lib/browserplugin-solution/doc/html/developingplugins.html b/lib/browserplugin-solution/doc/html/developingplugins.html
new file mode 100644
index 0000000..0a5aba5
--- /dev/null
+++ b/lib/browserplugin-solution/doc/html/developingplugins.html
@@ -0,0 +1,231 @@
+
+
+
+
+
+ Developing Plugins
+
+
+
+
The QtBrowserPlugin solution makes it easy to write browser plugins that can be used in Netscape, Mozilla FireFox, Opera, and any other web browser supporting the "npruntime" API:
Current versions of Microsoft Internet Explorer do not support this API. However, you can use the ActiveQt framework to compile a single plugin library that works with all web browsers.
Since any QWidget or QObject subclass can be turned into a plugin with little effort it is usually easiest to do the development as a stand-alone Qt application - debugging plugins is cumbersome.
+
Make sure that the subclasses you want to export use the Q_OBJECT macro and provide a default constructor. Use the Q_CLASSINFO macro to specify a list of MIME types each of your classes supports, and export the classes through the QtNPFactory macros:
+
QTNPFACTORY_BEGIN("Qt-based Graph Plugin", "A Qt-based LiveConnected plug-in that graphs numeric data");
+ QTNPCLASS(Graph)
+ QTNPFACTORY_END()
+
Include the qtbrowserplugin.pri in your .pro file, and regenerate the makefile with qmake. The resulting makefile will generate a shared library with a file name starting with "np" - this is required by all browsers to recognize the library as a plugin.
+
+
Windows specific notes
+
On Windows it is required to link a version resource into the plugin library. To do that, create an .rc file (a plain-text file) and add it to the RC_FILE variable of your project. The .rc file needs to contain a version description like here:
+
1 VERSIONINFO
+ FILEVERSION 1,0,0,1
+ PRODUCTVERSION 1,0,0,1
+ FILEFLAGSMASK 0x3fL
+ #ifdef _DEBUG
+ FILEFLAGS 0x1L
+ #else
+ FILEFLAGS 0x0L
+ #endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+ BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904e4"
+ BEGIN
+ VALUE "Comments", "\0"
+ VALUE "CompanyName", "Trolltech\0"
+ VALUE "FileDescription", "grapher\0"
+ VALUE "FileExtents", "g1n\0"
+ VALUE "FileOpenName", "Graphable data (*.g1n)\0"
+ VALUE "FileVersion", "1, 0, 0, 1\0"
+ VALUE "InternalName", "grapher\0"
+ VALUE "LegalCopyright", "Copyright 1997 Trolltech ASA\0"
+ VALUE "LegalTrademarks", "\0"
+ VALUE "MIMEType", "application/x-graphable\0"
+ VALUE "OriginalFilename", "grapher.dll\0"
+ VALUE "PrivateBuild", "\0"
+ VALUE "ProductName", "Trolltech grapher\0"
+ VALUE "ProductVersion", "1, 0, 0, 1\0"
+ VALUE "SpecialBuild", "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1252
+ END
+ END
+
+
Enabling ActiveX support
+
To build a plugin project with ActiveX support, use ActiveQt's QAxServer module by adding the following line to your project:
+
CONFIG += qaxserver
+
Also, add the following line to your resource file
+
1 TYPELIB "thisfile.rc"
+
In your plugin code, use Q_CLASSINFO and the QAxFactory macros as usual.
+
When you build the plugin, then ActiveQt will perform the build steps required to turn the plugin library into an ActiveX control server which provides your plugin classes not only to browsers supporting the npruntime API, but also to browsers supporting ActiveX controls (i.e. Internet Explorer).
+
However, not that calling QtNPBindable APIs will not do anything when the browser does not support the npruntime API. In some cases, QAxBindable provides equivalent APIs (i.e. for reading incoming data).
+
+
Unix specific notes
+
On Unix/Linux, QtBrowserPlugin uses the XEmbed protocol. This is a fairly recent addition to the NPP plugin API. At the time of writing, it is not supported by the Opera and Konqueror browsers. Firefox and other Mozilla/Gecko-based browsers do support it.
+
Update: Opera version 9.50 will support the XEmbed protocol. QtBrowserPlugin is tested successfully with the beta release of Opera 9.50. One known issue: Opera does not automatically register the extension part of the MIME description. If required, work around by adding it manually in the Preferences->Advanced->Download dialog. (e.g. add "g1n" to "application/x-graphable" to make the grapher example work).
+
+
Known Issues on Unix/Linux
+
There are two known issues that may cause the plugin to crash on initialization, possibly taking the browser down with it:
+
+
Double initialization of glib/threading. This is fixed in Qt 4.3.1 and later.
+
Symbol clash with other instances of the Qt libraries. Although Firefox/Gecko itself does not use Qt, it is not uncommon on Linux that another plugin or style engine is present that will load the Qt dynamic libraries. When another plugin based on the Qt 4 dynamically libraries are added, some symbol clashes between the different Qt instances will occur, leading to a crash. With Qt 4.4 and later, this is easily worked around by configuring your Qt build to use a separate namespace. Just add the -qtnamespace=SomeNamespace option to configure. For Qt 4.3, it is possible to work around this by building the Qt 4 library statically, and link them into the plugin executable with a special linker option. See qtbrowserplugin.pri for details.
+
+
In addition, Firefox may emit this warning when initializing the plugin: _XEMBED_INFO property has wrong type. This is fixed in Qt 4.3.1 and later.
+
+
Mac OSX specific notes
+
To build a browser plugin on Mac, two plain-text resource files are needed: an Info.plist file and a .r file. To create these files, it is easiest to use the ones provided with the QtBrowserPlugin examples as templates, editing as necessary. Then add them to your project (.pro file) like this:
After navigating away from the webpage with the plugin, and then back again, the plugin no longer shows up or runs. No workaround currently known.
+
Some painting issues. Fixed in Qt 4.3.1 and later.
+
+
+
Installing and using Plugins
+
Most browsers provide a UI to display all loaded plugins. Use this functionality to diagnose problems.
+
The plugin will need to load the Qt libraries at runtime (unless they are statically linked into the plugin). Hence, the required Qt dynamic libraries (at least QtCore, QtGui, and QtNetwork) must be located in a directory which the system searches for DLLs. This may or may not include the directory where the plugin itself is located, depending on the OS and browser.
+
Windows, Netscape-style browsers: To install the plugin, copy the plugin library in the "plugins" directory of the browser. See src/qtbrowserplugin.pri for some typical paths.
+
Windows, Internet Explorer: The Makefile generated by qmake by default runs the necessary commands to register the plugin as an ActiveX server (if CONFIG includes qaxserver). To unregister, use the following command:
Mac: The build will result in a directory called myplugin.plugin. To install, copy this directory with all contents to /Library/Internet Plugins.
+
Unix: Copy the file myplugin.so to the browser or system plugin directory, typically /usr/lib/browser-plugins. The path to the Qt libraries may be set in the LD_LIBRARY_PATH environment variable of the browser process.
+
+
Using the plugin in HTML
+
Different browser support different embedding tags, but the following should work with Netscape, FireFox, Opera and Internet Explorer (if the plugin has been compiled as an ActiveX server as well).
+
+
Object with data:
+
Objects can be initialized with a data file, which will be delivered to the plugin at some point after plugin creation to the plugin through the QtNPBindable::readData() virtual function.
<object data="http://doc.trolltech.com/3.3/graph.g1n" width=50% height=300>
+ Plugin not installed!
+ </object>
+
Note that some browsers will not display or immediately unload the plugin if the data file does not exist, while other browsers will display the plugin without ever calling readData().
+
+
Objects without data:
+
<embed type="trivial/very" [property]=[value]>
+
+
Not working with all browsers
+
+
<embed src=...> Internet Explorer does not receive data
+
<object type=...> Opera does not display plugin without data attribute
+
<object classid=...> FireFox and Netscape don't display
+
<object type=... data=...><param ...> Internet Explorer does not receive data
+
+
For additional information, see http://devedge-temp.mozilla.org/library/manuals
+
+
Scripting
+
Plugins embedded into browsers that support the respecive NPAPI extensions as well as ActiveX controls can be accessed from JavaScript in the HTML page.
Before the object can be accessed, some browsers require it to be located based on the id in the object tag.
+
+
JavaScript calling slots and properties
+
var ScriptableObject = document.getElementById('ScriptableObject');
+
Object properties and public slots can then be accessed as usual. The QtBrowserPlugin implementation supports properties and slots that have parameters and types that QVariant can be convert to and from strings, or that are QObjects. Only public slots and scriptable properties are exposed. If the QObject class sets a "ToSuperClass" Q_CLASSINFO, then only slots and properties up to the specified superclass are exposed. See the QAxServer documentation provided with Qt for more information.
+
+
The plugin calling JavaScript
+
JavaScript functions can be connected to Qt signals emitted by the Qt plugin object.
Assign a function to a property of the object with the same name as the signal. Overloads (i.e. two signal with the same name, but different parameters) are not possible.
+
<!-- Special hookup code required for Internet Explorer -->
+ <!--[if IE]>
+ <script language=JScript>
+ function ScriptableObject::mouseDown() { ScriptableObject.mouseDown() }
+ function ScriptableObject::mouseMove(x, y) { ScriptableObject.mouseMove(x, y) }
+ function ScriptableObject::mouseUp() { ScriptableObject.mouseUp() }
+ </script>
+
Internet Explorer requires a special syntax that is not compatible with other browsers, but the IE-specific function can just call the other functions.
+
+
Using plugins in forms
+
Plugin objects can be embedded as form elements. To specify which property value the plugin should report to the form upon submission, specify the name of the property as the DefaultProperty using a Q_CLASSINFO entry:
+
Q_OBJECT
+ Q_CLASSINFO("MIME", "trivial/very:xxx:Trivial and useless")
+ Q_CLASSINFO("DefaultProperty", "text")
The QtBrowserPlugin solution is useful for implementing plugins for web browser.
+
The project provides a framework that makes it simple to export widgets and objects as plugins for web browsers supporting the Netscape LiveConnect APIs.
+
Supported web browsers are Netscape, Mozilla FireFox and Opera. Internet Explorer is supported when the plugin supports ActiveX via ActiveQt.
This example demonstrates the combination of Javascript and a trivial plugin, and the use of a plugin in combination with a form.
+
If the browser supports scripting plugins, and everything is set up correctly, the plugin below should react to mouse clicks and drags by changing its text. The About... button should pop up an About Qt dialog. The second plugin instance, below the horizontal line, should display the word QtBrowserPlugin, and pressing the Go! button should navigate the browser to a search for this word at trolltech.com.
+
+
+
+
+
+
+
+
+
+
+
+
Implementation:
+
/****************************************************************************
+ **
+ ** Copyright (C) 2003-2008 Trolltech ASA. All rights reserved.
+ **
+ ** This file is part of a Qt Solutions component.
+ **
+ ** This file may be used under the terms of the GNU General Public
+ ** License version 2.0 as published by the Free Software Foundation
+ ** and appearing in the file LICENSE.GPL included in the packaging of
+ ** this file. Please review the following information to ensure GNU
+ ** General Public Licensing requirements will be met:
+ ** http://www.trolltech.com/products/qt/opensource.html
+ **
+ ** If you are unsure which license is appropriate for your use, please
+ ** review the following information:
+ ** http://www.trolltech.com/products/qt/licensing.html or contact the
+ ** Trolltech sales department at sales@trolltech.com.
+ **
+ ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ **
+ ****************************************************************************/
+ #include <QtGui>
+ #include <qtbrowserplugin.h>
+
+ class Trivial : public QWidget
+ {
+ Q_OBJECT
+ Q_PROPERTY(QString text READ text WRITE setText)
+
+ Q_CLASSINFO("ClassID", "{5a22176d-118f-4185-9653-9f98958a6df8}")
+ Q_CLASSINFO("InterfaceID", "{2df735ba-da4f-4fb7-8f35-b8dfbf8cfd9a}")
+ Q_CLASSINFO("EventsID", "{449de213-f8bd-4d2e-a2cf-eab407c03245}")
+
+ Q_CLASSINFO("MIME", "trivial/very:xxx:Trivial and useless")
+ Q_CLASSINFO("ToSuperClass", "Trivial")
+ Q_CLASSINFO("DefaultProperty", "text")
+
+ public:
+ Trivial(QWidget *parent = 0)
+ : QWidget(parent)
+ {
+ m_text = QString::fromLatin1("Empty");
+ }
+
+ void mousePressEvent(QMouseEvent *)
+ {
+ mouseDown();
+ }
+ void mouseMoveEvent(QMouseEvent *e)
+ {
+ mouseMove(e->x(), e->y());
+ }
+ void mouseReleaseEvent(QMouseEvent*)
+ {
+ mouseUp();
+ }
+ QString text() const
+ {
+ return m_text;
+ }
+
+ public slots:
+ void about()
+ {
+ QMessageBox::aboutQt(this);
+ }
+ void setText(const QString &text)
+ {
+ m_text = text;
+ update();
+ }
+
+ signals:
+ void mouseDown();
+ void mouseMove(int x, int y);
+ void mouseUp();
+
+ protected:
+ void paintEvent(QPaintEvent*)
+ {
+ QPainter p(this);
+ QRect r(rect());
+ r.adjust(0, 0, -1, -1);
+
+ p.drawRect(r);
+ p.drawText(r, Qt::AlignCenter, m_text);
+ }
+
+ private:
+ QString m_text;
+ };
+
+ #include "trivial.moc"
+
+ QTNPFACTORY_BEGIN("Trivial Qt-based Plugin", "A Qt-based LiveConnected plug-in that does nothing")
+ QTNPCLASS(Trivial)
+ QTNPFACTORY_END()
+
+ #ifdef QAXSERVER
+ #include <ActiveQt/QAxFactory>
+ QAXFACTORY_BEGIN("{aa3216bf-7e20-482c-84c6-06167bacb616}", "{08538ca5-eb7a-4f24-a3c4-a120c6e04dc4}")
+ QAXCLASS(Trivial)
+ QAXFACTORY_END()
+ #endif
This example is trivial, and thus useful for investigating problems you might have installing plugins. If everything works correctly, the trivial plugin should appear below as a rectangular field below with some text in it:
+
+
Implementation:
+
/****************************************************************************
+ **
+ ** Copyright (C) 2003-2008 Trolltech ASA. All rights reserved.
+ **
+ ** This file is part of a Qt Solutions component.
+ **
+ ** This file may be used under the terms of the GNU General Public
+ ** License version 2.0 as published by the Free Software Foundation
+ ** and appearing in the file LICENSE.GPL included in the packaging of
+ ** this file. Please review the following information to ensure GNU
+ ** General Public Licensing requirements will be met:
+ ** http://www.trolltech.com/products/qt/opensource.html
+ **
+ ** If you are unsure which license is appropriate for your use, please
+ ** review the following information:
+ ** http://www.trolltech.com/products/qt/licensing.html or contact the
+ ** Trolltech sales department at sales@trolltech.com.
+ **
+ ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ **
+ ****************************************************************************/
+ #include <QtGui>
+ #include <qtbrowserplugin.h>
+
+ class Trivial : public QWidget
+ {
+ Q_OBJECT
+ Q_PROPERTY(QString text READ text WRITE setText)
+
+ Q_CLASSINFO("ClassID", "{5a22176d-118f-4185-9653-9f98958a6df8}")
+ Q_CLASSINFO("InterfaceID", "{2df735ba-da4f-4fb7-8f35-b8dfbf8cfd9a}")
+ Q_CLASSINFO("EventsID", "{449de213-f8bd-4d2e-a2cf-eab407c03245}")
+
+ Q_CLASSINFO("MIME", "trivial/very:xxx:Trivial and useless")
+ Q_CLASSINFO("ToSuperClass", "Trivial")
+ Q_CLASSINFO("DefaultProperty", "text")
+
+ public:
+ Trivial(QWidget *parent = 0)
+ : QWidget(parent)
+ {
+ m_text = QString::fromLatin1("Empty");
+ }
+
+ void mousePressEvent(QMouseEvent *)
+ {
+ mouseDown();
+ }
+ void mouseMoveEvent(QMouseEvent *e)
+ {
+ mouseMove(e->x(), e->y());
+ }
+ void mouseReleaseEvent(QMouseEvent*)
+ {
+ mouseUp();
+ }
+ QString text() const
+ {
+ return m_text;
+ }
+
+ public slots:
+ void about()
+ {
+ QMessageBox::aboutQt(this);
+ }
+ void setText(const QString &text)
+ {
+ m_text = text;
+ update();
+ }
+
+ signals:
+ void mouseDown();
+ void mouseMove(int x, int y);
+ void mouseUp();
+
+ protected:
+ void paintEvent(QPaintEvent*)
+ {
+ QPainter p(this);
+ QRect r(rect());
+ r.adjust(0, 0, -1, -1);
+
+ p.drawRect(r);
+ p.drawText(r, Qt::AlignCenter, m_text);
+ }
+
+ private:
+ QString m_text;
+ };
+
+ #include "trivial.moc"
+
+ QTNPFACTORY_BEGIN("Trivial Qt-based Plugin", "A Qt-based LiveConnected plug-in that does nothing")
+ QTNPCLASS(Trivial)
+ QTNPFACTORY_END()
+
+ #ifdef QAXSERVER
+ #include <ActiveQt/QAxFactory>
+ QAXFACTORY_BEGIN("{aa3216bf-7e20-482c-84c6-06167bacb616}", "{08538ca5-eb7a-4f24-a3c4-a120c6e04dc4}")
+ QAXCLASS(Trivial)
+ QAXFACTORY_END()
+ #endif
The QtNPBindable class provides an interface between a widget and the web browser.
+
Inherit your plugin widget class from both QWidget (or QObject) and QtNPBindable to be able to call the functions of this class, and to reimplement the virtual functions. The meta-object compiler requires you to inherit from the QObject subclass first.
+
class PluginWidget : public QWidget, public QtNPBindable
+ {
+ Q_OBJECT
+ public:
+ PluginWidget(QWidget *parent = 0)
+ {
+ }
+
+ //...
+ };
+
+
Member Type Documentation
+
enum QtNPBindable::DisplayMode
+
This enum specifies the different display modes of a plugin
+
+
Constant
Value
Description
+
QtNPBindable::Embedded
1
The plugin widget is embedded in a web page, usually with the <EMBED> or the <OBJECT> tag.
+
QtNPBindable::Fullpage
2
The plugin widget is the primary content of the web browser, which is usually the case when the web browser displays a file the plugin supports.
+
+
enum QtNPBindable::Reason
+
This enum specifies how an URL operation was completed
Returns the browser's plugin instance associated with this plugin object. The instance is required to call functions in the Netscape Plugin API, i.e. NPN_GetJavaPeer().
+
The instance returned is only valid as long as this object is.
+
See http://devedge-temp.mozilla.org/library/manuals/2002/plugin/1.0/ for documentation of the NPP type.
Requests that the url be retrieved and sent to the named window (or a new window if window is empty), and returns the ID of the request that is delivered to transferComplete() when the get-operation has finished. Returns 0 when the browser or the system doesn't support notification, or -1 when an error occured.
Returns the parameters passed to the plugin instance.
+
The framework sets the properties of the plugin to the corresponding parameters when the plugin object has been created, but you can use this function to process additional parameters.
+
Note that the SGML specification does not permit multiple arguments with the same name.
Reimplement this function to read data from source provided with mime type format. The data is the one specified in the src or data attribute of the <EMBED> or <OBJECT> tag of in HTML page. This function is called once for every stream the browser creates for the plugin.
+
Return true to indicate successfull processing of the data, otherwise return false. The default implementation does nothing and returns false.
Called as a result of a call to openUrl, uploadData or uploadFile. url corresponds to the respective parameter, and id to value returned by the call. reason indicates how the transfer was completed.
+
int QtNPBindable::uploadData ( const QString & url, const QString & window, const QByteArray & data )
+
Posts data to url, and displays the result in window. Returns the ID of the request that is delivered to transferComplete() when the post-operation has finished. Returns 0 when the browser or the system doesn't support notification, or -1 when an error occured.
+
void MyPlugin::sendMail()
+ {
+ uploadData("mailto:fred@somewhere.com", QString(), "There is a new file for you!");
+ }
+
See Netscape's JavaScript documentation for an explanation of window names.
Posts filename to url, and displays the result in window. Returns the ID of the request that is delivered to transferComplete() when the post-operation has finished. Returns 0 when the browser or the system doesn't support notification, or -1 when an error occured.
+
diff --git a/lib/browserplugin-solution/doc/html/qtnpfactory-members.html b/lib/browserplugin-solution/doc/html/qtnpfactory-members.html
new file mode 100644
index 0000000..878ed5b
--- /dev/null
+++ b/lib/browserplugin-solution/doc/html/qtnpfactory-members.html
@@ -0,0 +1,31 @@
+
+
+
+
+
+ List of All Members for QtNPFactory
+
+
+
+
The QtNPFactory class provides the factory for plugin objects.
+
Implement this factory once in your plugin project to provide information about the plugin and to create the plugin objects. Subclass QtNPFactory and implement the pure virtual functions, and export the factory using the QTNPFACTORY_EXPORT() macro.
+
If you use the Q_CLASSINFO macro in your object classes you can use the QTNPFACTORY_BEGIN(), QTNPCLASS() and QTNPFACTORY_END() macros to generate a factory implementation:
If Qt is linked to the plugin as a dynamic library, only one instance of QApplication will exist across all plugins that have been made with Qt. So, your plugin should tread lightly on global settings. Do not, for example, use QApplication::setFont() - that will change the font in every widget of every Qt-based plugin currently loaded!
This is called by the plugin binding code just before the plugin is about to be unloaded from memory. If createObject() has been called, a QApplication will still exist at this time, but will be deleted shortly after, just before the plugin is deleted.
Reimplement this function to return the QObject or QWidget subclass supporting the mime type type, or 0 if the factory doesn't support the type requested.
+
type will be in the same form as the leftmost (mime) part of the string(s) returned by mimeTypes(), e.g. "image/png".
Reimplement this function to return the MIME types of the data formats supported by your plugin. The format of each string is mime:extension(s):description:
+
diff --git a/lib/browserplugin-solution/doc/images/qt-logo.png b/lib/browserplugin-solution/doc/images/qt-logo.png
new file mode 100644
index 0000000..fa3c518
Binary files /dev/null and b/lib/browserplugin-solution/doc/images/qt-logo.png differ
diff --git a/lib/browserplugin-solution/doc/images/trolltech-logo.png b/lib/browserplugin-solution/doc/images/trolltech-logo.png
new file mode 100644
index 0000000..7b119aa
Binary files /dev/null and b/lib/browserplugin-solution/doc/images/trolltech-logo.png differ
diff --git a/lib/browserplugin-solution/doc/index.qdoc b/lib/browserplugin-solution/doc/index.qdoc
new file mode 100644
index 0000000..2209833
--- /dev/null
+++ b/lib/browserplugin-solution/doc/index.qdoc
@@ -0,0 +1,51 @@
+/*!
+ \page index.html
+ \title Browser Plugin
+
+ \section1 Description
+
+ The QtBrowserPlugin solution is useful for implementing plugins for
+ web browser.
+
+
+
+ The project provides a framework that makes it simple to export
+ widgets and objects as plugins for web browsers supporting the Netscape
+ LiveConnect APIs.
+
+ Supported web browsers are Netscape, Mozilla FireFox and Opera.
+ Internet Explorer is supported when the plugin supports ActiveX via ActiveQt.
+
+
+ This Qt Solutions component is for Qt 4. For Qt 3 Solutions, please
+ visit \l{http://www.trolltech.com/products/qt/addon/solutions/catalog/3/}{the Qt 3 Solutions Catalog}.
+
+
+ \section1 Guidelines
+ \list
+ \i \link developingplugins.html Developing Plugins \endlink \endlist
+
+ \section1 Classes
+ \list
+ \i QtNPBindable \i QtNPFactory\endlist
+
+ \section1 Examples
+ \list
+ \i \link qtbrowserplugin-example-trivial.html A trivial "Hello, World" plugin. \endlink \i \link qtbrowserplugin-example-scripting.html A webpage that combines javascript and the trivial plugin. \endlink \i \link qtbrowserplugin-example-grapher.html A plugin widget displaying a data file as a graph. \endlink \endlist
+
+
+
+
+
+
+ \section1 Tested platforms
+ \list
+ \i Qt 4.3, 4.4 / Windows XP, Vista / MSVC.NET 2005
+ \i [experimental] Qt 4.3, 4.4 / Linux / gcc
+ \i [experimental] Qt 4.3, 4.4 / MacOS X / gcc
+ \endlist
+
+
+
+
+ */
\ No newline at end of file
diff --git a/lib/browserplugin-solution/doc/qtbrowserplugin.qdoc b/lib/browserplugin-solution/doc/qtbrowserplugin.qdoc
new file mode 100644
index 0000000..91a41ef
--- /dev/null
+++ b/lib/browserplugin-solution/doc/qtbrowserplugin.qdoc
@@ -0,0 +1,296 @@
+/*!
+
+\page developingplugins.html
+\title Developing Plugins
+
+The QtBrowserPlugin solution makes it easy to write browser plugins
+that can be used in Netscape, Mozilla FireFox, Opera, and any other
+web browser supporting the "npruntime" API:
+
+http://www.mozilla.org/projects/plugins/
+http://www.mozilla.org/projects/plugins/npruntime.html
+
+Current versions of Microsoft Internet Explorer do not support this
+API. However, you can use the ActiveQt framework to compile a
+single plugin library that works with all web browsers.
+
+\tableofcontents
+
+\section1 Implementing plugins
+
+Since any QWidget or QObject subclass can be turned into a plugin with
+little effort it is usually easiest to do the development as a
+stand-alone Qt application - debugging plugins is cumbersome.
+
+Make sure that the subclasses you want to export use the Q_OBJECT macro
+and provide a default constructor. Use the Q_CLASSINFO macro to specify
+a list of MIME types each of your classes supports, and export the
+classes through the QtNPFactory macros:
+
+\quotefromfile grapher.cpp
+\skipto QTNPFACTORY_BEGIN
+\printuntil QTNPFACTORY_END()
+
+Include the \c qtbrowserplugin.pri in your .pro file, and regenerate
+the makefile with qmake. The resulting makefile will generate a shared
+library with a file name starting with \c{"np"} - this is required
+by all browsers to recognize the library as a plugin.
+
+\section2 Windows specific notes
+
+On Windows it is required to link a version resource into the plugin
+library. To do that, create an .rc file (a plain-text file) and add
+it to the \c RC_FILE variable of your project. The .rc file needs to
+contain a version description like here:
+
+\quotefromfile grapher.rc
+\skipto VERSION
+\printuntil VarFileInfo
+\printuntil END
+\printuntil END
+
+\section3 Enabling ActiveX support
+
+To build a plugin project with ActiveX support, use ActiveQt's QAxServer
+module by adding the following line to your project:
+
+CONFIG += qaxserver
+
+Also, add the following line to your resource file
+
+\c{1 TYPELIB "thisfile.rc"}
+
+In your plugin code, use Q_CLASSINFO and the QAxFactory macros as usual.
+
+When you build the plugin, then ActiveQt will perform the build steps
+required to turn the plugin library into an ActiveX control server
+which provides your plugin classes not only to browsers supporting the
+npruntime API, but also to browsers supporting ActiveX controls
+(i.e. Internet Explorer).
+
+However, not that calling QtNPBindable APIs will not do anything when
+the browser does not support the npruntime API. In some cases, QAxBindable
+provides equivalent APIs (i.e. for reading incoming data).
+
+\section2 Unix specific notes
+
+On Unix/Linux, QtBrowserPlugin uses the XEmbed protocol. This is a
+fairly recent addition to the NPP plugin API. At the time of writing,
+it is not supported by the Opera and Konqueror browsers. Firefox and
+other Mozilla/Gecko-based browsers do support it.
+
+Update: Opera version 9.50 will support the XEmbed
+protocol. QtBrowserPlugin is tested successfully with the beta release
+of Opera 9.50. One known issue: Opera does not automatically register
+the extension part of the MIME description. If required, work around
+by adding it manually in the \c{Preferences->Advanced->Download}
+dialog. (e.g. add "g1n" to "application/x-graphable" to make the
+grapher example work).
+
+
+\section3 Known Issues on Unix/Linux
+
+There are two known issues that may cause the plugin to crash on
+initialization, possibly taking the browser down with it:
+
+\list
+\o Double initialization of glib/threading. This is fixed in Qt 4.3.1 and
+later.
+
+\o Symbol clash with other instances of the Qt libraries. Although
+Firefox/Gecko itself does not use Qt, it is not uncommon on Linux that
+another plugin or style engine is present that will load the Qt
+dynamic libraries. When another plugin based on the Qt 4 dynamically
+libraries are added, some symbol clashes between the different Qt
+instances will occur, leading to a crash. With Qt 4.4 and later, this
+is easily worked around by configuring your Qt build to use a separate
+namespace. Just add the \c{-qtnamespace=SomeNamespace} option to \c
+configure. For Qt 4.3, it is possible to work around this by
+building the Qt 4 library statically, and link them into
+the plugin executable with a special linker option. See \c
+qtbrowserplugin.pri for details.
+\endlist
+
+In addition, Firefox may emit this warning when initializing the
+plugin: \c{_XEMBED_INFO property has wrong type}. This is fixed in Qt
+4.3.1 and later.
+
+\section2 Mac OSX specific notes
+
+To build a browser plugin on Mac, two plain-text resource files are
+needed: an \c Info.plist file and a \c .r file. To create these files,
+it is easiest to use the ones provided with the QtBrowserPlugin
+examples as templates, editing as necessary. Then add them to your
+project (\c .pro file) like this:
+
+\quotefromfile grapher.pro
+\skipto QMAKE_INFO_PLIST
+\printuntil QMAKE_BUNDLE_DATA
+
+\section3 Known Issues on Mac
+
+\list
+\o After navigating away from the webpage with the plugin, and then back
+again, the plugin no longer shows up or runs. No workaround currently
+known.
+
+\o Some painting issues. Fixed in Qt 4.3.1 and later.
+\endlist
+
+\section1 Installing and using Plugins
+
+Most browsers provide a UI to display all loaded plugins. Use this
+functionality to diagnose problems.
+
+The plugin will need to load the Qt libraries at runtime (unless they
+are statically linked into the plugin). Hence, the required Qt dynamic
+libraries (at least QtCore, QtGui, and QtNetwork) must be located in a
+directory which the system searches for DLLs. This may or may not
+include the directory where the plugin itself is located, depending on
+the OS and browser.
+
+Windows, Netscape-style browsers: To install the plugin, copy the
+plugin library in the "plugins" directory of the browser. See
+\c{src/qtbrowserplugin.pri} for some typical paths.
+
+Windows, Internet Explorer: The Makefile generated by qmake by default
+runs the necessary commands to register the plugin as an ActiveX
+server (if \c CONFIG includes \c qaxserver). To unregister, use the
+following command:
+
+\code
+c:\Qt-x.y.z\bin\idc.exe path\to\myplugin.dll /unregserver
+\endcode
+
+Mac: The build will result in a directory called \c
+myplugin.plugin. To install, copy this directory with all contents to
+\c{/Library/Internet Plugins}.
+
+Unix: Copy the file \c myplugin.so to the browser or system plugin
+directory, typically \c /usr/lib/browser-plugins. The path to the Qt
+libraries may be set in the LD_LIBRARY_PATH environment variable of
+the browser process.
+
+\section2 Using the plugin in HTML
+
+Different browser support different embedding tags, but the following
+should work with Netscape, FireFox, Opera and Internet Explorer (if the
+plugin has been compiled as an ActiveX server as well).
+
+\section3 Object with data:
+
+Objects can be initialized with a data file, which will be delivered to
+the plugin at some point after plugin creation to the plugin through the
+QtNPBindable::readData() virtual function.
+\footnote
+If files viewed by a plugin are provided by an HTTP server
+(using a \c{http://...} URL) then the server must be configured to send
+the correct MIME type for the file, e.g. by editing Apache's
+\c{mime.types} file. If the files are viewed via a \c{file://...} URL,
+then the browser will use the filename extension to decide the file type
+(and hence the plugin to load) - the user may need to set the filename
+extension in the Helpers or Applications section of their browser preferences.
+\endfootnote
+
+\code
+
+\endcode
+
+\code
+
+\endcode
+
+Note that some browsers will not display or immediately unload the plugin
+if the data file does not exist, while other browsers will display the plugin
+without ever calling readData().
+
+\section3 Objects without data:
+
+\code
+