00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "qcopbridge.h"
00022 #include "transferserver.h"
00023
00024
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
00035 #include <qtextstream.h>
00036 #include <qtimer.h>
00037 #ifdef Q_WS_QWS
00038 #include <qcopchannel_qws.h>
00039 #endif
00040
00041
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
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
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
00151 sendSync = TRUE;
00152 startTimer( 20000 );
00153 }
00154
00155 if ( m_mode & Qtopia1_7 ) {
00156
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
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( "&" );
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
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 += ";";
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
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;
00311 send ( str );
00312 }
00313
00314 void QCopBridgePI::sendDesktopMessage( const QCString &msg, const QByteArray& data )
00315 {
00316 if ( !isOpen() )
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() )
00333 return;
00334 QTextStream os( this );
00335 os << msg << endl;
00336
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
00350
00351
00352 QStringList msg = QStringList::split( " ", message );
00353 if ( msg.isEmpty() ) return;
00354
00355
00356 QString cmd = msg[0].upper();
00357
00358
00359 QString arg;
00360 if ( msg.count() >= 2 )
00361 arg = msg[1];
00362
00363
00364 if ( cmd == "QUIT" ) {
00365 send( "211 Have a nice day!" );
00366 close();
00367 return;
00368 }
00369
00370
00371 if ( Connected == state )
00372 return;
00373
00374
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" );
00379 return;
00380 }
00381 send( "331 User name ok, need password" );
00382 state = Wait_PASS;
00383 return;
00384 }
00385
00386
00387 if ( Wait_PASS == state ) {
00388
00389 if ( cmd != "PASS" || !SyncAuthentication::checkPassword( arg ) ) {
00390 send( "530 Please login with USER and PASS" );
00391 return;
00392 }
00393 send( "230 User logged in, proceed" );
00394 state = Ready;
00395 if ( sendSync ) {
00396 sendDesktopMessage( "startSync()" );
00397 sendSync = FALSE;
00398 }
00399 return;
00400 }
00401
00402
00403 else if ( cmd == "NOOP" ) {
00404 send( "200 Command okay" );
00405 }
00406
00407
00408 else if ( cmd == "CALL" ) {
00409
00410
00411
00412 if ( msg.count() < 3 ) {
00413 send( "500 Syntax error, command unrecognized" );
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" );
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" );
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" );
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("&"), "&" );
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" );
00463 return;
00464 }
00465 msgId++;
00466 }
00467
00468 #ifndef QT_NO_COP
00469 if ( !QCopChannel::isRegistered( channel.latin1() ) ) {
00470
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" );
00484 #endif
00485 }
00486 }
00487
00488 else
00489 send( "502 Command not implemented" );
00490 }
00491
00492