[X2go-Commits] x2goclient2.git - master (branch) updated: c01d49db3afcbc028d704d3048f96fabee5827b4

X2Go dev team git-admin at x2go.org
Mon Nov 12 16:38:37 CET 2012


The branch, master has been updated
       via  c01d49db3afcbc028d704d3048f96fabee5827b4 (commit)
      from  ac2eeb5461e7f27cef3aaff705f690bf839bd8ce (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit c01d49db3afcbc028d704d3048f96fabee5827b4
Author: Oleksandr Shneyder <o.shneyder at phoca-gmbh.de>
Date:   Mon Nov 12 16:37:59 2012 +0100

    implement class SshProcess. Add support for type SSH in X2GoBroker

-----------------------------------------------------------------------

Summary of changes:
 sshconnection.cpp   |  561 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 sshconnection.h     |   80 +++++---
 sshprocess.cpp      |  242 ++++++++++++++++++++++
 sshprocess.h        |   84 ++++++++
 x2goapplication.cpp |    5 +-
 x2gobroker.cpp      |   50 ++++-
 x2gobroker.h        |    9 +-
 x2goclient2.pro     |    2 +
 8 files changed, 991 insertions(+), 42 deletions(-)
 create mode 100644 sshprocess.cpp
 create mode 100644 sshprocess.h

The diff of changes is:
diff --git a/sshconnection.cpp b/sshconnection.cpp
index 878c66c..29f22cf 100644
--- a/sshconnection.cpp
+++ b/sshconnection.cpp
@@ -20,6 +20,7 @@
 
 #include "sshconnection.h"
 #include "sshconnectionguiinteraction.h"
+#include "sshprocess.h"
 
 #define PROXYTUNNELPORT 44444
 
@@ -68,6 +69,7 @@ SshConnection::SshConnection(QObject* parent, QString host, int port, bool accep
     sshProxyReady=false;
     nextPid=0;
     my_ssh_session=0;
+    connected=false;
 
     breakLoop=false;
     this->host=host;
@@ -94,11 +96,71 @@ SshConnection::SshConnection(QObject* parent, QString host, int port, bool accep
     }
 }
 
+//private constructor for reverse tunnel connections
+SshConnection::SshConnection(QObject* parent, QString host, int port, bool acceptUnknownServers,
+                             QString user, QString pass, QString key, bool autoLogin, bool krbLogin,
+                             int remotePort, QString localHost, int localPort, SshProcess* creator, bool useProxy,
+                             SshConnection::ProxyType proxyType, QString proxyServer, quint16 proxyPort, QString proxyLogin,
+                             QString proxyPassword, QString proxyKey, bool proxyAutoLogin, int localProxyPort): QThread(parent)
+{
+#if defined ( Q_OS_DARWIN )
+    setStackSize (sizeof (char) * 1024 * 1024 * 2);
+#endif
+    nextPid=0;
+    my_ssh_session=0;
+    tcpProxySocket = NULL;
+    tcpNetworkProxy = NULL;
+    sshProxy= NULL;
+    sshProxyReady=false;
+    breakLoop=false;
+    this->host=host;
+    this->port=port;
+    this->user=user;
+    this->pass=pass;
+    this->key=key;
+    this->autoLogin=autoLogin;
+    this->acceptUnknownServers=acceptUnknownServers;
+    this->useProxy=useProxy;
+    this->proxyServer=proxyServer;
+    this->proxyPort=proxyPort;
+    this->proxyLogin=proxyLogin;
+    this->proxyPassword=proxyPassword;
+    this->proxyType=proxyType;
+    this->proxyAutoLogin=proxyAutoLogin;
+    this->proxyKey=proxyKey;
+    this->localProxyPort=localProxyPort;
+    this->kerberos=krbLogin;
+    reverseTunnelLocalHost=localHost;
+    reverseTunnelLocalPort=localPort;
+    reverseTunnelCreator=creator;
+    reverseTunnel=true;
+    reverseTunnelRemotePort=remotePort;
+#ifdef DEBUG
+    qDebug()<<"SshMasterConnection, instance "<<this<<" created (reverse tunnel)";
+#endif
+}
+
+
 SshConnection::~SshConnection()
 {
+    disconnectFlagMutex.lock();
+    disconnectSessionFlag=true;
+    disconnectFlagMutex.unlock();
+#ifdef DEBUG
+    qDebug()<<"SshConnection, instance "<<this<<" waiting for thread to finish";
+#endif
+    wait();
+#ifdef DEBUG
+    qDebug()<<"SshConnection, instance "<<this<<" thread finished";
+#endif
+    for(int i=processes.count()-1; i>=0; --i)
+    {
+        delete processes[i];
+    }
     if(my_ssh_session)
     {
         ssh_free(my_ssh_session);
+        my_ssh_session=0;
     }
     qDebug()<<"ssh connection destructor";
 }
@@ -106,6 +168,7 @@ SshConnection::~SshConnection()
 void SshConnection::run()
 {
     disconnectSessionFlag=false;
+#warning implement ssh proxy code
     if ( !isLibSshInited )
     {
         if ( ssh_init() !=0 )
@@ -113,7 +176,7 @@ void SshConnection::run()
             QString err=tr ( "Can not initialize libssh" );
             qDebug()<<err<<endl;
             guiInteractor->critical(err, MessageBox::OK);
-            emit signalError ( CONNECTION, err );
+            emit signalError ( (int)CONNECTION, err );
             return;
         }
         isLibSshInited=true;
@@ -133,7 +196,7 @@ void SshConnection::run()
         QString err=tr ( "Can not create ssh session" );
         qDebug()<<err<<endl;
         guiInteractor->critical(err, MessageBox::OK);
-        emit signalError ( CONNECTION, err);
+        emit signalError ( (int)CONNECTION, err);
         if ( reverseTunnel )
             emit signalIoError ( reverseTunnelCreator, err, "" );
         return;
@@ -161,8 +224,9 @@ void SshConnection::run()
             QString message=tr ( "Can not connect to proxy server" );
             qDebug()<<message<<endl;
             guiInteractor->critical(message, MessageBox::OK);
-            emit signalError ( CONNECTION, message );
+            emit signalError ( (int)CONNECTION, message );
             ssh_free ( my_ssh_session );
+            my_ssh_session=0;
             return;
         }
         ssh_options_set( my_ssh_session, SSH_OPTIONS_FD, &proxysocket);
@@ -176,10 +240,11 @@ void SshConnection::run()
         message+=" - "+err;
         qDebug()<<message;
         guiInteractor->critical(message, MessageBox::OK);
-        emit signalError (CONNECTION, message);
+        emit signalError ((int)CONNECTION, message);
         if ( reverseTunnel )
             emit signalIoError ( reverseTunnelCreator, message, err);
         ssh_free ( my_ssh_session );
+        my_ssh_session=0;
         return;
     }
     QString errMsg;
@@ -187,9 +252,10 @@ void SshConnection::run()
     if ( state != SSH_SERVER_KNOWN_OK )
     {
         guiInteractor->critical(errMsg, MessageBox::OK);
-        emit signalError (SERVERAUTH, errMsg);
+        emit signalError ((int)SERVERAUTH, errMsg);
         ssh_disconnect ( my_ssh_session );
         ssh_free ( my_ssh_session );
+        my_ssh_session=0;
         return;
     }
 
@@ -201,6 +267,7 @@ void SshConnection::run()
     {
         qDebug()<<"SSH session connected";
         emit signalConnectionOk(host);
+        connected=true;
     }
     else
     {
@@ -211,11 +278,12 @@ void SshConnection::run()
         guiInteractor->critical(message, MessageBox::OK);
         message+=" - "+err+"\n"+authErrors.join ( "\n" );
         qDebug()<<message;
-        emit signalError (USERAUTH,  message );
+        emit signalError ((int)USERAUTH,  message );
         if ( reverseTunnel )
             emit signalIoError ( reverseTunnelCreator,message,err );
         ssh_disconnect ( my_ssh_session );
         ssh_free ( my_ssh_session );
+        my_ssh_session=0;
         return;
     }
 
@@ -241,6 +309,7 @@ void SshConnection::run()
             emit signalIoError ( reverseTunnelCreator, message, err );
             ssh_disconnect ( my_ssh_session );
             ssh_free ( my_ssh_session );
+            my_ssh_session=0;
             return;
         }
         emit signalReverseListenOk ( reverseTunnelCreator );
@@ -303,7 +372,7 @@ int SshConnection::serverAuth(QString& errorMsg)
         return SSH_SERVER_ERROR;
 
 #ifdef DEBUG
-    x2goDebug<<"state: "<<state<<endl;
+    qDebug()<<"state: "<<state<<endl;
 #endif
 
     switch ( state )
@@ -466,12 +535,488 @@ bool SshConnection::userAuthWithPass()
 
 }
 
+
+void SshConnection::copy()
+{
+    for ( int i=copyRequests.size()-1; i>=0; --i )
+    {
+        QStringList lst=copyRequests[i].dst.split ( "/" );
+        QString dstFile=lst.last();
+        lst.removeLast();
+        QString dstPath=lst.join ( "/" );
+#ifdef DEBUG
+        qDebug()<<"dst path:"<<dstPath<<" file:"<<dstFile<<endl;
+#endif
+        ssh_scp scp=ssh_scp_new ( my_ssh_session, SSH_SCP_WRITE|SSH_SCP_RECURSIVE, dstPath.toAscii() );
+        if ( scp == NULL )
+        {
+            qDebug()<<"Error allocating scp session: "<< ssh_get_error ( my_ssh_session ) <<endl;
+            return;
+        }
+        int rc = ssh_scp_init ( scp );
+        if ( rc != SSH_OK )
+        {
+            qDebug()<<"Error initializing scp session: "<< ssh_get_error ( my_ssh_session ) <<endl;
+            ssh_scp_free ( scp );
+            return;
+        }
+        QFile file ( copyRequests[i].src );
+        if ( !file.open ( QIODevice::ReadOnly ) )
+        {
+            QString errMsg=tr ( "Can not open file " ) +copyRequests[i].src;
+            emit signalCopyError ( copyRequests[i].creator, errMsg, "" );
+            copyRequests.removeAt ( i );
+            ssh_scp_close ( scp );
+            ssh_scp_free ( scp );
+            continue;
+        }
+        QByteArray arr=file.readAll();
+        file.close();
+        rc=ssh_scp_push_file ( scp,dstFile.toAscii(),arr.size(), 0600 );
+        if ( rc != SSH_OK )
+        {
+            QString errMsg=tr ( "Can not create remote file " ) +copyRequests[i].dst;
+            QString serr=ssh_get_error ( my_ssh_session );
+            qDebug()<<errMsg<<" - "<<serr<<endl;
+            emit signalCopyError ( copyRequests[i].creator, errMsg, serr );
+            copyRequests.removeAt ( i );
+            ssh_scp_close ( scp );
+            ssh_scp_free ( scp );
+            continue;
+        }
+        rc=ssh_scp_write ( scp,arr.data(),arr.size() );
+        if ( rc != SSH_OK )
+        {
+            QString serr=ssh_get_error ( my_ssh_session );
+            QString errMsg=tr ( "Can not write to remote file " ) +copyRequests[i].dst;
+            qDebug()<<errMsg<<" - "<<serr<<endl;
+            emit signalCopyError ( copyRequests[i].creator, errMsg, serr );
+            copyRequests.removeAt ( i );
+            ssh_scp_close ( scp );
+            ssh_scp_free ( scp );
+            continue;
+        }
+        emit signalCopyOk ( copyRequests[i].creator );
+#ifdef DEBUG
+        qDebug()<<"scp ok: "<<copyRequests[i].src<<" -> "<<user<<"@"<<host<<":"<<copyRequests[i].dst<<endl;
+#endif
+        copyRequests.removeAt ( i );
+        ssh_scp_close ( scp );
+        ssh_scp_free ( scp );
+    }
+}
+
+
 void SshConnection::channelLoop()
 {
+    forever
+    {
+        copyRequestMutex.lock();
+        if ( copyRequests.size() >0 )
+            copy();
+        copyRequestMutex.unlock();
+        if ( reverseTunnel )
+        {
+            ssh_channel newChan=channel_forward_accept ( my_ssh_session,0 );
+            if ( newChan )
+            {
+#ifdef DEBUG
+                qDebug()<<"new forward connection"<<endl;
+#endif
+                int sock=socket ( AF_INET, SOCK_STREAM,0 );
+#ifndef Q_OS_WIN
+                const int y=1;
+#else
+                const char y=1;
+#endif
+                setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,&y, sizeof(int));
+
+                struct sockaddr_in address;
+                address.sin_family=AF_INET;
+                address.sin_port=htons ( reverseTunnelLocalPort );
+#ifdef DEBUG
+                qDebug()<<"connecting to "<<reverseTunnelLocalHost<<":"<<reverseTunnelLocalPort<<endl;
+#endif
+#ifndef Q_OS_WIN
+                inet_aton ( reverseTunnelLocalHost.toAscii(), &address.sin_addr );
+#else
+                address.sin_addr.s_addr=inet_addr (
+                    reverseTunnelLocalHost.toAscii() );
+#endif
+
+                if ( ::connect ( sock, ( struct sockaddr * ) &address,sizeof ( address ) ) !=0 )
+                {
+                    QString errMsg=tr ( "can not connect to " ) +
+                    reverseTunnelLocalHost+":"+QString::number ( reverseTunnelLocalPort );
+                    qDebug()<<errMsg<<endl;
+                    emit signalIoError ( reverseTunnelCreator, errMsg, "" );
+                    continue;
+                }
+#ifdef DEBUG
+                qDebug()<<"creating new channel connection"<<endl;
+#endif
+                ChannelConnection con;
+                con.channel=newChan;
+                con.sock=sock;
+                con.creator=reverseTunnelCreator;
+                channelConnectionsMutex.lock();
+                channelConnections<<con;
+                channelConnectionsMutex.unlock();
+            }
+        }
+
+        char buffer[1024*512]; //512K buffer
+        int nbytes;
+        fd_set rfds;
+
+        struct timeval tv;
+
+        tv.tv_sec = 0;
+        tv.tv_usec = 500;
+
+        int retval;
+        int maxsock=-1;
+
+        disconnectFlagMutex.lock();
+        bool disconnect=disconnectSessionFlag;
+        disconnectFlagMutex.unlock();
+
+        if ( disconnect )
+        {
+
+            if (useProxy && proxyType==PROXYSSH && sshProxy)
+            {
+                delete sshProxy;
+                sshProxy=0;
+            }
+
+#ifdef DEBUG
+            if ( !reverseTunnel )
+                qDebug()<<"Disconnecting..."<<endl;
+#endif
+            reverseTunnelConnectionsMutex.lock();
+            for ( int i=reverseTunnelConnections.size()-1; i>=0; --i)
+            {
+                delete reverseTunnelConnections[i];
+            }
+            reverseTunnelConnectionsMutex.unlock();
+
+            channelConnectionsMutex.lock();
+            for ( int i=0; i<channelConnections.size(); ++i )
+            {
+                finalize ( i );
+            }
+            channelConnectionsMutex.unlock();
+            ssh_disconnect ( my_ssh_session );
+            ssh_free ( my_ssh_session );
+            my_ssh_session=0;
+
+            if (tcpProxySocket != NULL)
+                delete tcpProxySocket;
+            if (tcpNetworkProxy != NULL)
+                delete tcpNetworkProxy;
+#ifdef DEBUG
+            if ( !reverseTunnel )
+                qDebug()<<"All channels closed, session disconnected, quiting session loop"<<endl;
+#endif
+            return;
+        }
+
+        channelConnectionsMutex.lock();
+        if ( channelConnections.size() <=0 )
+        {
+            channelConnectionsMutex.unlock();
+            usleep ( 500 );
+            continue;
+        }
+        ssh_channel* read_chan=new ssh_channel[channelConnections.size() +1];
+        ssh_channel* out_chan=new ssh_channel[channelConnections.size() +1];
+        read_chan[channelConnections.size() ]=NULL;
+
+        FD_ZERO ( &rfds );
+
+        for ( int i=0; i<channelConnections.size(); ++i )
+        {
+            int tcpSocket=channelConnections.at ( i ).sock;
+            if ( tcpSocket>0 )
+                FD_SET ( tcpSocket, &rfds );
+            if ( channelConnections.at ( i ).channel==0l )
+            {
+#ifdef DEBUG
+                qDebug()<<"creating new channel"<<endl;
+#endif
+                ssh_channel channel=channel_new ( my_ssh_session );
+#ifdef DEBUG
+                qDebug()<<"new channel:"<<channel<<endl;
+#endif
+                channelConnections[i].channel=channel;
+                if ( tcpSocket>0 )
+                {
+#ifdef DEBUG
+                    qDebug()<<"forwarding new channel, local port: "<<channelConnections.at ( i ).localPort<<endl;
+#endif
+                    if ( channel_open_forward ( channel,
+                                                channelConnections.at ( i ).forwardHost.toAscii(),
+                                                channelConnections.at ( i ).forwardPort,
+                                                channelConnections.at ( i ).localHost.toAscii(),
+                                                channelConnections.at ( i ).localPort ) != SSH_OK )
+                    {
+                        QString err=ssh_get_error ( my_ssh_session );
+                        QString errorMsg=tr ( "channel_open_forward failed" );
+                        emit signalIoError ( channelConnections[i].creator, errorMsg, err );
+                        qDebug()<<errorMsg<<": "<<err<<endl;
+                    }
+#ifdef DEBUG
+                    else
+                    {
+                        qDebug()<<" new channel forwarded"<<endl;
+                    }
+#endif
+                }
+                else
+                {
+#ifdef DEBUG
+                    qDebug()<<"executing remote: "<<channelConnections.at ( i ).command<<endl;
+#endif
+                    if ( channel_open_session ( channel ) !=SSH_OK )
+                    {
+                        QString err=ssh_get_error ( my_ssh_session );
+                        QString errorMsg=tr ( "channel_open_session failed" );
+                        emit signalIoError ( channelConnections[i].creator, errorMsg, err );
+                        qDebug()<<errorMsg<<": "<<err<<endl;
+                    }
+                    else if ( channel_request_exec ( channel, channelConnections[i].command.toAscii() ) != SSH_OK )
+                    {
+                        QString err=ssh_get_error ( my_ssh_session );
+                        QString errorMsg=tr ( "channel_request_exec failed" );
+                        emit signalIoError ( channelConnections[i].creator, errorMsg, err );
+                        qDebug()<<errorMsg<<": "<<err<<endl;
+                    }
+#ifdef DEBUG
+                    else
+                    {
+                        qDebug()<<" new exec channel created"<<endl;
+                    }
+#endif
+                }
+            }
+            read_chan[i]=channelConnections.at ( i ).channel;
+            if ( tcpSocket>maxsock )
+                maxsock=tcpSocket;
+        }
+        channelConnectionsMutex.unlock();
+        retval=ssh_select ( read_chan,out_chan,maxsock+1,&rfds,&tv );
+        delete [] read_chan;
+        delete [] out_chan;
+
+        if ( retval == -1 )
+        {
+            qDebug()<<"select error\n";
+            continue;
+        }
+
+        channelConnectionsMutex.lock();
+        for ( int i=channelConnections.size()-1; i>=0; --i )
+        {
+            int tcpSocket=channelConnections.at ( i ).sock;
+            ssh_channel channel=channelConnections.at ( i ).channel;
+            if ( channel==0l )
+                continue;
+            if ( channel_poll ( channel,1 ) >0 )
+            {
+                nbytes = channel_read ( channel, buffer, sizeof ( buffer )-1, 1 );
+                emit signalStdErr ( channelConnections[i].creator, QByteArray ( buffer,nbytes ) );
+            }
+            int rez=channel_poll ( channel,0 );
+            if ( rez==SSH_EOF )
+            {
+#ifdef DEBUG
+                qDebug()<<"EOF ON CHANNEL "<<channel<<endl;
+#endif
+                //////Finished////////
+                finalize ( i );
+                continue;
+            }
+            if ( rez>0 )
+            {
+                nbytes = channel_read ( channel, buffer, sizeof ( buffer )-1, 0 );
+                if ( nbytes > 0 )
+                {
+                    if ( tcpSocket>0 )
+                    {
+                        if ( send ( tcpSocket,buffer, nbytes,0 ) != nbytes )
+                        {
+                            QString errMsg=tr ( "error writing to socket" );
+                            qDebug()<<"error writing "<<nbytes<<" to tcp socket"<<tcpSocket<<endl;
+                            emit signalIoError ( channelConnections[i].creator,errMsg,"" );
+                            finalize ( i );
+                            continue;
+                        }
+                    }
+                    else
+                    {
+                        emit signalStdOut ( channelConnections[i].creator, QByteArray ( buffer,nbytes ) );
+                    }
+                }
+
+                if ( nbytes < 0 )
+                {
+                    //////ERROR!!!!!////////
+                    QString err=ssh_get_error ( my_ssh_session );
+                    QString errorMsg=tr ( "error reading channel" );
+                    emit signalIoError ( channelConnections[i].creator, errorMsg, err );
+                    qDebug()<<errorMsg<<" - "<<err<<endl;
+                    finalize ( i );
+                    continue;
+                }
+
+                if ( channel_is_eof ( channel ) )
+                {
+#ifdef DEBUG
+                    qDebug()<<"EOF ON CHANNEL "<<channel<<endl;
+#endif
+                    //////Finished////////
+                    finalize ( i );
+                    continue;
+                }
+            }
+            if ( tcpSocket<=0 )
+            {
+                continue;
+            }
+            if ( FD_ISSET ( tcpSocket,&rfds ) )
+            {
+                nbytes = recv ( tcpSocket, buffer, sizeof ( buffer )-1,0 );
+                if ( nbytes > 0 )
+                {
+                    if ( channel_write ( channel, buffer, nbytes ) !=nbytes )
+                    {
+                        QString err=ssh_get_error ( my_ssh_session );
+                        QString errorMsg=tr ( "channel_write failed" );
+                        emit signalIoError ( channelConnections[i].creator, errorMsg, err );
+                        qDebug()<<errorMsg<<" - "<<err<<endl;
+                        finalize ( i );
+                        continue;
+                    }
+                }
+                if ( nbytes < 0 )
+                {
+                    //////ERROR!!!!!////////
+                    QString err="";
+                    QString errorMsg=tr ( "error reading tcp socket" );
+                    emit signalIoError ( channelConnections[i].creator, errorMsg, err );
+                    qDebug()<<errorMsg<<" - "<<err<<endl;
+                    finalize ( i );
+                    continue;
+                }
+                if ( nbytes==0 )
+                {
+#ifdef DEBUG
+                    qDebug()<<"socket closed "<<tcpSocket<<endl;
+#endif
+                    finalize ( i );
+                    continue;
+                }
+            }
+        }
+        channelConnectionsMutex.unlock();
+    }
+}
+
+void SshConnection::finalize(int item)
+{
+    int tcpSocket=channelConnections.at ( item ).sock;
+    ssh_channel channel=channelConnections.at ( item ).channel;
+    if ( channel )
+    {
+        channel_send_eof ( channel );
+#ifdef DEBUG
+        qDebug()<<"eof sent\n";
+#endif
+        channel_close ( channel );
+#ifdef DEBUG
+        qDebug()<<"channel closed\n";
+#endif
+        channel_free ( channel );
+    }
+    if ( tcpSocket>0 )
+    {
+#ifndef Q_OS_WIN
+        shutdown(tcpSocket, SHUT_RDWR);
+#endif
+        close ( tcpSocket );
+    }
+    SshProcess* proc=channelConnections[item].creator;
+    channelConnections.removeAt ( item );
+    emit signalChannelClosed ( proc );
+}
 
+void SshConnection::addChannelConnection(SshProcess* creator, QString cmd)
+{
+    ChannelConnection con;
+    con.channel=NULL;
+    con.sock=-1;
+    con.creator=creator;
+    con.command=cmd;
+
+    channelConnectionsMutex.lock();
+    channelConnections<<con;
+    channelConnectionsMutex.unlock();
+}
+
+void SshConnection::addChannelConnection(SshProcess* creator, int sock, QString forwardHost, int forwardPort, QString localHost, int localPort, void* channel)
+{
+    ChannelConnection con;
+    con.channel= ( ssh_channel ) channel;
+    con.sock=sock;
+    con.creator=creator;
+    con.forwardHost=forwardHost;
+    con.forwardPort=forwardPort;
+    con.localHost=localHost;
+    con.localPort=localPort;
+
+
+    channelConnectionsMutex.lock();
+    channelConnections<<con;
+    channelConnectionsMutex.unlock();
 }
 
-void SshConnection::finalize(int arg1)
+void SshConnection::addCopyRequest(SshProcess* creator, QString src, QString dst)
 {
+    CopyRequest req;
+    req.src=src;
+    req.dst=dst;
+    req.creator=creator;
+    copyRequestMutex.lock();
+    copyRequests<<req;
+    copyRequestMutex.unlock();
+}
 
+SshConnection* SshConnection::reverseTunnelConnection(SshProcess* creator, int remotePort, QString localHost, int localPort)
+{
+    SshConnection* con=new SshConnection (this, host, port, acceptUnknownServers, user, pass,
+                                          key, autoLogin, kerberos, remotePort,localHost,
+                                          localPort, creator, useProxy, proxyType, proxyServer, proxyPort, proxyLogin,
+                                          proxyPassword, proxyKey, proxyAutoLogin, localProxyPort );
+
+    connect(con, SIGNAL(signalIoError(SshProcess*, QString, QString)), this, SIGNAL(signalIoError(SshProcess*, QString, QString)));
+    connect(con, SIGNAL(signalStdErr(SshProcess*, QByteArray)), this, SIGNAL ( signalStdErr(SshProcess*, QByteArray)));
+    connect(con, SIGNAL(signalReverseListenOk(SshProcess*)), this, SIGNAL(signalReverseListenOk(SshProcess*)));
+    con->start();
+    reverseTunnelConnectionsMutex.lock();
+    reverseTunnelConnections.append ( con );
+    reverseTunnelConnectionsMutex.unlock();
+    return con;
+}
+
+int SshConnection::executeCommand(const QString& command, QObject* receiver, const char* slotFinished)
+{
+    SshProcess* proc=new SshProcess(this, nextPid++);
+    if(receiver && slotFinished)
+    {
+        connect(proc, SIGNAL(signalSshFinished(bool,QString,int)), receiver, slotFinished);
+    }
+    proc->startCommand(command);
+    processes<<proc;
+    return proc->pid;
 }
diff --git a/sshconnection.h b/sshconnection.h
index abb08e7..81171ab 100644
--- a/sshconnection.h
+++ b/sshconnection.h
@@ -35,32 +35,10 @@
 class SshProcess;
 class SshConnectionGuiInteraction;
 
-struct ChannelConnection
-{
-    ssh_channel channel;
-    int sock;
-    SshProcess* creator;
-    int forwardPort;
-    int localPort;
-    QString forwardHost;
-    QString localHost;
-    QString command;
-    bool operator==(ChannelConnection& t)
-    {
-        return (channel==t.channel);
-    }
-};
-
-struct CopyRequest
-{
-    SshProcess* creator;
-    QString src;
-    QString dst;
-};
-
 class SshConnection: public QThread
 {
     Q_OBJECT
+    X2GO_RO_PROPERTY(bool, connected)
 public:
     enum ProxyType {PROXYSSH, PROXYHTTP};
     enum Error {CONNECTION, SERVERAUTH, USERAUTH};
@@ -71,7 +49,39 @@ public:
                   bool proxyAutoLogin=false);
     ~SshConnection();
     static void finalizeLibSsh();
+    void addChannelConnection(SshProcess* creator, QString cmd);
+    void addChannelConnection(SshProcess* creator, int sock, QString forwardHost,
+                              int forwardPort, QString localHost, int localPort, void* channel=0l);
+
+    void addCopyRequest(SshProcess* creator, QString src, QString dst);
+    SshConnection* reverseTunnelConnection(SshProcess* creator, int remotePort,
+                                           QString localHost, int localPort);
+    int executeCommand(const QString& command, QObject* receiver=0, const char* slotFinished=0);
+
+
+
 private:
+    struct ChannelConnection
+    {
+        ssh_channel channel;
+        int sock;
+        SshProcess* creator;
+        int forwardPort;
+        int localPort;
+        QString forwardHost;
+        QString localHost;
+        QString command;
+        bool operator==(ChannelConnection& t)
+        {
+            return (channel==t.channel);
+        }
+    };
+    struct CopyRequest
+    {
+        SshProcess* creator;
+        QString src;
+        QString dst;
+    };
     ssh_session my_ssh_session;
     QList<ChannelConnection> channelConnections;
     QList<CopyRequest> copyRequests;
@@ -110,20 +120,40 @@ private:
     bool breakLoop;
     static bool isLibSshInited;
     static SshConnectionGuiInteraction* guiInteractor;
+
+    QMutex channelConnectionsMutex;
+    QMutex copyRequestMutex;
+    QMutex disconnectFlagMutex;
+    QMutex reverseTunnelConnectionsMutex;
+
 private:
+    SshConnection(QObject* parent, QString host, int port, bool acceptUnknownServers, QString user,
+                  QString pass, QString key, bool autoLogin, bool krbLogin, int remotePort, QString localHost,
+                  int localPort, SshProcess* creator,
+                  bool useProxy=false, ProxyType proxyType=PROXYSSH, QString proxyServer=QString::null, quint16 proxyPort=0,
+                  QString proxyLogin=QString::null, QString proxyPassword=QString::null, QString proxyKey=QString::null,
+                  bool proxyAutoLogin=false, int localProxyPort=0);
+
     bool sshConnect();
     bool userAuthWithPass();
     bool userAuthAuto();
     bool userAuthWithKey();
     bool userAuth();
     void channelLoop();
-    void finalize(int arg1);
+    void finalize(int item);
     int serverAuth(QString& errorMsg);
+    void copy();
 protected:
     void run();
 signals:
-    void signalError(Error, QString);
+    void signalError(int, QString);
     void signalIoError(SshProcess* caller, QString error, QString lastSessionError);
+    void signalCopyError(SshProcess* caller, QString error, QString lastSessionError);
+    void signalCopyOk(SshProcess* caller);
+    void signalChannelClosed(SshProcess* caller);
+
+    void signalStdErr(SshProcess* caller, QByteArray data);
+    void signalStdOut(SshProcess* caller, QByteArray data);
 
     void signalConnectionOk( QString host);
     void signalReverseListenOk(SshProcess* creator);
diff --git a/sshprocess.cpp b/sshprocess.cpp
new file mode 100644
index 0000000..f382f64
--- /dev/null
+++ b/sshprocess.cpp
@@ -0,0 +1,242 @@
+/**************************************************************************
+*   Copyright (C) 2005-2012 by Oleksandr Shneyder                         *
+*   o.shneyder at phoca-gmbh.de                                              *
+*                                                                         *
+*   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.,                                       *
+*   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+***************************************************************************/
+
+
+#include "sshprocess.h"
+#include <QTimer>
+#include <QDebug>
+
+#ifndef Q_OS_WIN
+#include <arpa/inet.h>
+#include <netinet/tcp.h>
+#endif
+
+#undef DEBUG
+// #define DEBUG
+
+
+SshProcess::SshProcess(SshConnection* masterConnection, int pid): QObject()
+{
+    this->masterConnection=masterConnection;
+    serverSocket=0;
+    this->pid=pid;
+    connect(masterConnection, SIGNAL(signalStdErr(SshProcess*,QByteArray)),this,SLOT(slotStdErr(SshProcess*,QByteArray)));
+    connect(masterConnection, SIGNAL(signalIoError(SshProcess*,QString,QString)), this,SLOT(slotIOerr(SshProcess*,QString,QString)));
+    tunnel=false;
+    normalExited=true;
+
+}
+
+SshProcess::~SshProcess()
+{
+#ifdef DEBUG
+    qDebug()<<"ssh process destructor";
+#endif
+    if (serverSocket>0)
+    {
+#ifdef Q_OS_WIN
+        closesocket(serverSocket);
+        WSACleanup();
+
+#else
+        close(serverSocket);
+#endif
+    }
+}
+
+
+void SshProcess::startCommand(const QString& cmd)
+{
+    QString shcmd = "sh -c \""+cmd+"\"";
+    masterConnection->addChannelConnection(this, shcmd);
+    connect(masterConnection,SIGNAL(signalStdOut(SshProcess*,QByteArray)),this,SLOT(slotStdOut(SshProcess*,QByteArray)));
+    connect(masterConnection,SIGNAL(signalChannelClosed(SshProcess*)), this,SLOT(slotChannelClosed(SshProcess*)));
+}
+
+void SshProcess::startCopy(QString src, QString dst)
+{
+    connect(masterConnection, SIGNAL(signalCopyError(SshProcess*,QString,QString)), this,
+            SLOT(slotCopyErr(SshProcess*,QString,QString)));
+    connect(masterConnection, SIGNAL(signalCopyOk(SshProcess*)), this,SLOT(slotCopyOk(SshProcess*)));
+    scpSource=src;
+    masterConnection->addCopyRequest(this,src,dst);
+}
+
+void SshProcess::startTunnel(const QString& forwardHost, uint forwardPort, const QString& localHost, uint localPort, bool reverse)
+{
+    this->forwardHost=forwardHost;
+    this->forwardPort=forwardPort;
+    this->localHost=localHost;
+    this->localPort=localPort;
+    tunnel=true;
+    if (!reverse)
+        tunnelLoop();
+    else
+    {
+        connect(masterConnection, SIGNAL(signalReverseListenOk(SshProcess*)), this, SLOT(slotReverseTunnelOk(SshProcess*)));
+        tunnelConnection=masterConnection->reverseTunnelConnection(this, forwardPort, localHost, localPort);
+    }
+}
+
+void SshProcess::slotChannelClosed(SshProcess* creator)
+{
+    if (creator!=this)
+        return;
+    QString output;
+    if (!normalExited)
+    {
+        output=abortString;
+    }
+    else
+    {
+        if ( stdOutString.length()<=0 &&  stdErrString.length() >0 )
+        {
+            normalExited=false;
+            output=stdErrString;
+#ifdef DEBUG
+            qDebug()<<"have only stderr, something must be wrong"<<endl;
+#endif
+        }
+        else
+            output=stdOutString;
+    }
+#ifdef DEBUG
+    qDebug()<<"ssh finished:"<<normalExited<<" - "<<output<<endl;
+#endif
+    emit signalSshFinished(normalExited, output, pid);
+}
+
+void SshProcess::slotCheckNewConnection()
+{
+    fd_set rfds;
+    struct timeval tv;
+
+    tv.tv_sec = 0;
+    tv.tv_usec = 0;
+
+    FD_ZERO(&rfds);
+    FD_SET(serverSocket, &rfds);
+
+    if (select(serverSocket+1,&rfds,NULL,NULL,&tv)<=0)
+        return;
+
+#ifdef DEBUG
+    qDebug()<<"new tcp connection\n";
+#endif
+    int tcpSocket=accept(serverSocket, (struct sockaddr*)&address,&addrlen);
+
+#ifdef DEBUG
+    qDebug()<<"new socket:"<<tcpSocket<<endl;
+#endif
+    masterConnection->addChannelConnection(this, tcpSocket, forwardHost, forwardPort, localHost,
+                                           ntohs(address.sin_port));
+}
+
+void SshProcess::slotCopyErr(SshProcess* creator, QString message, QString sshSessionErr)
+{
+    if (creator!=this)
+        return;
+    emit signalSshFinished(false, message+" - "+sshSessionErr, pid);
+
+}
+
+void SshProcess::slotCopyOk(SshProcess* creator)
+{
+    if (creator!=this)
+        return;
+    emit signalSshFinished(true,"", pid);
+}
+
+void SshProcess::slotIOerr(SshProcess* creator, QString message, QString sshSessionErr)
+{
+    if (creator!=this)
+        return;
+#ifdef DEBUG
+    qDebug()<<"io error:"<<message<<" - "<<sshSessionErr<<endl;
+#endif
+    normalExited=false;
+    abortString=message+" - "+sshSessionErr;
+}
+
+void SshProcess::slotReverseTunnelOk(SshProcess* creator)
+{
+    if (creator==this)
+        emit signalSshTunnelOk(pid);
+
+}
+
+void SshProcess::slotStdErr(SshProcess* creator, QByteArray data)
+{
+    if (creator!=this)
+        return;
+#ifdef DEBUG
+    qDebug()<<"new err data:"<<data<<endl;
+#endif
+    stdErrString+=data;
+}
+
+void SshProcess::slotStdOut(SshProcess* creator, QByteArray data)
+{
+    if (creator!=this)
+        return;
+#ifdef DEBUG
+    qDebug()<<"new data"<<data<<endl;
+#endif
+    stdOutString+=data;
+}
+
+void SshProcess::tunnelLoop()
+{
+    serverSocket=socket(AF_INET, SOCK_STREAM, 0);
+    if (serverSocket<=0)
+    {
+        QString err=tr("Error creating socket");
+        qDebug()<<err<<endl;
+        emit signalSshFinished(false,err,pid);
+        return;
+    }
+#ifndef Q_OS_WIN
+    const int y=1;
+#else
+    const char y=1;
+#endif
+    setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR,&y, sizeof(int));
+    setsockopt(serverSocket, IPPROTO_TCP, TCP_NODELAY,&y, sizeof(int));
+
+    address.sin_family=AF_INET;
+    address.sin_addr.s_addr=INADDR_ANY;
+    address.sin_port=htons(localPort);
+    if (bind(serverSocket,(struct sockaddr*) &address,sizeof(address))!=0)
+    {
+        QString err=tr("Error binding ")+localHost+":"+QString::number(localPort);
+        qDebug()<<err<<endl;
+        emit signalSshFinished(false,err,pid);
+        return;
+    }
+    listen(serverSocket,5);
+    addrlen=sizeof(struct sockaddr_in);
+    QTimer* timer=new QTimer();
+    connect(timer,SIGNAL(timeout()),this,SLOT(slotCheckNewConnection()));
+    timer->start(100);
+    emit signalSshTunnelOk(pid);
+#ifdef DEBUG
+    qDebug()<<"Direct tunnel: waiting for connections on "<<localHost<<":"<<localPort<<endl;
+#endif
+}
diff --git a/sshprocess.h b/sshprocess.h
new file mode 100644
index 0000000..5603f0c
--- /dev/null
+++ b/sshprocess.h
@@ -0,0 +1,84 @@
+/**************************************************************************
+*   Copyright (C) 2005-2012 by Oleksandr Shneyder                         *
+*   o.shneyder at phoca-gmbh.de                                              *
+*                                                                         *
+*   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.,                                       *
+*   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+***************************************************************************/
+
+
+#ifndef SSHPROCESS_H
+#define SSHPROCESS_H
+
+#include <QObject>
+
+#ifndef Q_OS_WIN
+#include <netinet/in.h>
+#endif
+
+#include "sshconnection.h"
+
+
+class SshProcess: public QObject
+{
+    Q_OBJECT
+    friend class SshConnection;
+private:
+    explicit SshProcess(SshConnection* masterConnection, int pid);
+    virtual ~SshProcess();
+    void startCommand(const QString& cmd);
+    void startTunnel(const QString& forwardHost, uint forwardPort, const QString& localHost,
+                     uint localPort, bool reverse=false);
+    void startCopy(QString src, QString dst);
+    void tunnelLoop();
+
+private:
+    SshConnection* masterConnection;
+    SshConnection* tunnelConnection;
+    int pid;
+    QString forwardHost;
+    QString localHost;
+    QString command;
+    QString scpSource;
+    quint16 forwardPort;
+    quint16 localPort;
+    uint serverSocket;
+    struct sockaddr_in address;
+#ifndef  Q_OS_WIN
+    socklen_t addrlen;
+#else
+    int addrlen;
+#endif
+    QString stdOutString;
+    QString stdErrString;
+    QString abortString;
+    bool tunnel;
+    bool normalExited;
+
+private slots:
+    void slotCheckNewConnection();
+    void slotStdErr(SshProcess* creator, QByteArray data);
+    void slotStdOut(SshProcess* creator, QByteArray data);
+    void slotIOerr(SshProcess* creator,QString message, QString sshSessionErr);
+    void slotChannelClosed(SshProcess* creator);
+    void slotReverseTunnelOk(SshProcess* creator);
+    void slotCopyOk(SshProcess* creator);
+    void slotCopyErr(SshProcess* creator,QString message, QString sshSessionErr);
+signals:
+    void signalSshFinished ( bool result, QString output, int processId);
+    void signalSshTunnelOk(int processId);
+};
+
+#endif // SSHPROCESS_H
diff --git a/x2goapplication.cpp b/x2goapplication.cpp
index 817f571..7ff0050 100644
--- a/x2goapplication.cpp
+++ b/x2goapplication.cpp
@@ -78,18 +78,21 @@ void X2GoApplication::slotInitApplication()
     {
         QMessageBox::critical(0,tr("Error"), tr("Error parsing command line arguments"));
         exit(-1);
+        return;
     }
     if(clientConfig->get_showHelp().get_value().toBool())
     {
         HelpDialog dialog(0);
         dialog.showHelp();
         exit(-1);
+        return;
     }
     if(clientConfig->get_showHelpPack().get_value().toBool())
     {
         HelpDialog dialog(0);
         dialog.showPacks();
         exit(-1);
+        return;
     }
 
     if(clientConfig->get_brokerUrl().get_value().toString()==QString::null)
@@ -106,7 +109,7 @@ void X2GoApplication::slotInitApplication()
         if(broker->get_brokerAbort())
             return;
         connect(broker, SIGNAL(signalSessionsLoaded()), this, SLOT(slotBrokerSessionsConfig()));
-        broker->getUserSessions();
+        broker->slotGetUserSessions();
     }
     if(clientConfig->get_disallowSessionEdit().get_value().toBool())
     {
diff --git a/x2gobroker.cpp b/x2gobroker.cpp
index cca32a7..ba34837 100644
--- a/x2gobroker.cpp
+++ b/x2gobroker.cpp
@@ -22,6 +22,7 @@
 #include <QFile>
 #include <QDir>
 #include <QDebug>
+#include <QTimer>
 #include "x2gobroker.h"
 #include "x2goapplication.h"
 #include "x2goclientconfig.h"
@@ -39,7 +40,7 @@ X2GoBroker::X2GoBroker(QObject* parent): QObject(parent)
     url = QUrl( urlString);
     if(url.userName().length()>0)
         user=url.userName();
-    if(!cfg->get_defaultNoBrockerAuth().get_value().toBool())
+    if(!cfg->get_defaultNoBrockerAuth().get_value().toBool() && brokerType==HTTP)
     {
         getLoginData();
     }
@@ -47,10 +48,14 @@ X2GoBroker::X2GoBroker(QObject* parent): QObject(parent)
     {
         brokerType=SSH;
 #warning search for default key hier
-        SshConnection* con=new SshConnection(this, url.host(), url.port(), cfg->get_autoAddToKnownHosts().get_value().toBool(),
-                                             user, pass, QString::null,
-                                             cfg->get_defaultAutoLogin().get_value().toBool());
-        con->start();
+
+        sshConnection=new SshConnection(this, url.host(), url.port(), cfg->get_autoAddToKnownHosts().get_value().toBool(),
+                                        user, pass, cfg->get_brokerSSHKey().get_value().toString(),
+                                        cfg->get_defaultBrockerAutoLogin().get_value().toBool());
+        connect(sshConnection, SIGNAL(signalConnectionOk(QString)), this, SLOT(slotSshConnectionOk()));
+        connect(sshConnection, SIGNAL(signalError(int,QString)), this,
+                SLOT(slotSshConnectionError(int,QString)));
+        sshConnection->start();
     }
     else
     {
@@ -89,6 +94,7 @@ X2GoBroker::~X2GoBroker()
 
 void X2GoBroker::getLoginData()
 {
+    X2GoClientConfig* cfg=X2GoApplication::instance()->get_clientConfig();
     if(url.userName().length()<=0)
     {
         MessageBox::Buttons res=MessageBox::input(tr("Enter user name for authentication on broker"),tr("User:"),user);
@@ -98,6 +104,13 @@ void X2GoBroker::getLoginData()
             X2GoApplication::exit(-1);
         }
     }
+    if(brokerType==SSH)
+    {
+        if(cfg->get_defaultBrockerAutoLogin().get_value().toBool())
+            return;
+        if(cfg->get_brokerSSHKey().get_value().toString().length()>0)
+            return;
+    }
     pass=QString::null;
     MessageBox::Buttons res=MessageBox::input(tr("Enter password for authentication on broker"),tr("Password:"),pass, QLineEdit::Password);
     if(res!=MessageBox::OK)
@@ -108,7 +121,7 @@ void X2GoBroker::getLoginData()
 }
 
 
-void X2GoBroker::getUserSessions()
+void X2GoBroker::slotGetUserSessions()
 {
     if(brokerType==HTTP)
     {
@@ -122,6 +135,19 @@ void X2GoBroker::getUserSessions()
         httpSessionAnswer.setData ( 0,0 );
         sessionsRequest=http->post ( url.path(),req.toUtf8(),&httpSessionAnswer );
     }
+    if(brokerType==SSH)
+    {
+        if(!sshConnection->get_connected())
+        {
+            QTimer::singleShot(100, this, SLOT(slotGetUserSessions()));
+            return;
+        }
+        sshConnection->executeCommand ( url.path() +" --authid "+
+                                        X2GoApplication::instance()->get_clientConfig()->get_authId().get_value().toString()+
+                                        " --task listsessions",
+                                        this, SLOT ( slotListSessions ( bool, QString,int ) ));
+
+    }
 }
 
 void X2GoBroker::slotRequestFinished(int id, bool error)
@@ -155,7 +181,7 @@ void X2GoBroker::slotListSessions(bool success, QString answer, int)
     if(!checkAccess(answer))
     {
         getLoginData();
-        getUserSessions();
+        slotGetUserSessions();
         return;
     }
     createIniFile(answer);
@@ -311,4 +337,14 @@ QString X2GoBroker::getHexVal(const QByteArray& ba)
 }
 
 
+void X2GoBroker::slotSshConnectionError(int, QString message)
+{
+    X2GoApplication::exit(-1);
+}
+
+void X2GoBroker::slotSshConnectionOk()
+{
+
+}
+
 
diff --git a/x2gobroker.h b/x2gobroker.h
index 49e3248..a101f40 100644
--- a/x2gobroker.h
+++ b/x2gobroker.h
@@ -28,6 +28,7 @@
 #include <QSslError>
 #include <QTime>
 #include "x2goapplication.h"
+#include "sshconnection.h"
 class QHttp;
 
 class X2GoBroker : public QObject
@@ -38,7 +39,6 @@ class X2GoBroker : public QObject
 public:
     explicit X2GoBroker(QObject* parent = 0);
     virtual ~X2GoBroker();
-    void getUserSessions();
 private:
     enum {SSH,HTTP} brokerType;
     QString user;
@@ -51,6 +51,7 @@ private:
     int sessionsRequest;
     int selSessRequest;
     QTime requestTime;
+    SshConnection* sshConnection;
 private:
     void getLoginData();
     QString getHexVal ( const QByteArray& ba );
@@ -61,6 +62,12 @@ private slots:
     void slotRequestFinished ( int id, bool error );
     void slotSslErrors ( const QList<QSslError> & errors ) ;
     void slotListSessions ( bool success, QString answer, int pid);
+    void slotSshConnectionError ( int error, QString message);
+    void slotSshConnectionOk ();
+
+public slots:
+    void slotGetUserSessions();
+
 signals:
     void signalSessionsLoaded();
 };
diff --git a/x2goclient2.pro b/x2goclient2.pro
index 5f02ec9..6962eac 100755
--- a/x2goclient2.pro
+++ b/x2goclient2.pro
@@ -58,6 +58,7 @@ SOURCES += main.cpp \
            x2gobroker.cpp \
            sshconnection.cpp \
            sshconnectionguiinteraction.cpp \
+           sshprocess.cpp \
            profile.cpp
 
 HEADERS += mainwindow.h \
@@ -88,6 +89,7 @@ HEADERS += mainwindow.h \
            x2gobroker.h \
            sshconnection.h \
            sshconnectionguiinteraction.h \
+           sshprocess.h \
            profile.h
 
 LIBS += -lssh


hooks/post-receive
-- 
x2goclient2.git (X2Go Client 2 (rewrite of x2goclient.git))

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "x2goclient2.git" (X2Go Client 2 (rewrite of x2goclient.git)).




More information about the x2go-commits mailing list