summaryrefslogtreecommitdiff
path: root/plugins/Listener/catchcopy-v0002
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/Listener/catchcopy-v0002')
-rw-r--r--plugins/Listener/catchcopy-v0002/DebugEngineMacro.h28
-rw-r--r--plugins/Listener/catchcopy-v0002/Environment.h10
-rw-r--r--plugins/Listener/catchcopy-v0002/StructEnumDefinition.h1
-rw-r--r--plugins/Listener/catchcopy-v0002/Variable.h15
-rw-r--r--plugins/Listener/catchcopy-v0002/catchcopy-api-0002/ClientCatchcopy.cpp379
-rw-r--r--plugins/Listener/catchcopy-v0002/catchcopy-api-0002/ClientCatchcopy.h113
-rw-r--r--plugins/Listener/catchcopy-v0002/catchcopy-api-0002/ExtraSocketCatchcopy.cpp38
-rw-r--r--plugins/Listener/catchcopy-v0002/catchcopy-api-0002/ExtraSocketCatchcopy.h31
-rw-r--r--plugins/Listener/catchcopy-v0002/catchcopy-api-0002/ServerCatchcopy.cpp740
-rw-r--r--plugins/Listener/catchcopy-v0002/catchcopy-api-0002/ServerCatchcopy.h144
-rw-r--r--plugins/Listener/catchcopy-v0002/catchcopy-api-0002/VariablesCatchcopy.h13
-rw-r--r--plugins/Listener/catchcopy-v0002/documentation.dox32
-rw-r--r--plugins/Listener/catchcopy-v0002/informations.xml26
-rw-r--r--plugins/Listener/catchcopy-v0002/listener.cpp123
-rw-r--r--plugins/Listener/catchcopy-v0002/listener.h59
-rw-r--r--plugins/Listener/catchcopy-v0002/listener.pro26
-rw-r--r--plugins/Listener/catchcopy-v0002/plugin.json1
17 files changed, 1779 insertions, 0 deletions
diff --git a/plugins/Listener/catchcopy-v0002/DebugEngineMacro.h b/plugins/Listener/catchcopy-v0002/DebugEngineMacro.h
new file mode 100644
index 0000000..4582010
--- /dev/null
+++ b/plugins/Listener/catchcopy-v0002/DebugEngineMacro.h
@@ -0,0 +1,28 @@
+/** \file DebugEngineMacro.h
+\brief Define the macro for the debug
+\author alpha_one_x86
+\licence GPL3, see the file COPYING */
+
+#ifndef DEBUGENGINEMACRO_H
+#define DEBUGENGINEMACRO_H
+
+#ifdef WIN32
+# define __func__ __FUNCTION__
+#endif
+
+/// \brief Macro for the debug log
+#ifdef ULTRACOPIER_PLUGIN_DEBUG
+ #if defined (__FILE__) && defined (__LINE__)
+ #define ULTRACOPIER_DEBUGCONSOLE(a,b) emit debugInformation(a,__func__,b,__FILE__,__LINE__)
+ #else
+ #define ULTRACOPIER_DEBUGCONSOLE(a,b) emit debugInformation(a,__func__,b)
+ #endif
+#else // ULTRACOPIER_DEBUG
+ #define ULTRACOPIER_DEBUGCONSOLE(a,b) void()
+#endif // ULTRACOPIER_DEBUG
+
+#endif // DEBUGENGINEMACRO_H
+
+
+
+
diff --git a/plugins/Listener/catchcopy-v0002/Environment.h b/plugins/Listener/catchcopy-v0002/Environment.h
new file mode 100644
index 0000000..265a5a6
--- /dev/null
+++ b/plugins/Listener/catchcopy-v0002/Environment.h
@@ -0,0 +1,10 @@
+/** \file Environment.h
+\brief Define the environment variable and global function
+\author alpha_one_x86
+\licence GPL3, see the file COPYING */
+
+#include "Variable.h"
+/// \brief The global include
+#include "StructEnumDefinition.h"
+#include "DebugEngineMacro.h"
+
diff --git a/plugins/Listener/catchcopy-v0002/StructEnumDefinition.h b/plugins/Listener/catchcopy-v0002/StructEnumDefinition.h
new file mode 100644
index 0000000..c1758f4
--- /dev/null
+++ b/plugins/Listener/catchcopy-v0002/StructEnumDefinition.h
@@ -0,0 +1 @@
+#include "../../../StructEnumDefinition.h"
diff --git a/plugins/Listener/catchcopy-v0002/Variable.h b/plugins/Listener/catchcopy-v0002/Variable.h
new file mode 100644
index 0000000..963d0c8
--- /dev/null
+++ b/plugins/Listener/catchcopy-v0002/Variable.h
@@ -0,0 +1,15 @@
+/** \file Variable.h
+\brief Define the environment variable
+\author alpha_one_x86
+\licence GPL3, see the file COPYING */
+
+#ifndef VARIABLE_H
+#define VARIABLE_H
+
+//Un-comment this next line to put ultracopier plugin in debug mode
+#define ULTRACOPIER_PLUGIN_DEBUG
+
+#endif // VARIABLE_H
+
+
+
diff --git a/plugins/Listener/catchcopy-v0002/catchcopy-api-0002/ClientCatchcopy.cpp b/plugins/Listener/catchcopy-v0002/catchcopy-api-0002/ClientCatchcopy.cpp
new file mode 100644
index 0000000..c466630
--- /dev/null
+++ b/plugins/Listener/catchcopy-v0002/catchcopy-api-0002/ClientCatchcopy.cpp
@@ -0,0 +1,379 @@
+/** \file ClientCatchcopy.cpp
+\brief Define the catchcopy client
+\author alpha_one_x86 */
+
+#include "ClientCatchcopy.h"
+#include "VariablesCatchcopy.h"
+#include "ExtraSocketCatchcopy.h"
+
+#include <QDataStream>
+
+ClientCatchcopy::ClientCatchcopy()
+{
+ disconnectedFromSocket();
+ error_string="Unknown error";
+ detectTimeOut.setSingleShot(true);
+ detectTimeOut.setInterval(CATCHCOPY_COMMUNICATION_TIMEOUT); // the max time to without send packet
+ connect(&socket, SIGNAL(connected()), this, SIGNAL(connected()));
+ connect(&socket, SIGNAL(disconnected()), this, SIGNAL(disconnected()));
+ connect(&socket, SIGNAL(disconnected()), this, SLOT(disconnectedFromSocket()));
+ connect(&socket, SIGNAL(stateChanged(QLocalSocket::LocalSocketState)), this, SIGNAL(stateChanged(QLocalSocket::LocalSocketState)));
+ connect(&socket, SIGNAL(error(QLocalSocket::LocalSocketError)), this, SIGNAL(errorSocket(QLocalSocket::LocalSocketError)));
+ connect(&socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
+ connect(&detectTimeOut, SIGNAL(timeout()), this, SLOT(checkTimeOut()));
+ connect(&socket, SIGNAL(connected()), this, SLOT(socketIsConnected()));
+}
+
+void ClientCatchcopy::checkTimeOut()
+{
+ if(haveData)
+ {
+ error_string="The server is too long to send the next part of the reply";
+ emit error(error_string);
+ disconnectFromServer();
+ }
+}
+
+const QString ClientCatchcopy::errorString()
+{
+ return error_string;
+}
+
+void ClientCatchcopy::socketIsConnected()
+{
+ orderIdFirstSendProtocol=sendProtocol();
+}
+
+void ClientCatchcopy::connectToServer()
+{
+ socket.connectToServer(QString::fromStdString(ExtraSocketCatchcopy::pathSocket()));
+}
+
+void ClientCatchcopy::disconnectFromServer()
+{
+ socket.abort();
+ socket.disconnectFromServer();
+}
+
+const QString ClientCatchcopy::errorStringSocket()
+{
+ return socket.errorString();
+}
+
+/// \brief to send stream of string list
+quint32 ClientCatchcopy::sendRawOrderList(const QStringList & order)
+{
+ if(!socket.isValid())
+ {
+ error_string="Socket is not valid, try send: "+order.join(";");
+ emit error(error_string);
+ return -1;
+ }
+ if(socket.state()!=QLocalSocket::ConnectedState)
+ {
+ error_string="Socket is not connected "+QString::number(socket.state());
+ emit error(error_string);
+ return -1;
+ }
+ do
+ {
+ idNextOrder++;
+ if(idNextOrder>2000000000)
+ idNextOrder=0;
+ } while(notRepliedQuery.contains(idNextOrder));
+ notRepliedQuery << idNextOrder;
+ QByteArray block;
+ QDataStream out(&block, QIODevice::WriteOnly);
+ out.setVersion(QDataStream::Qt_4_4);
+ out << int(0);
+ out << idNextOrder;
+ out << order;
+ out.device()->seek(0);
+ out << block.size();
+ if(idNextOrder!=1) // drop if internal protocol send
+ {
+ emit dataSend(idNextOrder,block);
+ emit dataSend(idNextOrder,order);
+ }
+ do //cut string list and send it as block of 32KB
+ {
+ QByteArray blockToSend;
+ int byteWriten;
+ blockToSend=block.left(32*1024);//32KB
+ block.remove(0,blockToSend.size());
+ byteWriten = socket.write(blockToSend);
+ if(!socket.isValid())
+ {
+ error_string="Socket is not valid";
+ emit error(error_string);
+ return -1;
+ }
+ if(socket.errorString()!="Unknown error" && socket.errorString()!="")
+ {
+ error_string=socket.errorString();
+ emit error(error_string);
+ return -1;
+ }
+ if(blockToSend.size()!=byteWriten)
+ {
+ error_string="All the bytes have not be written";
+ emit error(error_string);
+ return -1;
+ }
+ }
+ while(block.size());
+ return idNextOrder;
+}
+
+void ClientCatchcopy::readyRead()
+{
+ while(socket.bytesAvailable()>0)
+ {
+ if(!haveData)
+ {
+ if(socket.bytesAvailable()<(int)sizeof(int))//int of size cuted
+ {
+ /* error_string="Bytes available is not sufficient to do a int";
+ emit error(error_string);
+ disconnectFromServer();*/
+ return;
+ }
+ QDataStream in(&socket);
+ in.setVersion(QDataStream::Qt_4_4);
+ in >> dataSize;
+ dataSize-=sizeof(int);
+ if(dataSize>64*1024*1024) // 64MB
+ {
+ error_string="Reply size is >64MB, seam corrupted";
+ emit error(error_string);
+ disconnectFromServer();
+ return;
+ }
+ if(dataSize<(int)(sizeof(int) //orderId
+ + sizeof(quint32) //returnCode
+ + sizeof(quint32) //string list size
+ ))
+ {
+ error_string="Reply size is too small to have correct code";
+ emit error(error_string);
+ disconnectFromServer();
+ return;
+ }
+ }
+ if(dataSize<(data.size()+socket.bytesAvailable()))
+ data.append(socket.read(dataSize-data.size()));
+ else
+ data.append(socket.readAll());
+ if(dataSize==data.size())
+ {
+ if(!checkDataIntegrity(data))
+ {
+ data.clear();
+ qWarning() << "Data of the reply is wrong";
+ return;
+ }
+ QStringList returnList;
+ quint32 orderId;
+ quint32 returnCode;
+ QDataStream in(data);
+ in.setVersion(QDataStream::Qt_4_4);
+ in >> orderId;
+ in >> returnCode;
+ in >> returnList;
+ data.clear();
+ if(orderId!=orderIdFirstSendProtocol)
+ {
+ if(!notRepliedQuery.contains(orderId))
+ qWarning() << "Unknown query not replied:" << orderId;
+ else
+ {
+ if(!parseReply(orderId,returnCode,returnList))
+ emit unknowReply(orderId);
+ emit newReply(orderId,returnCode,returnList);
+ }
+ }
+ else
+ {
+ if(!sendProtocolReplied)
+ {
+ sendProtocolReplied=true;
+ if(returnCode!=1000)
+ {
+ error_string="Protocol not supported";
+ emit error(error_string);
+ disconnectFromServer();
+ return;
+ }
+ }
+ else
+ {
+ error_string=QStringLiteral("First send protocol send with the query id %1 have been already previously replied").arg(orderIdFirstSendProtocol);
+ emit error(error_string);
+ disconnectFromServer();
+ return;
+ }
+ }
+ }
+ }
+ if(haveData)
+ detectTimeOut.start();
+ else
+ detectTimeOut.stop();
+}
+
+bool ClientCatchcopy::checkDataIntegrity(QByteArray data)
+{
+ quint32 orderId;
+ qint32 replyCode;
+ qint32 listSize;
+ QDataStream in(data);
+ in.setVersion(QDataStream::Qt_4_4);
+ in >> orderId;
+ in >> replyCode;
+ in >> listSize;
+ if(listSize>65535)
+ {
+ emit error("List size is wrong");
+ qWarning() << "List size is wrong";
+ return false;
+ }
+ int index=0;
+ while(index<listSize)
+ {
+ qint32 stringSize;
+ in >> stringSize;
+ if(stringSize>65535)
+ {
+ emit error("String size is wrong");
+ qWarning() << "String size is wrong";
+ return false;
+ }
+ if(stringSize>(in.device()->size()-in.device()->pos()))
+ {
+ emit error(QStringLiteral("String size is greater than the data: %1>(%2-%3)").arg(stringSize).arg(in.device()->size()).arg(in.device()->pos()));
+ qWarning() << QStringLiteral("String size is greater than the data: %1>(%2-%3)").arg(stringSize).arg(in.device()->size()).arg(in.device()->pos());
+ return false;
+ }
+ in.device()->seek(in.device()->pos()+stringSize);
+ index++;
+ }
+ if(in.device()->size()!=in.device()->pos())
+ {
+ emit error("Remaining data after string list parsing");
+ qWarning() << "Remaining data after string list parsing";
+ return false;
+ }
+ return true;
+}
+
+QLocalSocket::LocalSocketState ClientCatchcopy::state()
+{
+ return socket.state();
+}
+
+void ClientCatchcopy::disconnectedFromSocket()
+{
+ haveData = false;
+ orderIdFirstSendProtocol= 0;
+ idNextOrder = 0;
+ sendProtocolReplied = false;
+ notRepliedQuery.clear();
+}
+
+/// \brief to send the protocol version used
+quint32 ClientCatchcopy::sendProtocol()
+{
+ return sendRawOrderList(QStringList() << "protocol" << CATCHCOPY_PROTOCOL_VERSION);
+}
+
+quint32 ClientCatchcopy::askServerName()
+{
+ return sendRawOrderList(QStringList() << "server" << "name?");
+}
+
+quint32 ClientCatchcopy::setClientName(const QString & name)
+{
+ return sendRawOrderList(QStringList() << "client" << name);
+}
+
+quint32 ClientCatchcopy::checkProtocolExtension(const QString & name)
+{
+ return sendRawOrderList(QStringList() << "protocol extension" << name);
+}
+
+quint32 ClientCatchcopy::checkProtocolExtension(const QString & name,const QString & version)
+{
+ return sendRawOrderList(QStringList() << "protocol extension" << name << version);
+}
+
+quint32 ClientCatchcopy::addCopyWithDestination(const QStringList & sources,const QString & destination)
+{
+ return sendRawOrderList(QStringList() << "cp" << sources << destination);
+}
+
+quint32 ClientCatchcopy::addCopyWithoutDestination(const QStringList & sources)
+{
+ return sendRawOrderList(QStringList() << "cp-?" << sources);
+}
+
+quint32 ClientCatchcopy::addMoveWithDestination(const QStringList & sources,const QString & destination)
+{
+ return sendRawOrderList(QStringList() << "mv" << sources << destination);
+}
+
+quint32 ClientCatchcopy::addMoveWithoutDestination(const QStringList & sources)
+{
+ return sendRawOrderList(QStringList() << "mv-?" << sources);
+}
+
+bool ClientCatchcopy::parseReply(quint32 orderId,quint32 returnCode,QStringList returnList)
+{
+ switch(returnCode)
+ {
+ case 1000:
+ emit protocolSupported(orderId);
+ break;
+ case 1001:
+ case 1002:
+ if(returnCode==1001)
+ emit protocolExtensionSupported(orderId,true);
+ else
+ emit protocolExtensionSupported(orderId,false);
+ break;
+ case 1003:
+ emit clientRegistered(orderId);
+ break;
+ case 1004:
+ if(returnList.size()!=1)
+ emit unknowOrder(orderId);
+ else
+ emit serverName(orderId,returnList.last());
+ break;
+ case 1005:
+ case 1006:
+ if(returnCode==1005)
+ emit copyFinished(orderId,false);
+ else
+ emit copyFinished(orderId,true);
+ break;
+ case 1007:
+ emit copyCanceled(orderId);
+ break;
+ case 5000:
+ emit incorrectArgumentListSize(orderId);
+ break;
+ case 5001:
+ emit incorrectArgument(orderId);
+ break;
+ case 5002:
+ emit unknowOrder(orderId); //the server have not understand the order
+ break;
+ case 5003:
+ emit protocolNotSupported(orderId);
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
diff --git a/plugins/Listener/catchcopy-v0002/catchcopy-api-0002/ClientCatchcopy.h b/plugins/Listener/catchcopy-v0002/catchcopy-api-0002/ClientCatchcopy.h
new file mode 100644
index 0000000..4c15890
--- /dev/null
+++ b/plugins/Listener/catchcopy-v0002/catchcopy-api-0002/ClientCatchcopy.h
@@ -0,0 +1,113 @@
+/** \file ClientCatchcopy.h
+\brief Define the catchcopy client
+\author alpha_one_x86
+\licence GPL3, see the file COPYING */
+
+#ifndef CLIENTCATCHCOPY_H
+#define CLIENTCATCHCOPY_H
+
+#include <QObject>
+#include <QLocalSocket>
+#include <QStringList>
+#include <QString>
+#include <QByteArray>
+#include <QTimer>
+
+/// \brief Define the catchcopy client
+class ClientCatchcopy : public QObject
+{
+ Q_OBJECT
+ public:
+ ClientCatchcopy();
+ /// \brief get the socket stat
+ QLocalSocket::LocalSocketState state();
+ /// \brief error string about the socket
+ const QString errorStringSocket();
+ /// \brief general error string
+ const QString errorString();
+ public slots:
+ void connectToServer();
+ void disconnectFromServer();
+ //to test and internal use
+ /// \brief to send order
+ quint32 sendProtocol();
+ /// \brief ask the server name
+ quint32 askServerName();
+ /// \brief set the client name
+ quint32 setClientName(const QString & name);
+ /// \brief check protocol extension
+ quint32 checkProtocolExtension(const QString & name);
+ /// \brief check protocol extension and version
+ quint32 checkProtocolExtension(const QString & name,const QString & version);
+ /// \brief add copy with destination
+ quint32 addCopyWithDestination(const QStringList & sources,const QString & destination);
+ /// \brief add copy without destination
+ quint32 addCopyWithoutDestination(const QStringList & sources);
+ /// \brief add move with destination
+ quint32 addMoveWithDestination(const QStringList & sources,const QString & destination);
+ /// \brief add move without destination
+ quint32 addMoveWithoutDestination(const QStringList & sources);
+ /// \brief to send stream of string list
+ quint32 sendRawOrderList(const QStringList & order);
+ signals:
+ /// \brief is connected
+ void connected();
+ /// \brief is disconnected
+ void disconnected();
+ /// \brief the socket state have changed
+ void stateChanged(QLocalSocket::LocalSocketState socketState);
+ /// \brief send the error string
+ void error(QString error);
+ /// \brief send socket error
+ void errorSocket(QLocalSocket::LocalSocketError socketError);
+ /// \brief have new reply
+ void newReply(quint32 orderId,quint32 returnCode,QStringList returnList);
+ /// \brief have data send
+ void dataSend(quint32 orderId,QByteArray data);
+ /// \brief have data send by string list
+ void dataSend(quint32 orderId,QStringList data);
+ /// \brief have unknow reply
+ void unknowReply(quint32 orderId);
+ //reply
+ /// \brief protocol is supported
+ void protocolSupported(quint32 orderId);
+ /// \brief incorrect argument list size
+ void incorrectArgumentListSize(quint32 orderId);
+ /// \brief incorrect argument
+ void incorrectArgument(quint32 orderId);
+ /// \brief protocol not supported
+ void protocolNotSupported(quint32 orderId);
+ /// \brief protocol extension supported
+ void protocolExtensionSupported(quint32 orderId,bool isSupported);
+ /// \brief client is registred
+ void clientRegistered(quint32 orderId);
+ /// \brief have the server name
+ void serverName(quint32 orderId,QString name);
+ /// \brief copy finished
+ void copyFinished(quint32 orderId,bool withError);
+ /// \brief copy canceled
+ void copyCanceled(quint32 orderId);
+ /// \brief have unknow order
+ void unknowOrder(quint32 orderId); //the server have not understand the order
+ private:
+ QLocalSocket socket;
+ QString error_string;
+ quint32 idNextOrder;
+ QByteArray data;
+ bool haveData;
+ int dataSize;
+ quint32 orderIdFirstSendProtocol;
+ QTimer detectTimeOut;
+ bool sendProtocolReplied;
+ QList<quint32> notRepliedQuery;
+ bool checkDataIntegrity(QByteArray data);
+ private slots:
+ void readyRead();
+ void disconnectedFromSocket();
+ void socketIsConnected();
+ void checkTimeOut();
+ protected:
+ bool parseReply(quint32 orderId,quint32 returnCode,QStringList returnList);
+};
+
+#endif // CLIENTCATCHCOPY_H
diff --git a/plugins/Listener/catchcopy-v0002/catchcopy-api-0002/ExtraSocketCatchcopy.cpp b/plugins/Listener/catchcopy-v0002/catchcopy-api-0002/ExtraSocketCatchcopy.cpp
new file mode 100644
index 0000000..9cd8373
--- /dev/null
+++ b/plugins/Listener/catchcopy-v0002/catchcopy-api-0002/ExtraSocketCatchcopy.cpp
@@ -0,0 +1,38 @@
+/** \file ExtraSocketCatchcopy.cpp
+\brief Define the socket of catchcopy
+\author alpha_one_x86 */
+
+#include "ExtraSocketCatchcopy.h"
+
+#include <stdio.h>
+
+const std::string ExtraSocketCatchcopy::pathSocket()
+{
+#ifdef Q_OS_UNIX
+ return "advanced-copier-"+std::to_string(getuid());
+#else
+ QString userName;
+ char uname[1024];
+ DWORD len=1023;
+ if(GetUserNameA(uname, &len)!=FALSE)
+ userName=QString::fromLatin1(toHex(uname));
+ return "advanced-copier-"+userName.toStdString();
+#endif
+}
+
+char * ExtraSocketCatchcopy::toHex(const char *str)
+{
+ char *p, *sz;
+ size_t len;
+ if (str==NULL)
+ return NULL;
+ len= strlen(str);
+ p = sz = (char *) malloc((len+1)*4);
+ for (size_t i=0; i<len; i++)
+ {
+ sprintf(p, "%.2x00", str[i]);
+ p+=4;
+ }
+ *p=0;
+ return sz;
+}
diff --git a/plugins/Listener/catchcopy-v0002/catchcopy-api-0002/ExtraSocketCatchcopy.h b/plugins/Listener/catchcopy-v0002/catchcopy-api-0002/ExtraSocketCatchcopy.h
new file mode 100644
index 0000000..fb4201c
--- /dev/null
+++ b/plugins/Listener/catchcopy-v0002/catchcopy-api-0002/ExtraSocketCatchcopy.h
@@ -0,0 +1,31 @@
+/** \file ExtraSocketCatchcopy.h
+\brief Define the socket of catchcopy
+\author alpha_one_x86
+\licence GPL3, see the file COPYING */
+
+#ifndef EXTRASOCKETCATCHCOPY_H
+#define EXTRASOCKETCATCHCOPY_H
+
+#include <string>
+#include <QString>
+
+#ifdef Q_OS_UNIX
+ #include <unistd.h>
+ #include <sys/types.h>
+#else
+ #ifndef NOMINMAX
+ #define NOMINMAX
+ #endif
+ #include <windows.h>
+#endif
+
+/// \brief to have extra socket function
+class ExtraSocketCatchcopy
+{
+public:
+ /// \brief to get the socket path
+ static const std::string pathSocket();
+ static char * toHex(const char *str);
+};
+
+#endif // EXTRASOCKETCATCHCOPY_H
diff --git a/plugins/Listener/catchcopy-v0002/catchcopy-api-0002/ServerCatchcopy.cpp b/plugins/Listener/catchcopy-v0002/catchcopy-api-0002/ServerCatchcopy.cpp
new file mode 100644
index 0000000..6fd1172
--- /dev/null
+++ b/plugins/Listener/catchcopy-v0002/catchcopy-api-0002/ServerCatchcopy.cpp
@@ -0,0 +1,740 @@
+/** \file ServerCatchcopy.cpp
+\brief Define the server of catchcopy
+\author alpha_one_x86*/
+
+#include "ServerCatchcopy.h"
+#include "VariablesCatchcopy.h"
+#include "ExtraSocketCatchcopy.h"
+
+#include <QFile>
+#include <QDataStream>
+#include <queue>
+#include <vector>
+#include <string>
+
+std::string stringimplode2(const std::vector<std::string>& elems, const std::string &delim)
+{
+ std::string newString;
+ for (std::vector<std::string>::const_iterator ii = elems.begin(); ii != elems.cend(); ++ii)
+ {
+ newString += (*ii);
+ if ( ii + 1 != elems.end() ) {
+ newString += delim;
+ }
+ }
+ return newString;
+}
+
+ServerCatchcopy::ServerCatchcopy()
+{
+ name="Default avanced copier";
+ idNextClient=0;
+ error_string="Unknown error";
+ connect(&server, &QLocalServer::newConnection, this, &ServerCatchcopy::newConnection);
+}
+
+ServerCatchcopy::~ServerCatchcopy()
+{
+ close();
+}
+
+bool ServerCatchcopy::isListening() const
+{
+ return server.isListening();
+}
+
+void ServerCatchcopy::setName(const std::string & name)
+{
+ this->name=name;
+}
+
+std::string ServerCatchcopy::getName() const
+{
+ return name;
+}
+
+/// \brief to get a client list
+std::vector<std::string> ServerCatchcopy::clientsList() const
+{
+ std::vector<std::string> clients;
+ int index=0;
+ int size=clientList.size();
+ while(index<size)
+ {
+ clients.push_back(clientList[index].name);
+ index++;
+ }
+ return clients;
+}
+
+bool ServerCatchcopy::listen()
+{
+ QLocalSocket socketTestConnection;
+ pathSocket=ExtraSocketCatchcopy::pathSocket();
+ socketTestConnection.connectToServer(QString::fromStdString(pathSocket));
+ if(socketTestConnection.waitForConnected(CATCHCOPY_COMMUNICATION_TIMEOUT))
+ {
+ error_string="Other server is listening";
+ emit error(error_string);
+ return false;
+ }
+ else
+ {
+ if(!server.removeServer(QString::fromStdString(pathSocket)))
+ {
+ error_string="Unable to remove the old server";
+ emit error(error_string);
+ }
+ #ifndef Q_OS_MAC
+ server.setSocketOptions(QLocalServer::UserAccessOption);
+ #endif
+ if(server.listen(QString::fromStdString(pathSocket)))
+ return true;
+ else
+ {
+ error_string=QStringLiteral("Unable to listen %1: %2").arg(QString::fromStdString(pathSocket)).arg(server.errorString()).toStdString();
+ emit error(error_string);
+ return false;
+ }
+ }
+}
+
+void ServerCatchcopy::close()
+{
+ if(server.isListening())
+ {
+ int index=0;
+ while(index<clientList.size())
+ {
+ clientList.at(index).socket->disconnectFromServer();
+ index++;
+ }
+ server.close();
+ if(!server.removeServer(QString::fromStdString(pathSocket)))
+ {
+ error_string="Unable to remove the old server";
+ emit error(error_string);
+ }
+ }
+}
+
+const std::string ServerCatchcopy::errorStringServer() const
+{
+ return server.errorString().toStdString();
+}
+
+const std::string ServerCatchcopy::errorString() const
+{
+ return error_string;
+}
+
+/// \brief New connexion
+void ServerCatchcopy::newConnection()
+{
+ while(server.hasPendingConnections())
+ {
+ QLocalSocket *clientSocket = server.nextPendingConnection();
+ if(clientSocket!=NULL)
+ {
+ do
+ {
+ idNextClient++;
+ if(idNextClient>2000000000)
+ idNextClient=0;
+ } while(clientIdFound(idNextClient));
+ Client newClient;
+ newClient.id = idNextClient;
+ newClient.socket = clientSocket;
+ newClient.haveData = false;
+ newClient.firstProtocolReplied = false;
+ newClient.detectTimeOut = new QTimer(this);
+ newClient.detectTimeOut->setSingleShot(true);
+ newClient.detectTimeOut->setInterval(CATCHCOPY_COMMUNICATION_TIMEOUT);
+ newClient.name="Unknown";
+ connect(newClient.socket, static_cast<void(QLocalSocket::*)(QLocalSocket::LocalSocketError)>(&QLocalSocket::error), this, &ServerCatchcopy::connectionError,Qt::QueuedConnection);
+ connect(newClient.socket, &QIODevice::readyRead, this, &ServerCatchcopy::readyRead,Qt::QueuedConnection);
+ connect(newClient.socket, &QLocalSocket::disconnected, this, &ServerCatchcopy::disconnected,Qt::QueuedConnection);
+ connect(newClient.detectTimeOut,&QTimer::timeout, this, &ServerCatchcopy::checkTimeOut,Qt::QueuedConnection);
+ clientList << newClient;
+ emit connectedClient(newClient.id);
+ }
+ }
+}
+
+bool ServerCatchcopy::clientIdFound(const uint32_t &id) const
+{
+ int index=0;
+ while(index<clientList.size())
+ {
+ if(clientList.at(index).id==id)
+ return true;
+ index++;
+ }
+ return false;
+}
+
+/// \brief new error at connexion
+void ServerCatchcopy::connectionError(const QLocalSocket::LocalSocketError &error)
+{
+ QLocalSocket *socket=qobject_cast<QLocalSocket *>(QObject::sender());
+ if(socket==NULL)
+ {
+ qWarning() << "Unlocated client socket!";
+ return;
+ }
+ int index=0;
+ while(index<clientList.size())
+ {
+ if(clientList.at(index).socket==socket)
+ {
+ if(error!=QLocalSocket::PeerClosedError)
+ {
+ qWarning() << "error detected for the client: " << index << ", type: " << error;
+ clientList.at(index).socket->disconnectFromServer();
+ }
+ return;
+ }
+ index++;
+ }
+}
+
+void ServerCatchcopy::disconnected()
+{
+ QLocalSocket *socket=qobject_cast<QLocalSocket *>(QObject::sender());
+ if(socket==NULL)
+ {
+ qWarning() << "Unlocated client socket!";
+ return;
+ }
+ int index=0;
+ while(index<clientList.size())
+ {
+ if(clientList.at(index).socket==socket)
+ {
+ const uint32_t &id=clientList.at(index).id;
+ //ClientList.at(index).socket->disconnectFromServer();//already disconnected
+ delete clientList.at(index).detectTimeOut;
+ clientList.at(index).socket->deleteLater();
+ clientList.removeAt(index);
+ emit disconnectedClient(id);
+ return;
+ }
+ index++;
+ }
+ qWarning() << "Unlocated client!";
+}
+
+void ServerCatchcopy::disconnectClient(const uint32_t &id)
+{
+ int index=0;
+ while(index<clientList.size())
+ {
+ if(clientList.at(index).id==id)
+ {
+ clientList.at(index).socket->disconnectFromServer();
+ return;
+ }
+ index++;
+ }
+ qWarning() << "Unlocated client!";
+}
+
+void ServerCatchcopy::readyRead()
+{
+ QLocalSocket *socket=qobject_cast<QLocalSocket *>(QObject::sender());
+ if(socket==NULL)
+ {
+ qWarning() << "Unlocated client socket!";
+ return;
+ }
+ int index=0;
+ while(index<clientList.size())
+ {
+ if(clientList.at(index).socket==socket)
+ {
+ while(socket->bytesAvailable()>0)
+ {
+ if(!clientList.at(index).haveData)
+ {
+ if(socket->bytesAvailable()<(int)sizeof(int))//ignore because first int is cuted!
+ {
+ /*error_string="Bytes available is not sufficient to do a int";
+ emit error(error_string);
+ disconnectClient(ClientList.at(index).id);*/
+ return;
+ }
+ QDataStream in(socket);
+ in.setVersion(QDataStream::Qt_4_4);
+ in >> clientList[index].dataSize;
+ clientList[index].dataSize-=sizeof(int);
+ if(clientList.at(index).dataSize>64*1024*1024) // 64MB
+ {
+ error_string="Reply size is >64MB, seam corrupted";
+ emit communicationError(error_string);
+ disconnectClient(clientList.at(index).id);
+ return;
+ }
+ if(clientList.at(index).dataSize<(int)(sizeof(int) //orderId
+ + sizeof(uint32_t) //returnCode
+ + sizeof(uint32_t) //string list size
+ ))
+ {
+ error_string="Reply size is too small to have correct code";
+ emit communicationError(error_string);
+ disconnectClient(clientList.at(index).id);
+ return;
+ }
+ clientList[index].haveData=true;
+ }
+ if(clientList.at(index).dataSize<(clientList.at(index).data.size()+socket->bytesAvailable()))
+ clientList[index].data.append(socket->read(clientList.at(index).dataSize-clientList.at(index).data.size()));
+ else
+ clientList[index].data.append(socket->readAll());
+ if(clientList.at(index).dataSize==(uint32_t)clientList.at(index).data.size())
+ {
+ if(!checkDataIntegrity(clientList.at(index).data))
+ {
+ emit communicationError("Data integrity wrong: "+QString(clientList.at(index).data.toHex()).toStdString());
+ clientList[index].data.clear();
+ clientList[index].haveData=false;
+ qWarning() << "Data integrity wrong";
+ return;
+ }
+ std::vector<std::string> returnList;
+ QStringList returnListQt;
+ uint32_t orderId;
+ QDataStream in(clientList.at(index).data);
+ in.setVersion(QDataStream::Qt_4_4);
+ in >> orderId;
+ in >> returnListQt;
+ {
+ int index=0;
+ while(index<returnListQt.size())
+ {
+ returnList.push_back(returnListQt.at(index).toStdString());
+ index++;
+ }
+ }
+ clientList[index].data.clear();
+ clientList[index].haveData=false;
+ if(clientList.at(index).queryNoReplied.contains(orderId))
+ {
+ emit communicationError("Duplicate query id");
+ qWarning() << "Duplicate query id";
+ return;
+ }
+ clientList[index].queryNoReplied << orderId;
+ if(!clientList.at(index).firstProtocolReplied && returnList.size()==2 && returnList.front()=="protocol")
+ {
+ clientList[index].firstProtocolReplied=true;
+ protocolSupported(clientList.at(index).id,orderId,(returnList.back()==CATCHCOPY_PROTOCOL_VERSION));
+ }
+ else
+ parseInput(clientList.at(index).id,orderId,returnList);
+ }
+ }
+ if(clientList.at(index).haveData)
+ clientList.at(index).detectTimeOut->start();
+ else
+ clientList.at(index).detectTimeOut->stop();
+ return;
+ }
+ index++;
+ }
+ emit error("Unallocated client!");
+ qWarning() << "Unallocated client!";
+}
+
+bool ServerCatchcopy::checkDataIntegrity(const QByteArray &data)
+{
+ uint32_t orderId;
+ qint32 listSize;
+ QDataStream in(data);
+ in.setVersion(QDataStream::Qt_4_4);
+ in >> orderId;
+ in >> listSize;
+ if(listSize>65535)
+ {
+ emit error("List size is wrong");
+ qWarning() << "List size is wrong";
+ return false;
+ }
+ int index=0;
+ while(index<listSize)
+ {
+ qint32 stringSize;
+ in >> stringSize;
+ if(stringSize>65535)
+ {
+ emit error("String size is wrong");
+ return false;
+ }
+ if(stringSize>(in.device()->size()-in.device()->pos()))
+ {
+ emit error(QStringLiteral("String size is greater than the data: %1>(%2-%3)").arg(stringSize).arg(in.device()->size()).arg(in.device()->pos()).toStdString());
+ return false;
+ }
+ in.device()->seek(in.device()->pos()+stringSize);
+ index++;
+ }
+ if(in.device()->size()!=in.device()->pos())
+ {
+ emit error("Remaining data after string list parsing");
+ return false;
+ }
+ return true;
+}
+
+void ServerCatchcopy::parseInput(const uint32_t &client,const uint32_t &orderId,const std::vector<std::string> &returnList)
+{
+ const ServerCatchcopy::inputReturnType returnVal=parseInputCurrentProtocol(client,orderId,returnList);
+ switch(returnVal)
+ {
+ case Ok:
+ emit newQuery(client,orderId,returnList);
+ break;
+ case Replied:
+ break;
+ case ExtensionWrong:
+ //protocolExtensionSupported(client,orderId,false);
+ break;
+ case WrongArgument:
+ incorrectArgument(client,orderId);
+ break;
+ case WrongArgumentListSize:
+ incorrectArgumentListSize(client,orderId);
+ break;
+ case UnknowOrder:
+ emit error("Unknown query: "+std::to_string(returnVal)+", with client: "+std::to_string(client)+", orderId: "+std::to_string(orderId)+", returnList: "+stringimplode2(returnList,", "));
+ qWarning() << "Unknown query";
+ unknowOrder(client,orderId);
+ break;
+ }
+}
+
+ServerCatchcopy::inputReturnType ServerCatchcopy::parseInputCurrentProtocol(const uint32_t &client,const uint32_t &orderId,const std::vector<std::string> &returnList)
+{
+ if(returnList.size()==0)
+ return WrongArgumentListSize;
+ //if is supported
+ std::string firstArgument=returnList.front();
+ if(firstArgument=="protocol")
+ {
+ if(returnList.size()!=2)
+ return WrongArgumentListSize;
+ emit askProtocolCompatibility(client,orderId,returnList.back());
+ return Ok;
+ }
+ else if(firstArgument=="protocol extension")
+ {
+ if(returnList.size()>3 || returnList.size()<2)
+ return WrongArgumentListSize;
+ return ExtensionWrong;
+ }
+ else if(firstArgument=="client")
+ {
+ if(returnList.size()!=2)
+ return WrongArgumentListSize;
+ int index=0;
+ int size=clientList.size();
+ while(index<size)
+ {
+ if(clientList.at(index).id==client)
+ {
+ clientList[index].name=returnList.back();
+ break;
+ }
+ index++;
+ }
+ emit clientName(client,returnList.back());
+ clientRegistered(client,orderId);
+ return Replied;
+ }
+ else if(firstArgument=="server")
+ {
+ if(returnList.size()!=2)
+ return WrongArgumentListSize;
+ if(returnList.back()!="name?")
+ return WrongArgument;
+ serverName(client,orderId,name);
+ return Replied;
+ }
+ else if(firstArgument=="cp")
+ {
+ if(returnList.size()<3)
+ return WrongArgumentListSize;
+ std::vector<std::string> sourceList=returnList;
+ sourceList.erase(sourceList.cbegin());
+ sourceList.pop_back();
+ emitNewCopy(client,orderId,sourceList,returnList.back());
+ return Ok;
+ }
+ else if(firstArgument=="cp-?")
+ {
+ if(returnList.size()<2)
+ return WrongArgumentListSize;
+ std::vector<std::string> sourceList=returnList;
+ sourceList.erase(sourceList.cbegin());
+ emitNewCopyWithoutDestination(client,orderId,sourceList);
+ return Ok;
+ }
+ else if(firstArgument=="mv")
+ {
+ if(returnList.size()<3)
+ return WrongArgumentListSize;
+ std::vector<std::string> sourceList=returnList;
+ sourceList.erase(sourceList.cbegin());
+ sourceList.pop_back();
+ emitNewMove(client,orderId,sourceList,returnList.back());
+ return Ok;
+ }
+ else if(firstArgument=="mv-?")
+ {
+ if(returnList.size()<2)
+ return WrongArgumentListSize;
+ std::vector<std::string> sourceList=returnList;
+ sourceList.erase(sourceList.cbegin());
+ emitNewMoveWithoutDestination(client,orderId,sourceList);
+ return Ok;
+ }
+ else //if is not supported
+ return UnknowOrder;
+}
+
+void ServerCatchcopy::emitNewCopyWithoutDestination(const uint32_t &client,const uint32_t &orderId,const std::vector<std::string> &sources)
+{
+ LinkGlobalToLocalClient newAssociation;
+ newAssociation.idClient=client;
+ newAssociation.orderId=orderId;
+ newAssociation.globalOrderId=incrementOrderId();
+ LinkGlobalToLocalClientList << newAssociation;
+ emit newCopyWithoutDestination(newAssociation.globalOrderId,sources);
+}
+
+void ServerCatchcopy::emitNewCopy(const uint32_t &client,const uint32_t &orderId,const std::vector<std::string> &sources,const std::string &destination)
+{
+ LinkGlobalToLocalClient newAssociation;
+ newAssociation.idClient=client;
+ newAssociation.orderId=orderId;
+ newAssociation.globalOrderId=incrementOrderId();
+ LinkGlobalToLocalClientList << newAssociation;
+ emit newCopy(newAssociation.globalOrderId,sources,destination);
+}
+
+void ServerCatchcopy::emitNewMoveWithoutDestination(const uint32_t &client,const uint32_t &orderId,const std::vector<std::string> &sources)
+{
+ LinkGlobalToLocalClient newAssociation;
+ newAssociation.idClient=client;
+ newAssociation.orderId=orderId;
+ newAssociation.globalOrderId=incrementOrderId();
+ LinkGlobalToLocalClientList << newAssociation;
+ emit newMoveWithoutDestination(newAssociation.globalOrderId,sources);
+}
+
+void ServerCatchcopy::emitNewMove(const uint32_t &client,const uint32_t &orderId,const std::vector<std::string> &sources,const std::string &destination)
+{
+ LinkGlobalToLocalClient newAssociation;
+ newAssociation.idClient=client;
+ newAssociation.orderId=orderId;
+ newAssociation.globalOrderId=incrementOrderId();
+ LinkGlobalToLocalClientList << newAssociation;
+ emit newMove(newAssociation.globalOrderId,sources,destination);
+}
+
+void ServerCatchcopy::copyFinished(const uint32_t &globalOrderId,const bool &withError)
+{
+ int index=0;
+ while(index<LinkGlobalToLocalClientList.size())
+ {
+ if(LinkGlobalToLocalClientList.at(index).globalOrderId==globalOrderId)
+ {
+ copyFinished(LinkGlobalToLocalClientList.at(index).idClient,LinkGlobalToLocalClientList.at(index).orderId,withError);
+ LinkGlobalToLocalClientList.removeAt(index);
+ orderList.removeOne(globalOrderId);
+ return;
+ }
+ index++;
+ }
+}
+
+void ServerCatchcopy::copyCanceled(const uint32_t &globalOrderId)
+{
+ int index=0;
+ while(index<LinkGlobalToLocalClientList.size())
+ {
+ if(LinkGlobalToLocalClientList.at(index).globalOrderId==globalOrderId)
+ {
+ copyCanceled(LinkGlobalToLocalClientList.at(index).idClient,LinkGlobalToLocalClientList.at(index).orderId);
+ LinkGlobalToLocalClientList.removeAt(index);
+ orderList.removeOne(globalOrderId);
+ return;
+ }
+ index++;
+ }
+}
+
+void ServerCatchcopy::reply(const uint32_t &client,const uint32_t &orderId,const uint32_t &returnCode,const std::string &returnString)
+{
+ std::vector<std::string> returnList;
+ returnList.push_back(returnString);
+ reply(client,orderId,returnCode,returnList);
+}
+
+void ServerCatchcopy::reply(const uint32_t &client,const uint32_t &orderId,const uint32_t &returnCode,const std::vector<std::string> &returnList)
+{
+ int index=0;
+ while(index<clientList.size())
+ {
+ if(clientList.at(index).id==client)
+ {
+ if(clientList.at(index).socket->isValid() && clientList.at(index).socket->state()==QLocalSocket::ConnectedState)
+ {
+ if(!clientList.at(index).queryNoReplied.contains(orderId))
+ {
+ qWarning() << "Reply to missing query or previously replied";
+ return;
+ }
+ clientList[index].queryNoReplied.removeOne(orderId);
+ //cut string list and send it as block of 32KB
+ QByteArray block;
+ QDataStream out(&block, QIODevice::WriteOnly);
+ out.setVersion(QDataStream::Qt_4_4);
+ out << int(0);
+ out << orderId;
+ out << returnCode;
+ QStringList returnListQt;
+ {
+ unsigned int index=0;
+ while(index<returnList.size())
+ {
+ returnListQt << QString::fromStdString(returnList.at(index));
+ index++;
+ }
+ }
+ out << returnListQt;
+ out.device()->seek(0);
+ out << block.size();
+ do
+ {
+ QByteArray blockToSend;
+ int byteWriten;
+ blockToSend=block.left(32*1024);//32KB
+ block.remove(0,blockToSend.size());
+ byteWriten = clientList[index].socket->write(blockToSend);
+ if(!clientList[index].socket->isValid())
+ {
+ error_string="Socket is not valid";
+ emit error(error_string);
+ return;
+ }
+ if(clientList[index].socket->error()!=QLocalSocket::UnknownSocketError && clientList[index].socket->error()!=QLocalSocket::PeerClosedError)
+ {
+ error_string="Error with socket: "+clientList[index].socket->errorString().toStdString();
+ emit error(error_string);
+ return;
+ }
+ if(blockToSend.size()!=byteWriten)
+ {
+ error_string="All the bytes have not be written";
+ emit error(error_string);
+ return;
+ }
+ }
+ while(block.size());
+ }
+ else
+ {
+ error_string="Socket is not valid or not connected";
+ emit error(error_string);
+ }
+ return;
+ }
+ index++;
+ }
+ qWarning() << "Client id not found:" << client;
+}
+
+void ServerCatchcopy::protocolSupported(const uint32_t &client,const uint32_t &orderId,const bool &value)
+{
+ if(value)
+ reply(client,orderId,1000,"protocol supported");
+ else
+ reply(client,orderId,5003,"protocol not supported");
+}
+
+void ServerCatchcopy::incorrectArgumentListSize(const uint32_t &client,const uint32_t &orderId)
+{
+ reply(client,orderId,5000,"incorrect argument list size");
+}
+
+void ServerCatchcopy::incorrectArgument(const uint32_t &client,const uint32_t &orderId)
+{
+ reply(client,orderId,5001,"incorrect argument");
+}
+
+void ServerCatchcopy::clientRegistered(const uint32_t &client,const uint32_t &orderId)
+{
+ reply(client,orderId,1003,"client registered");
+}
+
+void ServerCatchcopy::serverName(const uint32_t &client,const uint32_t &orderId,const std::string &name)
+{
+ reply(client,orderId,1004,name);
+}
+
+void ServerCatchcopy::copyFinished(const uint32_t &client,const uint32_t &orderId,const bool &withError)
+{
+ if(!withError)
+ reply(client,orderId,1005,"finished");
+ else
+ reply(client,orderId,1006,"finished with error(s)");
+}
+
+void ServerCatchcopy::copyCanceled(const uint32_t &client,const uint32_t &orderId)
+{
+ reply(client,orderId,1007,"canceled");
+}
+
+void ServerCatchcopy::unknowOrder(const uint32_t &client,const uint32_t &orderId)
+{
+ reply(client,orderId,5002,"unknown order");
+}
+
+void ServerCatchcopy::checkTimeOut()
+{
+ QTimer *timer=qobject_cast<QTimer *>(QObject::sender());
+ if(timer==NULL)
+ {
+ qWarning() << "Unallocated client timer!";
+ return;
+ }
+ int index=0;
+ while(index<clientList.size())
+ {
+ if(clientList.at(index).detectTimeOut==timer)
+ {
+ clientList.at(index).detectTimeOut->stop();
+ if(clientList.at(index).haveData)
+ {
+ error_string="The client is too long to send the next part of the reply: "+QString(clientList.at(index).data.toHex()).toStdString();
+ clientList[index].haveData=false;
+ clientList[index].data.clear();
+ clientList.at(index).socket->disconnectFromServer();
+ emit error(error_string);
+ }
+ return;
+ }
+ index++;
+ }
+}
+
+uint32_t ServerCatchcopy::incrementOrderId()
+{
+ do
+ {
+ nextOrderId++;
+ if(nextOrderId>2000000)
+ nextOrderId=0;
+ } while(orderList.contains(nextOrderId));
+ return nextOrderId;
+}
diff --git a/plugins/Listener/catchcopy-v0002/catchcopy-api-0002/ServerCatchcopy.h b/plugins/Listener/catchcopy-v0002/catchcopy-api-0002/ServerCatchcopy.h
new file mode 100644
index 0000000..85acff9
--- /dev/null
+++ b/plugins/Listener/catchcopy-v0002/catchcopy-api-0002/ServerCatchcopy.h
@@ -0,0 +1,144 @@
+/** \file ServerCatchcopy.h
+\brief Define the server of catchcopy
+\author alpha_one_x86
+\licence GPL3, see the file COPYING */
+
+#ifndef SERVERCATCHCOPY_H
+#define SERVERCATCHCOPY_H
+
+#include <QObject>
+#include <QLocalSocket>
+#include <QLocalServer>
+#include <vector>
+#include <string>
+#include <QByteArray>
+#include <QTimer>
+
+/// \brief Define the server of catchcopy
+class ServerCatchcopy : public QObject
+{
+ Q_OBJECT
+ public:
+ ServerCatchcopy();
+ ~ServerCatchcopy();
+ /// \brief return if is listening
+ bool isListening() const;
+ /// \brief try listen
+ bool listen();
+ /// \brief try close the server
+ void close();
+ /// \brief get the error string on the QLocalServer
+ const std::string errorStringServer() const;
+ /// \brief get the general error string
+ const std::string errorString() const;
+ /// \brief set the name of the server
+ void setName(const std::string & name);
+ /// \brief get the name
+ std::string getName() const;
+ /// \brief to get a client list
+ std::vector<std::string> clientsList() const;
+ private:
+ std::string pathSocket;
+ std::string name;
+ std::string error_string;
+ QLocalServer server;
+ uint32_t idNextClient;
+ struct Client
+ {
+ uint32_t id;
+ QLocalSocket *socket;
+ QByteArray data;
+ bool haveData;
+ uint32_t dataSize;
+ bool firstProtocolReplied;
+ QList<uint32_t> queryNoReplied;
+ QTimer *detectTimeOut;
+ std::string name;
+ };
+ QList<Client> clientList;
+ struct LinkGlobalToLocalClient
+ {
+ uint32_t idClient;
+ uint32_t orderId;
+ uint32_t globalOrderId;
+ };
+ QList<LinkGlobalToLocalClient> LinkGlobalToLocalClientList;
+ enum inputReturnType{Ok,Replied,ExtensionWrong,WrongArgument,WrongArgumentListSize,UnknowOrder};
+ inputReturnType parseInputCurrentProtocol(const uint32_t &client,const uint32_t &orderId,const std::vector<std::string> &returnList);
+ bool clientIdFound(const uint32_t &id) const;
+ uint32_t nextOrderId;
+ QList<uint32_t> orderList;
+ uint32_t incrementOrderId();
+ void emitNewCopyWithoutDestination(const uint32_t &client,const uint32_t &orderId,const std::vector<std::string> &sources);
+ void emitNewCopy(const uint32_t &client,const uint32_t &orderId,const std::vector<std::string> &sources,const std::string &destination);
+ void emitNewMoveWithoutDestination(const uint32_t &client,const uint32_t &orderId,const std::vector<std::string> &sources);
+ void emitNewMove(const uint32_t &client,const uint32_t &orderId,const std::vector<std::string> &sources,const std::string &destination);
+ bool checkDataIntegrity(const QByteArray &data);
+ protected:
+ void parseInput(const uint32_t &client,const uint32_t &orderId,const std::vector<std::string> &returnList);
+ private slots:
+ void newConnection();
+ void connectionError(const QLocalSocket::LocalSocketError &error);
+ void disconnected();
+ void readyRead();
+ void checkTimeOut();
+ public slots:
+ /// \brief disconnect one client
+ void disconnectClient(const uint32_t &id);
+ /// \brief reply to a client with std::vector<std::string>
+ void reply(const uint32_t &client,const uint32_t &orderId,const uint32_t &returnCode,const std::vector<std::string> &returnList);
+ /// \brief reply to a client
+ void reply(const uint32_t &client,const uint32_t &orderId,const uint32_t &returnCode,const std::string &returnString);
+ //reply
+ /// \brief send if the protocol is supported
+ void protocolSupported(const uint32_t &client,const uint32_t &orderId,const bool &value);
+ /// \brief send incorrect arguement list size
+ void incorrectArgumentListSize(const uint32_t &client,const uint32_t &orderId);
+ /// \brief send incorrect arguement
+ void incorrectArgument(const uint32_t &client,const uint32_t &orderId);
+ /// \brief the client is registred
+ void clientRegistered(const uint32_t &client,const uint32_t &orderId);
+ /// \brief send the server name
+ void serverName(const uint32_t &client,const uint32_t &orderId,const std::string &name);
+ /// \brief send the copy is finished
+ void copyFinished(const uint32_t &client,const uint32_t &orderId,const bool &withError);
+ /// \brief send the copy is canceled
+ void copyCanceled(const uint32_t &client,const uint32_t &orderId);
+ /// \brief send the copy is finished by global is order
+ void copyFinished(const uint32_t &globalOrderId,const bool &withError);
+ /// \brief send copy cancel by global is order
+ void copyCanceled(const uint32_t &globalOrderId);
+ /// \brief send the unknow order
+ void unknowOrder(const uint32_t &client,const uint32_t &orderId);
+ signals:
+ /// \brief send connected client
+ void connectedClient(const uint32_t &id);
+ /// \brief send disconnect client
+ void disconnectedClient(const uint32_t &id);
+ /// \brief have new query
+ void newQuery(const uint32_t &client,const uint32_t &orderId,const std::vector<std::string> &returnList);
+ /// \brief have new error
+ void error(const std::string &error);
+ void communicationError(const std::string &error);
+ //query
+ /// \brief ask the protocol compatility
+ void askProtocolCompatibility(const uint32_t &client,const uint32_t &orderId,const std::string &version);
+ /// \brief ask protocol extension
+ void askProtocolExtension(const uint32_t &client,const uint32_t &orderId,const std::string &extension);
+ /// \brief ask protocol extension with version
+ void askProtocolExtension(const uint32_t &client,const uint32_t &orderId,const std::string &extension,const std::string &version);
+ /// \brief send the client name, without query id
+ void clientName(const uint32_t &client,const std::string &name);
+ /// \brief send the client have ask the server name
+ void askServerName(const uint32_t &client,const uint32_t &orderId);
+ /// \brief copy is send, by globalOrderId, without destination
+ void newCopyWithoutDestination(const uint32_t &globalOrderId,const std::vector<std::string> &sources);
+ /// \brief copy is send, by globalOrderId, with destination
+ void newCopy(const uint32_t &globalOrderId,const std::vector<std::string> &sources,const std::string &destination);
+ /// \brief move is send, by globalOrderId, without destination
+ void newMoveWithoutDestination(const uint32_t &globalOrderId,const std::vector<std::string> &sources);
+ /// \brief move is send, by globalOrderId, with destination
+ void newMove(const uint32_t &globalOrderId,const std::vector<std::string> &sources,const std::string &destination);
+};
+
+#endif // SERVERCATCHCOPY_H
diff --git a/plugins/Listener/catchcopy-v0002/catchcopy-api-0002/VariablesCatchcopy.h b/plugins/Listener/catchcopy-v0002/catchcopy-api-0002/VariablesCatchcopy.h
new file mode 100644
index 0000000..135c087
--- /dev/null
+++ b/plugins/Listener/catchcopy-v0002/catchcopy-api-0002/VariablesCatchcopy.h
@@ -0,0 +1,13 @@
+/** \file VariablesCatchcopy.h
+\brief Define the variable for catchcopy
+\author alpha_one_x86
+\licence GPL3, see the file COPYING */
+
+#ifndef VARIABLECATCHCOPY_H
+#define VARIABLECATCHCOPY_H
+
+#define CATCHCOPY_PROTOCOL_VERSION "0002"
+#define CATCHCOPY_COMMUNICATION_TIMEOUT 200
+
+#endif // VARIABLECATCHCOPY_H
+
diff --git a/plugins/Listener/catchcopy-v0002/documentation.dox b/plugins/Listener/catchcopy-v0002/documentation.dox
new file mode 100644
index 0000000..51aa937
--- /dev/null
+++ b/plugins/Listener/catchcopy-v0002/documentation.dox
@@ -0,0 +1,32 @@
+/* -*- mode: C++ ; c-file-style: "stroustrup" -*- **/
+
+/*
+ This file contains NO source code, just some documentation for doxygen to
+ parse.
+*/
+
+/*!
+ \mainpage catchcopy-v0002
+
+ \section mainpage_overview Overview
+
+ Is the default listener to wait a copy/move. It use the catchcopy protocol.\n
+ More informations on <a href="http://ultracopier-wiki.first-world.info/">the wiki of ultracopier</a>.
+
+ \section mainpage_platforms Platforms
+
+ Ultracopier might be usable in all environments where you find Qt 5.\n
+ Ultracopier requires Qt 5.0 or newer. Tested on Qt 5.0.
+
+ \section mainpage_downloads Downloads
+
+ You can find the link on <a href="http://ultracopier.first-world.info/">Ultracopier</a> project page, via git, snapshot sources, ...
+
+ \section mainpage_algorithm Protocol
+
+ The protocol in version 0.0.0.2 is used, you can see the documentation on <a href="http://catchcopy.first-world.info/">Catchcopy web site</a>
+
+ \section license GPL Version 3
+ The code source is under GPL3. The image is extacted from Oxygen icon pack of KDE4.
+
+*/
diff --git a/plugins/Listener/catchcopy-v0002/informations.xml b/plugins/Listener/catchcopy-v0002/informations.xml
new file mode 100644
index 0000000..9efc7ce
--- /dev/null
+++ b/plugins/Listener/catchcopy-v0002/informations.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<package>
+ <title xml:lang="en"><![CDATA[Listener for catchcopy v0002]]></title><!-- english is required -->
+ <title xml:lang="fr"><![CDATA[Écouteur pour catchcopy v0002]]></title>
+ <!-- What kind of plugin this is -->
+ <category>Listener</category>
+ <!-- Who wrote this plugin -->
+ <author><![CDATA[BRULE Herman, alpha_one_x86 (alpha_one_x86@first-world.info)]]></author>
+ <!-- URL of page or site for this plugin (may provide additional information, bug reports, feature requests). -->
+ <website xml:lang="en"><![CDATA[http://ultracopier.first-world.info/]]></website><!-- not required -->
+ <website xml:lang="fr"><![CDATA[http://ultracopier-fr.first-world.info/]]></website><!-- not required -->
+ <!-- the date-time format should be in timestamps format -->
+ <pubDate>1287496800</pubDate>
+ <!-- the architecture code of this plugin, found PlatformMacro.h into ultracopier source -->
+ <architecture>windows-x86</architecture>
+ <!-- Detailed description -->
+ <description xml:lang="en"><![CDATA[Listener for catchcopy v0002. Allow to receive copy list from plugin/explorer compatible with catchcopy.]]></description>
+ <description xml:lang="fr"><![CDATA[Écouteur pour catchcopy v0002. Permet de recevoir un liste de copie venant d'un plugin/explorateur avec catchcopy.]]></description>
+ <!-- Version of this release of this plugin, need be like that's: A.B.C.D, where A, B, C and D is number -->
+ <version>1.4.0.4</version>
+ <!-- This internal name should never change, because it is used to detect when a particular plugin is updated. It must comprise only lower case ASCII characters (a-z), numerical digits (0-9), "-", "." or "_", and it must be be unique within the category. And have size lower than 64 char. -->
+ <name>catchcopy-v0002</name>
+ <!-- Dependency checking. This is used to check when a plugin may not be compatible with an updated version of either Ultracopier or another plugin. This example only checks Ultracopier. -->
+ <dependencies><![CDATA[
+ ]]></dependencies>
+</package> \ No newline at end of file
diff --git a/plugins/Listener/catchcopy-v0002/listener.cpp b/plugins/Listener/catchcopy-v0002/listener.cpp
new file mode 100644
index 0000000..e45a08b
--- /dev/null
+++ b/plugins/Listener/catchcopy-v0002/listener.cpp
@@ -0,0 +1,123 @@
+#include "listener.h"
+#include "catchcopy-api-0002/ExtraSocketCatchcopy.h"
+#include "../../../cpp11addition.h"
+
+Listener::Listener()
+{
+ server.setName(tr("Ultracopier").toStdString());
+ connect(&server,&ServerCatchcopy::newCopyWithoutDestination, this,&Listener::copyWithoutDestination);
+ connect(&server,&ServerCatchcopy::newCopy, this,&Listener::copy);
+ connect(&server,&ServerCatchcopy::newMoveWithoutDestination, this,&Listener::moveWithoutDestination);
+ connect(&server,&ServerCatchcopy::newMove, this,&Listener::move);
+ connect(&server,&ServerCatchcopy::error, this,&Listener::errorInternal);
+ connect(&server,&ServerCatchcopy::communicationError, this,&Listener::communicationErrorInternal);
+ connect(&server,&ServerCatchcopy::clientName, this,&Listener::clientName);
+ connect(&server,&ServerCatchcopy::clientName, this,&Listener::newClientList);
+ connect(&server,&ServerCatchcopy::connectedClient, this,&Listener::newClientList);
+ connect(&server,&ServerCatchcopy::disconnectedClient, this,&Listener::newClientList);
+
+}
+
+void Listener::listen()
+{
+ ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"start: "+ExtraSocketCatchcopy::pathSocket());
+ if(server.listen())
+ emit newState(Ultracopier::FullListening);
+ else
+ emit newState(Ultracopier::NotListening);
+}
+
+void Listener::close()
+{
+ server.close();
+ emit newState(Ultracopier::NotListening);
+}
+
+const std::string Listener::errorString() const
+{
+ return server.errorString();
+}
+
+void Listener::setResources(OptionInterface * options, const std::string &writePath, const std::string &pluginPath, const bool &portableVersion)
+{
+ Q_UNUSED(options);
+ Q_UNUSED(writePath);
+ Q_UNUSED(pluginPath);
+ Q_UNUSED(portableVersion);
+}
+
+/// \brief to get the options widget, NULL if not have
+QWidget * Listener::options()
+{
+ return NULL;
+}
+
+/// \brief to get a client list
+std::vector<std::string> Listener::clientsList() const
+{
+ return server.clientsList();
+}
+
+void Listener::transferFinished(const uint32_t &orderId, const bool &withError)
+{
+ ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"start, orderId: "+std::to_string(orderId)+", withError: "+std::to_string(withError));
+ server.copyFinished(orderId,withError);
+}
+
+void Listener::transferCanceled(const uint32_t &orderId)
+{
+ ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Notice,"start, orderId: "+std::to_string(orderId));
+ server.copyCanceled(orderId);
+}
+
+/// \brief to reload the translation, because the new language have been loaded
+void Listener::newLanguageLoaded()
+{
+}
+
+void Listener::errorInternal(const std::string &string)
+{
+ Q_UNUSED(string);
+ ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Warning,"warning emited from Catchcopy lib: "+string);
+}
+
+void Listener::communicationErrorInternal(const std::string &string)
+{
+ ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Warning,"warning emited from Catchcopy lib: "+string);
+ emit error(string);
+}
+
+void Listener::clientName(uint32_t client,std::string name)
+{
+ Q_UNUSED(client);
+ Q_UNUSED(name);
+ ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Information,QStringLiteral("clientName: %1, for the id: %2").arg(QString::fromStdString(name)).arg(client).toStdString());
+}
+
+void Listener::copyWithoutDestination(const uint32_t &orderId,const std::vector<std::string> &sources)
+{
+ ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Information,QStringLiteral("copyWithoutDestination(%1,%2)")
+ .arg(orderId)
+ .arg(QString::fromStdString(stringimplode(sources,";")))
+ .toStdString()
+ );
+ emit newCopyWithoutDestination(orderId,sources);
+}
+
+void Listener::copy(const uint32_t &orderId,const std::vector<std::string> &sources,const std::string &destination)
+{
+ ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Information,QStringLiteral("copy(%1,%2,%3)").arg(orderId).arg(QString::fromStdString(stringimplode(sources,";")).arg(QString::fromStdString(destination))).toStdString());
+ emit newCopy(orderId,sources,destination);
+}
+
+void Listener::moveWithoutDestination(const uint32_t &orderId,const std::vector<std::string> &sources)
+{
+ ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Information,QStringLiteral("moveWithoutDestination(%1,%2)").arg(orderId).arg(QString::fromStdString(stringimplode(sources,";"))).toStdString());
+ emit newMoveWithoutDestination(orderId,sources);
+}
+
+void Listener::move(const uint32_t &orderId,const std::vector<std::string> &sources,const std::string &destination)
+{
+ ULTRACOPIER_DEBUGCONSOLE(Ultracopier::DebugLevel_Information,QStringLiteral("move(%1,%2,%3)").arg(orderId).arg(QString::fromStdString(stringimplode(sources,";")).arg(QString::fromStdString(destination))).toStdString());
+ emit newMove(orderId,sources,destination);
+}
diff --git a/plugins/Listener/catchcopy-v0002/listener.h b/plugins/Listener/catchcopy-v0002/listener.h
new file mode 100644
index 0000000..8cab248
--- /dev/null
+++ b/plugins/Listener/catchcopy-v0002/listener.h
@@ -0,0 +1,59 @@
+/** \file listener.h
+\brief Define the server compatible with Ultracopier interface
+\author alpha_one_x86
+\licence GPL3, see the file COPYING */
+
+#ifndef SERVER_H
+#define SERVER_H
+
+#include <string>
+#ifndef ULTRACOPIER_PLUGIN_ALL_IN_ONE_DIRECT
+#include <QtPlugin>
+#endif
+
+#include "Environment.h"
+#include "../../../interface/PluginInterface_Listener.h"
+#include "catchcopy-api-0002/ServerCatchcopy.h"
+
+/// \brief Define the server compatible with Ultracopier interface
+class Listener : public PluginInterface_Listener
+{
+ Q_OBJECT
+ #ifndef ULTRACOPIER_PLUGIN_ALL_IN_ONE_DIRECT
+ Q_PLUGIN_METADATA(IID "first-world.info.ultracopier.PluginInterface.Listener/1.0.0.0" FILE "plugin.json")
+ Q_INTERFACES(PluginInterface_Listener)
+ #endif
+public:
+ Listener();
+ /// \brief try listen the copy/move
+ void listen();
+ /// \brief stop listen to copy/move
+ void close();
+ /// \brief return the error strong
+ const std::string errorString() const;
+ /// \brief set resources for this plugins
+ void setResources(OptionInterface * options,const std::string &writePath,const std::string &pluginPath,const bool &portableVersion);
+ /// \brief to get the options widget, NULL if not have
+ QWidget * options();
+ /// \brief to get a client list
+ std::vector<std::string> clientsList() const;
+public slots:
+ /// \brief say to the client that's the copy/move is finished
+ void transferFinished(const uint32_t &orderId,const bool &withError);
+ /// \brief say to the client that's the copy/move is finished
+ void transferCanceled(const uint32_t &orderId);
+ /// \brief to reload the translation, because the new language have been loaded
+ void newLanguageLoaded();
+private:
+ ServerCatchcopy server;
+private slots:
+ void errorInternal(const std::string &string);
+ void communicationErrorInternal(const std::string &string);
+ void clientName(uint32_t client,std::string name);
+ void copyWithoutDestination(const uint32_t &orderId,const std::vector<std::string> &sources);
+ void copy(const uint32_t &orderId,const std::vector<std::string> &sources,const std::string &destination);
+ void moveWithoutDestination(const uint32_t &orderId,const std::vector<std::string> &sources);
+ void move(const uint32_t &orderId,const std::vector<std::string> &sources,const std::string &destination);
+};
+
+#endif // SERVER_H
diff --git a/plugins/Listener/catchcopy-v0002/listener.pro b/plugins/Listener/catchcopy-v0002/listener.pro
new file mode 100644
index 0000000..b21289a
--- /dev/null
+++ b/plugins/Listener/catchcopy-v0002/listener.pro
@@ -0,0 +1,26 @@
+CONFIG += c++11
+QMAKE_CXXFLAGS+="-std=c++0x -Wall -Wextra"
+mac:QMAKE_CXXFLAGS+="-stdlib=libc++"
+
+TEMPLATE = lib
+CONFIG += plugin
+QT += network
+win32:LIBS += -ladvapi32
+HEADERS = \
+ $$PWD/listener.h \
+ $$PWD/catchcopy-api-0002/VariablesCatchcopy.h \
+ $$PWD/catchcopy-api-0002/ServerCatchcopy.h \
+ $$PWD/catchcopy-api-0002/ExtraSocketCatchcopy.h \
+ $$PWD/Environment.h \
+ $$PWD/Variable.h \
+ $$PWD/DebugEngineMacro.h \
+ $$PWD/StructEnumDefinition.h \
+ $$PWD/../../../interface/PluginInterface_Listener.h \
+ $$PWD/../../../cpp11addition.h
+SOURCES = \
+ $$PWD/listener.cpp \
+ $$PWD/catchcopy-api-0002/ServerCatchcopy.cpp \
+ $$PWD/catchcopy-api-0002/ExtraSocketCatchcopy.cpp \
+ $$PWD/../../../cpp11addition.cpp \
+ $$PWD/../../../cpp11additionstringtointcpp.cpp
+TARGET = $$qtLibraryTarget(listener)
diff --git a/plugins/Listener/catchcopy-v0002/plugin.json b/plugins/Listener/catchcopy-v0002/plugin.json
new file mode 100644
index 0000000..9e26dfe
--- /dev/null
+++ b/plugins/Listener/catchcopy-v0002/plugin.json
@@ -0,0 +1 @@
+{} \ No newline at end of file