Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

qcopbridge.cpp

Go to the documentation of this file.
00001 /**********************************************************************
00002 ** Copyright (C) 2000-2002 Trolltech AS.  All rights reserved.
00003 **
00004 ** This file is part of the Qtopia Environment.
00005 **
00006 ** This file may be distributed and/or modified under the terms of the
00007 ** GNU General Public License version 2 as published by the Free Software
00008 ** Foundation and appearing in the file LICENSE.GPL included in the
00009 ** packaging of this file.
00010 **
00011 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00012 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00013 **
00014 ** See http://www.trolltech.com/gpl/ for GPL licensing information.
00015 **
00016 ** Contact info@trolltech.com if any conditions of this licensing are
00017 ** not clear to you.
00018 **
00019 **********************************************************************/
00020 
00021 #include "qcopbridge.h"
00022 #include "transferserver.h"
00023 
00024 /* OPIE */
00025 #include <opie2/odebug.h>
00026 #include <opie2/oglobal.h>
00027 #ifdef Q_WS_QWS
00028 #include <qtopia/qcopenvelope_qws.h>
00029 #endif
00030 #include <qtopia/qpeapplication.h>
00031 #include <qtopia/version.h>
00032 using namespace Opie::Core;
00033 
00034 /* QT */
00035 #include <qtextstream.h>
00036 #include <qtimer.h>
00037 #ifdef Q_WS_QWS
00038 #include <qcopchannel_qws.h>
00039 #endif
00040 
00041 /* STD */
00042 #ifndef _XOPEN_SOURCE
00043 #define _XOPEN_SOURCE
00044 #endif
00045 #ifndef Q_OS_WIN32
00046 #include <pwd.h>
00047 #include <unistd.h>
00048 #include <fcntl.h>
00049 #include <sys/types.h>
00050 #endif
00051 
00052 #if defined(_OS_LINUX_)
00053 #include <shadow.h>
00054 #endif
00055 
00056 const int block_size = 51200;
00057 
00058 QCopBridge::QCopBridge( Q_UINT16 port, QObject *parent,
00059         const char* name )
00060     : QServerSocket( port, 1, parent, name ),
00061       desktopChannel( 0 ),
00062       cardChannel( 0 )
00063 {
00064     if ( !ok() )
00065         owarn << "Failed to bind to port " << port << "" << oendl;
00066     else {
00067         ::fcntl( socket(), F_SETFD, FD_CLOEXEC );
00068 #ifndef QT_NO_COP
00069         desktopChannel = new QCopChannel( "QPE/Desktop", this );
00070         connect( desktopChannel, SIGNAL(received(const QCString&,const QByteArray&)),
00071                  this, SLOT(desktopMessage(const QCString&,const QByteArray&)) );
00072         cardChannel = new QCopChannel( "QPE/Card", this );
00073         connect( cardChannel, SIGNAL(received(const QCString&,const QByteArray&)),
00074                  this, SLOT(desktopMessage(const QCString&,const QByteArray&)) );
00075 #endif
00076     }
00077     sendSync = FALSE;
00078     openConnections.setAutoDelete( TRUE );
00079     authorizeConnections();
00080 }
00081 
00082 QCopBridge::~QCopBridge()
00083 {
00084 #ifndef QT_NO_COP
00085     delete desktopChannel;
00086 #endif
00087 }
00088 
00089 void QCopBridge::authorizeConnections()
00090 {
00091     Config cfg("Security");
00092     cfg.setGroup("SyncMode");
00093     m_mode = Mode(cfg.readNumEntry("Mode", Sharp ));
00094     QListIterator<QCopBridgePI> it(openConnections);
00095     while ( it.current() ) {
00096         if ( !it.current()->verifyAuthorised() ) {
00097             disconnect ( it.current(), SIGNAL( connectionClosed(QCopBridgePI*) ), this, SLOT( closed(QCopBridgePI*) ) );
00098             openConnections.removeRef( it.current() );
00099         } else
00100             ++it;
00101     }
00102 }
00103 
00104 void QCopBridge::newConnection( int socket )
00105 {
00106     QCopBridgePI *pi = new QCopBridgePI( socket, this );
00107     openConnections.append( pi );
00108     connect ( pi, SIGNAL( connectionClosed(QCopBridgePI*) ), this, SLOT( closed(QCopBridgePI*) ) );
00109 
00110     /* ### libqtopia merge FIXME */
00111 #if 0
00112     QPEApplication::setTempScreenSaverMode( QPEApplication::DisableSuspend );
00113 #endif
00114 #ifndef QT_NO_COP
00115     QCopEnvelope( "QPE/System", "setScreenSaverMode(int)" ) << QPEApplication::DisableSuspend;
00116 #endif
00117 
00118     if ( sendSync ) {
00119         pi ->startSync();
00120         sendSync = FALSE;
00121     }
00122 }
00123 
00124 void QCopBridge::closed( QCopBridgePI *pi )
00125 {
00126     emit connectionClosed( pi->peerAddress() );
00127     openConnections.removeRef( pi );
00128     if ( openConnections.count() == 0 ) {
00129         /* ### FIXME libqtopia merge */
00130 #if 0
00131         QPEApplication::setTempScreenSaverMode( QPEApplication::Enable );
00132 #endif
00133 #ifndef QT_NO_COP
00134         QCopEnvelope( "QPE/System", "setScreenSaverMode(int)" ) << QPEApplication::Enable;
00135 #endif
00136     }
00137 }
00138 
00139 void QCopBridge::closeOpenConnections()
00140 {
00141     QCopBridgePI *pi;
00142     for ( pi = openConnections.first(); pi != 0; pi = openConnections.next() )
00143         pi->close();
00144 }
00145 
00146 
00147 void QCopBridge::desktopMessage( const QCString &command, const QByteArray &data )
00148 {
00149     if ( command == "startSync()" ) {
00150         // we need to buffer it a bit
00151         sendSync = TRUE;
00152         startTimer( 20000 );
00153     }
00154 
00155     if ( m_mode & Qtopia1_7 ) {
00156         // send the command to all open connections
00157         QCopBridgePI *pi;
00158         for ( pi = openConnections.first(); pi != 0; pi = openConnections.next() ) {
00159             pi->sendDesktopMessage( command, data );
00160         }
00161     }
00162     if ( ( m_mode & Sharp ) || (m_mode & IntelliSync) )
00163         sendDesktopMessageOld( command, data );
00164 }
00165 
00166 #ifndef OPIE_NO_OLD_SYNC_CODE
00167 /*
00168  * Old compat mode
00169  */
00170 void QCopBridge::sendDesktopMessageOld( const QCString& command, const QByteArray& args) {
00171     command.stripWhiteSpace();
00172 
00173     int paren = command.find( "(" );
00174     if ( paren <= 0 ) {
00175     odebug << "DesktopMessage: bad qcop syntax" << oendl;
00176         return;
00177     }
00178 
00179     QString params = command.mid( paren + 1 );
00180     if ( params[params.length()-1] != ')' ) {
00181     odebug << "DesktopMessage: bad qcop syntax" << oendl;
00182         return;
00183     }
00184 
00185     params.truncate( params.length()-1 );
00186 
00187     QStringList paramList = QStringList::split( ",", params );
00188     QString data;
00189     if ( paramList.count() ) {
00190         QDataStream stream( args, IO_ReadOnly );
00191         for ( QStringList::Iterator it = paramList.begin(); it != paramList.end(); ++it ) {
00192             QString str;
00193             if ( *it == "QString" ) {
00194                 stream >> str;
00195             } else if ( *it == "QCString" ) {
00196                 QCString cstr;
00197                 stream >> cstr;
00198                 str = QString::fromLocal8Bit( cstr );
00199             } else if ( *it == "int" ) {
00200                 int i;
00201                 stream >> i;
00202                 str = QString::number( i );
00203             } else if ( *it == "bool" ) {
00204                 int i;
00205                 stream >> i;
00206                 str = QString::number( i );
00207             } else {
00208         odebug << " cannot route the argument type " << (*it) << " throught the qcop bridge" << oendl;
00209                 return;
00210             }
00211             QString estr;
00212             for (int i=0; i<(int)str.length(); i++) {
00213                 QChar ch = str[i];
00214                 if ( ch.row() )
00215                     goto quick;
00216                 switch (ch.cell()) {
00217                     case '&':
00218                         estr.append( "&amp;" );
00219                         break;
00220                     case ' ':
00221                         estr.append( "&0x20;" );
00222                         break;
00223                     case '\n':
00224                         estr.append( "&0x0d;" );
00225                         break;
00226                     case '\r':
00227                         estr.append( "&0x0a;" );
00228                         break;
00229                     default: quick:
00230                         estr.append(ch);
00231                 }
00232             }
00233             data += " " + estr;
00234         }
00235     }
00236     QString sendCommand = QString(command.data()) + data;
00237 
00238 
00239     // send the command to all open connections
00240     QCopBridgePI *pi;
00241     for ( pi = openConnections.first(); pi != 0; pi = openConnections.next() )
00242         pi->sendDesktopMessage( sendCommand );
00243 
00244 }
00245 #endif
00246 
00247 
00248 void QCopBridge::timerEvent( QTimerEvent * )
00249 {
00250     sendSync = FALSE;
00251     killTimers();
00252 }
00253 
00254 
00255 QCopBridgePI::QCopBridgePI( int socket, QObject *parent, const char* name )
00256     : QSocket( parent, name )
00257 {
00258     setSocket( socket );
00259 
00260     peerport = peerPort();
00261     peeraddress = peerAddress();
00262 
00263 #ifndef INSECURE
00264     if ( !SyncAuthentication::isAuthorized(peeraddress) ) {
00265         state = Forbidden;
00266         close();
00267     } else
00268 #endif
00269     {
00270         state = Connected;
00271         connect( this, SIGNAL( readyRead() ), SLOT( read() ) );
00272         QString intro="220 Qtopia ";
00273         intro += QPE_VERSION; intro += ";";
00274         intro += "challenge="; intro += SyncAuthentication::serverId(); intro += ";"; // No tr
00275         intro += "loginname="; intro += SyncAuthentication::loginName(); intro += ";";
00276         intro += "displayname="; intro += SyncAuthentication::ownerName(); intro += ";";
00277         send( intro );
00278         state = Wait_USER;
00279     }
00280     sendSync = FALSE;
00281     connect( this, SIGNAL( connectionClosed() ), SLOT( myConnectionClosed() ) );
00282 
00283     // idle timer to close connections when not used anymore
00284     timer = new QTimer(this);
00285     connect( timer, SIGNAL(timeout()), this, SLOT(myConnectionClosed()) );
00286     timer->start( 300000, TRUE );
00287 }
00288 
00289 
00290 QCopBridgePI::~QCopBridgePI()
00291 {
00292 }
00293 
00294 bool QCopBridgePI::verifyAuthorised()
00295 {
00296     if ( !SyncAuthentication::isAuthorized(peerAddress()) ) {
00297         state = Forbidden;
00298         return FALSE;
00299     }
00300     return TRUE;
00301 }
00302 
00303 void QCopBridgePI::myConnectionClosed()
00304 {
00305     emit connectionClosed( this );
00306 }
00307 
00308 void QCopBridgePI::sendDesktopMessage( const QString &msg )
00309 {
00310     QString str = "CALL QPE/Desktop " + msg; // No tr
00311     send ( str );
00312 }
00313 
00314 void QCopBridgePI::sendDesktopMessage( const QCString &msg, const QByteArray& data )
00315 {
00316     if ( !isOpen() ) // eg. Forbidden
00317         return;
00318 
00319     const char hdr[]="CALLB QPE/Desktop ";
00320     writeBlock(hdr,sizeof(hdr)-1);
00321     writeBlock(msg,msg.length());
00322     writeBlock(" ",1);
00323     QByteArray b64 = OGlobal::encodeBase64(data);
00324     writeBlock(b64.data(),b64.size());
00325     writeBlock("\r\n",2);
00326 
00327 }
00328 
00329 
00330 void QCopBridgePI::send( const QString& msg )
00331 {
00332     if ( !isOpen() ) // eg. Forbidden
00333         return;
00334     QTextStream os( this );
00335     os << msg << endl;
00336     //odebug << "sending qcop message: " << msg << "" << oendl;
00337 }
00338 
00339 void QCopBridgePI::read()
00340 {
00341     while ( canReadLine() ) {
00342         timer->start( 300000, TRUE );
00343         process( readLine().stripWhiteSpace() );
00344     }
00345 }
00346 
00347 void QCopBridgePI::process( const QString& message )
00348 {
00349     //odebug << "Command: " << message << "" << oendl;
00350 
00351     // split message using "," as separator
00352     QStringList msg = QStringList::split( " ", message );
00353     if ( msg.isEmpty() ) return;
00354 
00355     // command token
00356     QString cmd = msg[0].upper();
00357 
00358     // argument token
00359     QString arg;
00360     if ( msg.count() >= 2 )
00361         arg = msg[1];
00362 
00363     // we always respond to QUIT, regardless of state
00364     if ( cmd == "QUIT" ) {
00365         send( "211 Have a nice day!" ); // No tr
00366         close();
00367         return;
00368     }
00369 
00370     // connected to client
00371     if ( Connected == state )
00372         return;
00373 
00374     // waiting for user name
00375     if ( Wait_USER == state ) {
00376 
00377         if ( cmd != "USER" || msg.count() < 2 || !SyncAuthentication::checkUser( arg ) ) {
00378             send( "530 Please login with USER and PASS" ); // No tr
00379             return;
00380         }
00381         send( "331 User name ok, need password" ); // No tr
00382         state = Wait_PASS;
00383         return;
00384     }
00385 
00386     // waiting for password
00387     if ( Wait_PASS == state ) {
00388 
00389         if ( cmd != "PASS" || !SyncAuthentication::checkPassword( arg ) ) {
00390             send( "530 Please login with USER and PASS" ); // No tr
00391             return;
00392         }
00393         send( "230 User logged in, proceed" ); // No tr
00394         state = Ready;
00395         if ( sendSync ) {
00396             sendDesktopMessage( "startSync()" );
00397             sendSync = FALSE;
00398         }
00399         return;
00400     }
00401 
00402     // noop (NOOP)
00403     else if ( cmd == "NOOP" ) {
00404         send( "200 Command okay" ); // No tr
00405     }
00406 
00407     // call (CALL)
00408     else if ( cmd == "CALL" ) {
00409 
00410         // example: call QPE/System execute(QString) addressbook
00411 
00412         if ( msg.count() < 3 ) {
00413             send( "500 Syntax error, command unrecognized" ); // No tr
00414         }
00415         else {
00416 
00417             QString channel = msg[1];
00418             QString command = msg[2];
00419 
00420             command.stripWhiteSpace();
00421 
00422             int paren = command.find( "(" );
00423             if ( paren <= 0 ) {
00424                 send( "500 Syntax error, command unrecognized" ); // No tr
00425                 return;
00426             }
00427 
00428             QString params = command.mid( paren + 1 );
00429             if ( params[(int)params.length()-1] != ')' ) {
00430                 send( "500 Syntax error, command unrecognized" ); // No tr
00431                 return;
00432             }
00433 
00434             params.truncate( params.length()-1 );
00435             QByteArray buffer;
00436             QDataStream ds( buffer, IO_WriteOnly );
00437 
00438             int msgId = 3;
00439 
00440             QStringList paramList = QStringList::split( ",", params );
00441             if ( paramList.count() > msg.count() - 3 ) {
00442                 send( "500 Syntax error, command unrecognized" ); // No tr
00443                 return;
00444             }
00445 
00446             for ( QStringList::Iterator it = paramList.begin(); it != paramList.end(); ++it ) {
00447 
00448                 QString arg = msg[msgId];
00449                 arg.replace( QRegExp("&0x20;"), " " );
00450                 arg.replace( QRegExp("&amp;"), "&" );
00451                 arg.replace( QRegExp("&0x0d;"), "\n" );
00452                 arg.replace( QRegExp("&0x0a;"), "\r" );
00453                 if ( *it == "QString" )
00454                     ds << arg;
00455                 else if ( *it == "QCString" )
00456                     ds << arg.local8Bit();
00457                 else if ( *it == "int" )
00458                     ds << arg.toInt();
00459                 else if ( *it == "bool" )
00460                     ds << arg.toInt();
00461                 else {
00462                     send( "500 Syntax error, command unrecognized" ); // No tr
00463                     return;
00464                 }
00465                 msgId++;
00466             }
00467 
00468 #ifndef QT_NO_COP
00469             if ( !QCopChannel::isRegistered( channel.latin1() ) ) {
00470                 // send message back about it
00471                 QString answer = "599 ChannelNotRegistered " + channel;
00472                 send( answer );
00473                 return;
00474             }
00475 #endif
00476 
00477 #ifndef QT_NO_COP
00478             if ( paramList.count() )
00479                 QCopChannel::send( channel.latin1(), command.latin1(), buffer );
00480             else
00481                 QCopChannel::send( channel.latin1(), command.latin1() );
00482 
00483             send( "200 Command okay" ); // No tr
00484 #endif
00485         }
00486     }
00487     // not implemented
00488     else
00489         send( "502 Command not implemented" ); // No tr
00490 }
00491 
00492 

Generated on Sat Nov 5 16:15:31 2005 for OPIE by  doxygen 1.4.2