From 15318cad33835e4e2dc620d033e43cd930676cdd Mon Sep 17 00:00:00 2001 From: kergoth <kergoth> Date: Fri, 25 Jan 2002 22:14:26 +0000 Subject: Initial revision --- (limited to 'core/launcher/qcopbridge.cpp') diff --git a/core/launcher/qcopbridge.cpp b/core/launcher/qcopbridge.cpp new file mode 100644 index 0000000..c78e827 --- a/dev/null +++ b/core/launcher/qcopbridge.cpp @@ -0,0 +1,416 @@ +/********************************************************************** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qcopbridge.h" +#include "transferserver.h" + +#include <qpe/qcopenvelope_qws.h> +#include <qpe/qpeapplication.h> + +#include <qdir.h> +#include <qfile.h> +#include <qtextstream.h> +#include <qdatastream.h> +#include <qstringlist.h> +#include <qfileinfo.h> +#include <qregexp.h> +#include <qcopchannel_qws.h> + +#define _XOPEN_SOURCE +#include <pwd.h> +#include <sys/types.h> +#include <unistd.h> + +#if defined(_OS_LINUX_) +#include <shadow.h> +#endif + +//#define INSECURE + +const int block_size = 51200; + +QCopBridge::QCopBridge( Q_UINT16 port, QObject *parent = 0, + const char* name = 0) + : QServerSocket( port, 1, parent, name ), + desktopChannel( 0 ), + cardChannel( 0 ) +{ + if ( !ok() ) + qWarning( "Failed to bind to port %d", port ); + else { + desktopChannel = new QCopChannel( "QPE/Desktop", this ); + connect( desktopChannel, SIGNAL(received(const QCString &, const QByteArray &)), + this, SLOT(desktopMessage( const QCString &, const QByteArray &)) ); + cardChannel = new QCopChannel( "QPE/Card", this ); + connect( cardChannel, SIGNAL(received(const QCString &, const QByteArray &)), + this, SLOT(desktopMessage( const QCString &, const QByteArray &)) ); + } + sendSync = FALSE; +} + +QCopBridge::~QCopBridge() +{ + delete desktopChannel; +} + +void QCopBridge::newConnection( int socket ) +{ + QCopBridgePI *pi = new QCopBridgePI( socket, this ); + openConnections.append( pi ); + connect ( pi, SIGNAL( connectionClosed( QCopBridgePI *) ), this, SLOT( connectionClosed( QCopBridgePI *) ) ); + QCopEnvelope( "QPE/System", "setScreenSaverMode(int)" ) << QPEApplication::DisableSuspend; + + if ( sendSync ) { + pi ->startSync(); + sendSync = FALSE; + } +} + +void QCopBridge::connectionClosed( QCopBridgePI *pi ) +{ + openConnections.remove( pi ); + if ( openConnections.count() == 0 ) { + QCopEnvelope( "QPE/System", "setScreenSaverMode(int)" ) << QPEApplication::Enable; + } +} + +void QCopBridge::closeOpenConnections() +{ + QCopBridgePI *pi; + for ( pi = openConnections.first(); pi != 0; pi = openConnections.next() ) + pi->close(); +} + + +void QCopBridge::desktopMessage( const QCString &command, const QByteArray &args ) +{ + command.stripWhiteSpace(); + + int paren = command.find( "(" ); + if ( paren <= 0 ) { + qDebug("DesktopMessage: bad qcop syntax"); + return; + } + + QString params = command.mid( paren + 1 ); + if ( params[params.length()-1] != ')' ) { + qDebug("DesktopMessage: bad qcop syntax"); + return; + } + + params.truncate( params.length()-1 ); + + QStringList paramList = QStringList::split( ",", params ); + QString data; + if ( paramList.count() ) { + QDataStream stream( args, IO_ReadOnly ); + for ( QStringList::Iterator it = paramList.begin(); it != paramList.end(); ++it ) { + QString str; + if ( *it == "QString" ) { + stream >> str; + } else if ( *it == "QCString" ) { + QCString cstr; + stream >> cstr; + str = QString::fromLocal8Bit( cstr ); + } else if ( *it == "int" ) { + int i; + stream >> i; + str = QString::number( i ); + } else if ( *it == "bool" ) { + int i; + stream >> i; + str = QString::number( i ); + } else { + qDebug(" cannot route the argument type %s throught the qcop bridge", (*it).latin1() ); + return; + } + str.replace( QRegExp("&"), "&" ); + str.replace( QRegExp(" "), "&0x20;" ); + str.replace( QRegExp("\n"), "&0x0d;" ); + str.replace( QRegExp("\r"), "&0x0a;" ); + data += " " + str; + } + } + QString sendCommand = QString(command.data()) + data; + // send the command to all open connections + if ( command == "startSync()" ) { + // we need to buffer it a bit + sendSync = TRUE; + startTimer( 20000 ); + } + + QCopBridgePI *pi; + for ( pi = openConnections.first(); pi != 0; pi = openConnections.next() ) { + pi->sendDesktopMessage( sendCommand ); + } +} + +void QCopBridge::timerEvent( QTimerEvent * ) +{ + sendSync = FALSE; + killTimers(); +} + + +QCopBridgePI::QCopBridgePI( int socket, QObject *parent = 0, const char* name = 0 ) + : QSocket( parent, name ) +{ + setSocket( socket ); + + peerport = peerPort(); + peeraddress = peerAddress(); + +#ifndef INSECURE + if ( !accessAuthorized(peeraddress) ) { + state = Forbidden; + startTimer( 0 ); + } else +#endif + { + state = Connected; + sendSync = FALSE; + connect( this, SIGNAL( readyRead() ), SLOT( read() ) ); + connect( this, SIGNAL( connectionClosed() ), SLOT( connectionClosed() ) ); + + send( "220 Qtopia QCop bridge ready!" ); + state = Wait_USER; + + // idle timer to close connections when not used anymore + startTimer( 60000 ); + connected = TRUE; + } +} + + +QCopBridgePI::~QCopBridgePI() +{ + +} + +void QCopBridgePI::connectionClosed() +{ + emit connectionClosed( this ); + // qDebug( "Debug: Connection closed" ); + delete this; +} + +void QCopBridgePI::sendDesktopMessage( const QString &msg ) +{ + QString str = "CALL QPE/Desktop " + msg; + send ( str ); +} + + +void QCopBridgePI::send( const QString& msg ) +{ + QTextStream os( this ); + os << msg << endl; + //qDebug( "sending qcop message: %s", msg.latin1() ); +} + +void QCopBridgePI::read() +{ + while ( canReadLine() ) + process( readLine().stripWhiteSpace() ); +} + +bool QCopBridgePI::checkUser( const QString& user ) +{ + if ( user.isEmpty() ) return FALSE; + + struct passwd *pw; + pw = getpwuid( geteuid() ); + QString euser = QString::fromLocal8Bit( pw->pw_name ); + return user == euser; +} + +bool QCopBridgePI::checkPassword( const QString& password ) +{ + // ### HACK for testing on local host + return true; + + /* + struct passwd *pw = 0; + struct spwd *spw = 0; + + pw = getpwuid( geteuid() ); + spw = getspnam( pw->pw_name ); + + QString cpwd = QString::fromLocal8Bit( pw->pw_passwd ); + if ( cpwd == "x" && spw ) + cpwd = QString::fromLocal8Bit( spw->sp_pwdp ); + + QString cpassword = QString::fromLocal8Bit( crypt( password.local8Bit(), cpwd.local8Bit() ) ); + return cpwd == cpassword; +*/ +} + +void QCopBridgePI::process( const QString& message ) +{ + //qDebug( "Command: %s", message.latin1() ); + + // split message using "," as separator + QStringList msg = QStringList::split( " ", message ); + if ( msg.isEmpty() ) return; + + // command token + QString cmd = msg[0].upper(); + + // argument token + QString arg; + if ( msg.count() >= 2 ) + arg = msg[1]; + + // we always respond to QUIT, regardless of state + if ( cmd == "QUIT" ) { + send( "211 Have a nice day!" ); + delete this; + return; + } + + // connected to client + if ( Connected == state ) + return; + + // waiting for user name + if ( Wait_USER == state ) { + + if ( cmd != "USER" || msg.count() < 2 || !checkUser( arg ) ) { + send( "530 Please login with USER and PASS" ); + return; + } + send( "331 User name ok, need password" ); + state = Wait_PASS; + return; + } + + // waiting for password + if ( Wait_PASS == state ) { + + if ( cmd != "PASS" || !checkPassword( arg ) ) { + //if ( cmd != "PASS" || msg.count() < 2 || !checkPassword( arg ) ) { + send( "530 Please login with USER and PASS" ); + return; + } + send( "230 User logged in, proceed" ); + state = Ready; + if ( sendSync ) { + sendDesktopMessage( "startSync()" ); + sendSync = FALSE; + } + return; + } + + // noop (NOOP) + else if ( cmd == "NOOP" ) { + connected = TRUE; + send( "200 Command okay" ); + } + + // call (CALL) + else if ( cmd == "CALL" ) { + + // example: call QPE/System execute(QString) addressbook + + if ( msg.count() < 3 ) { + send( "500 Syntax error, command unrecognized" ); + } + else { + + QString channel = msg[1]; + QString command = msg[2]; + + command.stripWhiteSpace(); + + int paren = command.find( "(" ); + if ( paren <= 0 ) { + send( "500 Syntax error, command unrecognized" ); + return; + } + + QString params = command.mid( paren + 1 ); + if ( params[params.length()-1] != ')' ) { + send( "500 Syntax error, command unrecognized" ); + return; + } + + params.truncate( params.length()-1 ); + QByteArray buffer; + QDataStream ds( buffer, IO_WriteOnly ); + + int msgId = 3; + + QStringList paramList = QStringList::split( ",", params ); + if ( paramList.count() > msg.count() - 3 ) { + send( "500 Syntax error, command unrecognized" ); + return; + } + + for ( QStringList::Iterator it = paramList.begin(); it != paramList.end(); ++it ) { + + QString arg = msg[msgId]; + arg.replace( QRegExp("&0x20;"), " " ); + arg.replace( QRegExp("&"), "&" ); + arg.replace( QRegExp("&0x0d;"), "\n" ); + arg.replace( QRegExp("&0x0a;"), "\r" ); + if ( *it == "QString" ) + ds << arg; + else if ( *it == "QCString" ) + ds << arg.local8Bit(); + else if ( *it == "int" ) + ds << arg.toInt(); + else if ( *it == "bool" ) + ds << arg.toInt(); + else { + send( "500 Syntax error, command unrecognized" ); + return; + } + msgId++; + } + + if ( !QCopChannel::isRegistered( channel.latin1() ) ) { + // send message back about it + QString answer = "599 ChannelNotRegistered " + channel; + send( answer ); + return; + } + + if ( paramList.count() ) + QCopChannel::send( channel.latin1(), command.latin1(), buffer ); + else + QCopChannel::send( channel.latin1(), command.latin1() ); + + send( "200 Command okay" ); + } + } + // not implemented + else + send( "502 Command not implemented" ); +} + + + +void QCopBridgePI::timerEvent( QTimerEvent * ) +{ + if ( connected ) + connected = FALSE; + else + connectionClosed(); +} -- cgit v0.9.0.2