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

transferserver.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 #include "transferserver.h"
00021 
00022 /* OPIE */
00023 #include <opie2/odebug.h>
00024 #include <opie2/oglobal.h>
00025 #include <qtopia/qprocess.h>
00026 #include <qtopia/process.h>
00027 #include <qtopia/private/contact.h>
00028 #include <qtopia/version.h>
00029 #ifdef Q_WS_QWS
00030 #include <qtopia/qcopenvelope_qws.h>
00031 #endif
00032 using namespace Opie::Core;
00033 
00034 /* QT */
00035 #include <qtextstream.h>
00036 #include <qmessagebox.h>
00037 
00038 /* STD */
00039 #include <pwd.h>
00040 #include <sys/types.h>
00041 #include <unistd.h>
00042 #include <fcntl.h>
00043 #include <stdlib.h>
00044 #include <time.h>
00045 
00046 #ifndef Q_OS_MACX
00047 #include <shadow.h>
00048 #include <crypt.h>
00049 #endif /* Q_OS_MACX */
00050 
00051 const int block_size = 51200;
00052 
00053 TransferServer::TransferServer( Q_UINT16 port, QObject *parent,
00054         const char* name)
00055     : QServerSocket( port, 1, parent, name )
00056 {
00057     connections.setAutoDelete( TRUE );
00058     if ( !ok() )
00059         owarn << "Failed to bind to port " << port << "" << oendl;
00060     else
00061         ::fcntl( socket(), F_SETFD, FD_CLOEXEC );       
00062 }
00063 
00064 void TransferServer::authorizeConnections()
00065 {
00066     QListIterator<ServerPI> it(connections);
00067     while ( it.current() ) {
00068     if ( !it.current()->verifyAuthorised() ) {
00069         disconnect( it.current(), SIGNAL(connectionClosed(ServerPI*)), this, SLOT( closed(ServerPI*)) );
00070         connections.removeRef( it.current() );
00071     } else
00072         ++it;
00073     }
00074 }
00075 
00076 void TransferServer::closed(ServerPI *item)
00077 {
00078     connections.removeRef(item);
00079 }
00080 
00081 TransferServer::~TransferServer()
00082 {
00083 }
00084 
00085 void TransferServer::newConnection( int socket )
00086 {
00087     ServerPI *ptr = new ServerPI( socket, this );
00088     connect( ptr, SIGNAL(connectionClosed(ServerPI*)), this, SLOT( closed(ServerPI*)) );
00089     connections.append( ptr );
00090 }
00091 
00092 QString SyncAuthentication::serverId()
00093 {
00094     Config cfg("Security");
00095     cfg.setGroup("Sync");
00096     QString r = cfg.readEntry("serverid");
00097 
00098     if ( r.isEmpty() ) {
00099         r = OGlobal::generateUuid();
00100         cfg.writeEntry("serverid", r );
00101     }
00102    return r;
00103 }
00104 
00105 QString SyncAuthentication::ownerName()
00106 {
00107     QString vfilename = Global::applicationFileName("addressbook",
00108                 "businesscard.vcf");
00109     if (QFile::exists(vfilename)) {
00110     Contact c;
00111     c = Contact::readVCard( vfilename )[0];
00112     return c.fullName();
00113     }
00114 
00115     return QString::null;
00116 }
00117 
00118 QString SyncAuthentication::loginName()
00119 {
00120     struct passwd *pw = 0L;
00121 #ifndef Q_OS_WIN32
00122     pw = getpwuid( geteuid() );
00123     return QString::fromLocal8Bit( pw->pw_name );
00124 #else
00125     //### revise
00126     return QString();
00127 #endif
00128 }
00129 
00130 int SyncAuthentication::isAuthorized(QHostAddress peeraddress)
00131 {
00132     Config cfg("Security");
00133     cfg.setGroup("Sync");
00134     //    QString allowedstr = cfg.readEntry("auth_peer","192.168.1.0");
00135     uint auth_peer = cfg.readNumEntry("auth_peer", 0xc0a80100);
00136 
00137     //    QHostAddress allowed;
00138     //    allowed.setAddress(allowedstr);
00139     //    uint auth_peer = allowed.ip4Addr();
00140     uint auth_peer_bits = cfg.readNumEntry("auth_peer_bits", 24);
00141     uint mask = auth_peer_bits >= 32 // shifting by 32 is not defined
00142                 ? 0xffffffff : (((1 << auth_peer_bits) - 1) << (32 - auth_peer_bits));
00143 
00144     return (peeraddress.ip4Addr() & mask) == auth_peer;
00145 }
00146 
00147 bool SyncAuthentication::checkUser( const QString& user )
00148 {
00149     if ( user.isEmpty() ) return FALSE;
00150     QString euser = loginName();
00151     return user == euser;
00152 }
00153 
00154 bool SyncAuthentication::checkPassword( const QString& password )
00155 {
00156 #ifdef ALLOW_UNIX_USER_FTP
00157     // First, check system password...
00158 
00159     struct passwd *pw = 0;
00160     struct spwd *spw = 0;
00161 
00162     pw = getpwuid( geteuid() );
00163     spw = getspnam( pw->pw_name );
00164 
00165     QString cpwd = QString::fromLocal8Bit( pw->pw_passwd );
00166     if ( cpwd == "x" && spw )
00167     cpwd = QString::fromLocal8Bit( spw->sp_pwdp );
00168 
00169     // Note: some systems use more than crypt for passwords.
00170     QString cpassword = QString::fromLocal8Bit( crypt( password.local8Bit(), cpwd.local8Bit() ) );
00171     if ( cpwd == cpassword )
00172     return TRUE;
00173 #endif
00174 
00175     static int lastdenial=0;
00176     static int denials=0;
00177     int now = time(0);
00178 
00179     Config cfg("Security");
00180     cfg.setGroup("SyncMode");
00181     int mode = cfg.readNumEntry("Mode", 0x02 );
00182 
00183     //No pass word needed if the user really needs it
00184     if (mode & 0x04) {
00185         QMessageBox unauth(
00186             tr("Sync Connection"),
00187             tr("<qt><p>An unauthorized system is requesting access to this device."
00188                "<p>You chose IntelliSync so you may I allow or deny this connection.</qt>" ),
00189             QMessageBox::Warning,
00190             QMessageBox::Ok, QMessageBox::Cancel|QMessageBox::Default, QMessageBox::NoButton,
00191             0, QString::null, TRUE, WStyle_StaysOnTop);
00192         unauth.setButtonText(QMessageBox::Ok, tr("Allow" ) );
00193         unauth.setButtonText(QMessageBox::Cancel, tr("Deny"));
00194         switch( unauth.exec() ) {
00195         case QMessageBox::Ok:
00196             return TRUE;
00197             break;
00198         case QMessageBox::Cancel:
00199         default:
00200             denials++;
00201             lastdenial=now;
00202             return FALSE;
00203         }
00204     }
00205 
00206     // Detect old Qtopia Desktop (no password) and fail
00207     if ( password.isEmpty() ) {
00208         if ( denials < 3 || now > lastdenial+600 ) {
00209             QMessageBox unauth(
00210             tr("Sync Connection"),
00211             tr("<p>An unauthorized system is requesting access to this device."
00212                 "<p>If you are using a version of Qtopia Desktop older than 1.5.1, "
00213                 "please upgrade or change the security setting to use IntelliSync." ),
00214             QMessageBox::Warning,
00215             QMessageBox::Cancel, QMessageBox::NoButton, QMessageBox::NoButton,
00216             0, QString::null, TRUE, WStyle_StaysOnTop);
00217             unauth.setButtonText(QMessageBox::Cancel, tr("Deny"));
00218             unauth.exec();
00219 
00220             denials++;
00221             lastdenial=now;
00222          }
00223         return FALSE;
00224 
00225     }
00226 
00227     // Second, check sync password...
00228 
00229     static int lock=0;
00230     if ( lock ) return FALSE;
00231 
00232     ++lock;
00233 
00234     /*
00235      *  we need to support old Sync software and QtopiaDesktop
00236      */
00237     if ( password.left(6) == "Qtopia" || password.left(6) == "rootme" ) {
00238     cfg.setGroup("Sync");
00239     QStringList pwds = cfg.readListEntry("Passwords",' ');
00240     for (QStringList::ConstIterator it=pwds.begin(); it!=pwds.end(); ++it) {
00241 #ifndef Q_OS_WIN32
00242         QString cpassword = QString::fromLocal8Bit(
00243         crypt( password.mid(8).local8Bit(), (*it).left(2).latin1() ) );
00244 #else
00245         // ### revise
00246         QString cpassword("");
00247 #endif
00248         if ( *it == cpassword ) {
00249         lock--;
00250         return TRUE;
00251         }
00252     }
00253 
00254     // Unrecognized system. Be careful...
00255     QMessageBox unrecbox(
00256         tr("Sync Connection"),
00257         tr( "<p>An unrecognized system is requesting access to this device."
00258         "<p>If you have just initiated a Sync for the first time, this is normal."),
00259         QMessageBox::Warning,
00260         QMessageBox::Cancel, QMessageBox::Yes, QMessageBox::NoButton,
00261         0, QString::null, TRUE, WStyle_StaysOnTop);
00262     unrecbox.setButtonText(QMessageBox::Cancel, tr("Deny"));
00263     unrecbox.setButtonText(QMessageBox::Yes, tr("Allow"));
00264 
00265     if ( (denials > 2 && now < lastdenial+600)
00266         || unrecbox.exec() != QMessageBox::Yes)
00267     {
00268         denials++;
00269         lastdenial=now;
00270         lock--;
00271         return FALSE;
00272     } else {
00273         const char salty[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/.";
00274         char salt[2];
00275         salt[0]= salty[rand() % (sizeof(salty)-1)];
00276         salt[1]= salty[rand() % (sizeof(salty)-1)];
00277 #ifndef Q_OS_WIN32
00278         QString cpassword = QString::fromLocal8Bit(
00279         crypt( password.mid(8).local8Bit(), salt ) );
00280 #else
00281         //### revise
00282         QString cpassword("");
00283 #endif
00284         denials=0;
00285         pwds.prepend(cpassword);
00286         cfg.writeEntry("Passwords",pwds,' ');
00287         lock--;
00288         return TRUE;
00289     }
00290     }
00291     lock--;
00292 
00293     return FALSE;
00294 }
00295 
00296 
00297 ServerPI::ServerPI( int socket, QObject *parent, const char* name )
00298     : QSocket( parent, name ) , dtp( 0 ), serversocket( 0 ), waitsocket( 0 ),
00299       storFileSize(-1)
00300 {
00301     state = Connected;
00302 
00303     setSocket( socket );
00304 
00305     peerport = peerPort();
00306     peeraddress = peerAddress();
00307 
00308 #ifndef INSECURE
00309     if ( !SyncAuthentication::isAuthorized(peeraddress) ) {
00310     state = Forbidden;
00311     startTimer( 0 );
00312     } else
00313 #endif
00314     {
00315     connect( this, SIGNAL( readyRead() ), SLOT( read() ) );
00316     connect( this, SIGNAL( connectionClosed() ), SLOT( connectionClosed() ) );
00317 
00318     passiv = FALSE;
00319     for( int i = 0; i < 4; i++ )
00320         wait[i] = FALSE;
00321 
00322     send( "220 Qtopia " QPE_VERSION " FTP Server" ); // No tr
00323     state = Wait_USER;
00324 
00325     dtp = new ServerDTP( this );
00326     connect( dtp, SIGNAL( completed() ), SLOT( dtpCompleted() ) );
00327     connect( dtp, SIGNAL( failed() ), SLOT( dtpFailed() ) );
00328     connect( dtp, SIGNAL( error(int) ), SLOT( dtpError(int) ) );
00329 
00330 
00331     directory = QDir::currentDirPath();
00332 
00333     static int p = 1024;
00334 
00335     while ( !serversocket || !serversocket->ok() ) {
00336         delete serversocket;
00337         serversocket = new ServerSocket( ++p, this );
00338     }
00339     connect( serversocket, SIGNAL( newIncomming(int) ),
00340          SLOT( newConnection(int) ) );
00341     }
00342 }
00343 
00344 ServerPI::~ServerPI()
00345 {
00346     close();
00347 
00348     if ( dtp )
00349         dtp->close();
00350     delete dtp;
00351     delete serversocket;
00352 }
00353 
00354 bool ServerPI::verifyAuthorised()
00355 {
00356     if ( !SyncAuthentication::isAuthorized(peerAddress()) ) {
00357     state = Forbidden;
00358     return FALSE;
00359     }
00360     return TRUE;
00361 }
00362 
00363 void ServerPI::connectionClosed()
00364 {
00365     // odebug << "Debug: Connection closed" << oendl;
00366     emit connectionClosed(this);
00367 }
00368 
00369 void ServerPI::send( const QString& msg )
00370 {
00371     QTextStream os( this );
00372     os << msg << endl;
00373     //odebug << "Reply: " << msg << "" << oendl;
00374 }
00375 
00376 void ServerPI::read()
00377 {
00378     while ( canReadLine() )
00379     process( readLine().stripWhiteSpace() );
00380 }
00381 
00382 bool ServerPI::checkReadFile( const QString& file )
00383 {
00384     QString filename;
00385     
00386     if ( file.length() == 1 && file[0] == "/" )
00387     filename = file;
00388     else if ( file[0] != "/" ) 
00389     filename = directory.path() + "/" + file;
00390     else
00391     filename = file;
00392 
00393     QFileInfo fi( filename );
00394     return ( fi.exists() && fi.isReadable() );
00395 }
00396 
00397 bool ServerPI::checkWriteFile( const QString& file )
00398 {
00399     QString filename;
00400 
00401     if ( file[0] != "/" )
00402     filename = directory.path() + "/" + file;
00403     else
00404     filename = file;
00405 
00406     QFileInfo fi( filename );
00407 
00408     if ( fi.exists() )
00409     if ( !QFile( filename ).remove() )
00410         return FALSE;
00411     return TRUE;
00412 }
00413 
00414 void ServerPI::process( const QString& message )
00415 {
00416     //odebug << "Command: " << message << "" << oendl;
00417 
00418     // split message using "," as separator
00419     QStringList msg = QStringList::split( " ", message );
00420     if ( msg.isEmpty() ) return;
00421 
00422     // command token
00423     QString cmd = msg[0].upper();
00424 
00425     // argument token
00426     QString arg;
00427     if ( msg.count() >= 2 )
00428     arg = msg[1];
00429 
00430     // full argument string
00431     QString args;
00432     if ( msg.count() >= 2 ) {
00433         QStringList copy( msg );
00434         // FIXME: for Qt3
00435         // copy.pop_front()
00436         copy.remove( copy.begin() );
00437         args = copy.join( " " );
00438     }
00439 
00440     //odebug << "args: " << args << "" << oendl;
00441 
00442     // we always respond to QUIT, regardless of state
00443     if ( cmd == "QUIT" ) {
00444     send( "211 Good bye!" ); // No tr
00445     close();
00446     return;
00447     }
00448 
00449     // connected to client
00450     if ( Connected == state )
00451     return;
00452 
00453     // waiting for user name
00454     if ( Wait_USER == state ) {
00455 
00456     if ( cmd != "USER" || msg.count() < 2 || !SyncAuthentication::checkUser( arg ) ) {
00457         send( "530 Please login with USER and PASS" ); // No tr
00458         return;
00459     }
00460     send( "331 User name ok, need password" ); // No tr
00461     state = Wait_PASS;
00462     return;
00463     }
00464 
00465     // waiting for password
00466     if ( Wait_PASS == state ) {
00467 
00468     if ( cmd != "PASS" || !SyncAuthentication::checkPassword( arg ) ) {
00469         send( "530 Please login with USER and PASS" ); // No tr
00470         return;
00471     }
00472     send( "230 User logged in, proceed" ); // No tr
00473     state = Ready;
00474     return;
00475     }
00476 
00477     // ACCESS CONTROL COMMANDS
00478 
00479     // Only an ALLO sent immediately before STOR is valid.
00480     if ( cmd != "STOR" )
00481     storFileSize = -1;
00482 
00483     // account (ACCT)
00484     if ( cmd == "ACCT" ) {
00485     // even wu-ftp does not support it
00486     send( "502 Command not implemented" ); // No tr
00487     }
00488 
00489     // change working directory (CWD)
00490     else if ( cmd == "CWD" ) {
00491 
00492     if ( !args.isEmpty() ) {
00493         if ( directory.cd( args, TRUE ) )
00494         send( "250 Requested file action okay, completed" ); // No tr
00495         else
00496         send( "550 Requested action not taken" ); // No tr
00497     }
00498     else
00499         send( "500 Syntax error, command unrecognized" ); // No tr
00500     }
00501 
00502     // change to parent directory (CDUP)
00503     else if ( cmd == "CDUP" ) {
00504     if ( directory.cdUp() )
00505         send( "250 Requested file action okay, completed" ); // No tr
00506     else
00507         send( "550 Requested action not taken" ); // No tr
00508     }
00509 
00510     // structure mount (SMNT)
00511     else if ( cmd == "SMNT" ) {
00512     // even wu-ftp does not support it
00513     send( "502 Command not implemented" ); // No tr
00514     }
00515 
00516     // reinitialize (REIN)
00517     else if ( cmd == "REIN" ) {
00518     // even wu-ftp does not support it
00519     send( "502 Command not implemented" ); // No tr
00520     }
00521 
00522 
00523     // TRANSFER PARAMETER COMMANDS
00524 
00525 
00526     // data port (PORT)
00527     else if ( cmd == "PORT" ) {
00528     if ( parsePort( arg ) )
00529         send( "200 Command okay" ); // No tr
00530     else
00531         send( "500 Syntax error, command unrecognized" ); // No tr
00532     }
00533 
00534     // passive (PASV)
00535     else if ( cmd == "PASV" ) {
00536     passiv = TRUE;
00537     send( "227 Entering Passive Mode (" // No tr
00538           + address().toString().replace( QRegExp( "\\." ), "," ) + ","
00539           + QString::number( ( serversocket->port() ) >> 8 ) + ","
00540           + QString::number( ( serversocket->port() ) & 0xFF ) +")" );
00541     }
00542 
00543     // representation type (TYPE)
00544     else if ( cmd == "TYPE" ) {
00545     if ( arg.upper() == "A" || arg.upper() == "I" )
00546         send( "200 Command okay" ); // No tr
00547     else
00548         send( "504 Command not implemented for that parameter" ); // No tr
00549     }
00550 
00551     // file structure (STRU)
00552     else if ( cmd == "STRU" ) {
00553     if ( arg.upper() == "F" )
00554         send( "200 Command okay" ); // No tr
00555     else
00556         send( "504 Command not implemented for that parameter" ); // No tr
00557     }
00558 
00559     // transfer mode (MODE)
00560     else if ( cmd == "MODE" ) {
00561     if ( arg.upper() == "S" )
00562         send( "200 Command okay" ); // No tr
00563     else
00564         send( "504 Command not implemented for that parameter" ); // No tr
00565     }
00566 
00567 
00568     // FTP SERVICE COMMANDS
00569 
00570 
00571     // retrieve (RETR)
00572     else if ( cmd == "RETR" )
00573     if ( !args.isEmpty() && checkReadFile( absFilePath( args ) )
00574          || backupRestoreGzip( absFilePath( args ) ) ) {
00575         send( "150 File status okay" ); // No tr
00576         sendFile( absFilePath( args ) );
00577     }
00578     else {
00579         odebug << "550 Requested action not taken" << oendl;
00580         send( "550 Requested action not taken" ); // No tr
00581     }
00582 
00583     // store (STOR)
00584     else if ( cmd == "STOR" )
00585     if ( !args.isEmpty() && checkWriteFile( absFilePath( args ) ) ) {
00586         send( "150 File status okay" ); // No tr
00587         retrieveFile( absFilePath( args ) );
00588     }
00589     else
00590         send( "550 Requested action not taken" ); // No tr
00591 
00592     // store unique (STOU)
00593     else if ( cmd == "STOU" ) {
00594     send( "502 Command not implemented" ); // No tr
00595     }
00596 
00597     // append (APPE)
00598     else if ( cmd == "APPE" ) {
00599     send( "502 Command not implemented" ); // No tr
00600     }
00601 
00602     // allocate (ALLO)
00603     else if ( cmd == "ALLO" ) {
00604     storFileSize = args.toInt();
00605     send( "200 Command okay" ); // No tr
00606     }
00607 
00608     // restart (REST)
00609     else if ( cmd == "REST" ) {
00610     send( "502 Command not implemented" ); // No tr
00611     }
00612 
00613     // rename from (RNFR)
00614     else if ( cmd == "RNFR" ) {
00615     renameFrom = QString::null;
00616     if ( args.isEmpty() )
00617         send( "500 Syntax error, command unrecognized" ); // No tr
00618     else {
00619         QFile file( absFilePath( args ) );
00620         if ( file.exists() ) {
00621         send( "350 File exists, ready for destination name" ); // No tr
00622         renameFrom = absFilePath( args );
00623         }
00624         else
00625         send( "550 Requested action not taken" ); // No tr
00626     }
00627     }
00628 
00629     // rename to (RNTO)
00630     else if ( cmd == "RNTO" ) {
00631     if ( lastCommand != "RNFR" )
00632         send( "503 Bad sequence of commands" ); // No tr
00633     else if ( args.isEmpty() )
00634         send( "500 Syntax error, command unrecognized" ); // No tr
00635     else {
00636         QDir dir( absFilePath( args ) );
00637         if ( dir.rename( renameFrom, absFilePath( args ), TRUE ) )
00638         send( "250 Requested file action okay, completed." ); // No tr
00639         else
00640         send( "550 Requested action not taken" ); // No tr
00641     }
00642     }
00643 
00644     // abort (ABOR)
00645     else if ( cmd.contains( "ABOR" ) ) {
00646     dtp->close();
00647     if ( dtp->dtpMode() != ServerDTP::Idle )
00648         send( "426 Connection closed; transfer aborted" ); // No tr
00649     else
00650         send( "226 Closing data connection" ); // No tr
00651     }
00652 
00653     // delete (DELE)
00654     else if ( cmd == "DELE" ) {
00655     if ( args.isEmpty() )
00656         send( "500 Syntax error, command unrecognized" ); // No tr
00657     else {
00658         QFile file( absFilePath( args ) ) ;
00659         if ( file.remove() ) {
00660         send( "250 Requested file action okay, completed" ); // No tr
00661         QCopEnvelope e("QPE/System", "linkChanged(QString)" );
00662         e << file.name();
00663         } else {
00664         send( "550 Requested action not taken" ); // No tr
00665         }
00666     }
00667     }
00668 
00669     // remove directory (RMD)
00670     else if ( cmd == "RMD" ) {
00671     if ( args.isEmpty() )
00672         send( "500 Syntax error, command unrecognized" ); // No tr
00673     else {
00674         QDir dir;
00675         if ( dir.rmdir( absFilePath( args ), TRUE ) )
00676         send( "250 Requested file action okay, completed" ); // No tr
00677         else
00678         send( "550 Requested action not taken" ); // No tr
00679     }
00680     }
00681 
00682     // make directory (MKD)
00683     else if ( cmd == "MKD" ) {
00684     if ( args.isEmpty() ) {
00685         odebug << " Error: no arg" << oendl;
00686         send( "500 Syntax error, command unrecognized" ); // No tr
00687     }
00688     else {
00689         QDir dir;
00690         if ( dir.mkdir( absFilePath( args ), TRUE ) )
00691         send( "250 Requested file action okay, completed." ); // No tr
00692         else
00693         send( "550 Requested action not taken" ); // No tr
00694     }
00695     }
00696 
00697     // print working directory (PWD)
00698     else if ( cmd == "PWD" ) {
00699     send( "257 \"" + directory.path() +"\"" );
00700     }
00701 
00702     // list (LIST)
00703     else if ( cmd == "LIST" ) {
00704     if ( args == "-la" )
00705         args = QString::null;
00706     
00707     if ( sendList( absFilePath( args ) ) )
00708         send( "150 File status okay" ); // No tr
00709     else
00710         send( "500 Syntax error, command unrecognized" ); // No tr
00711     }
00712 
00713     // size (SIZE)
00714     else if ( cmd == "SIZE" ) {
00715     QString filePath = absFilePath( args );
00716     QFileInfo fi( filePath );
00717     bool gzipfile = backupRestoreGzip( filePath );
00718     if ( !fi.exists() && !gzipfile )
00719         send( "500 Syntax error, command unrecognized" ); // No tr
00720     else {
00721         if ( !gzipfile )
00722         send( "213 " + QString::number( fi.size() ) );
00723         else {
00724         Process duproc( QString("du") );
00725         duproc.addArgument("-s");
00726         QString in, out;
00727         if ( !duproc.exec(in, out) ) {
00728             odebug << "du process failed; just sending back 1K" << oendl;
00729             send( "213 1024");
00730         }
00731         else {
00732             QString size = out.left( out.find("\t") );
00733             int guess = size.toInt()/5;
00734             if ( filePath.contains("doc") ) // No tr
00735             guess *= 1000;
00736             odebug << "sending back gzip guess of " << guess << "" << oendl;
00737             send( "213 " + QString::number(guess) );
00738         }
00739         }
00740     }
00741     }
00742     // name list (NLST)
00743     else if ( cmd == "NLST" ) {
00744     send( "502 Command not implemented" ); // No tr
00745     }
00746 
00747     // site parameters (SITE)
00748     else if ( cmd == "SITE" ) {
00749     send( "502 Command not implemented" ); // No tr
00750     }
00751 
00752     // system (SYST)
00753     else if ( cmd == "SYST" ) {
00754     send( "215 UNIX Type: L8" ); // No tr
00755     }
00756 
00757     // status (STAT)
00758     else if ( cmd == "STAT" ) {
00759     send( "502 Command not implemented" ); // No tr
00760     }
00761 
00762     // help (HELP )
00763     else if ( cmd == "HELP" ) {
00764     send( "502 Command not implemented" ); // No tr
00765     }
00766 
00767     // noop (NOOP)
00768     else if ( cmd == "NOOP" ) {
00769     send( "200 Command okay" ); // No tr
00770     }
00771 
00772     // not implemented
00773     else
00774     send( "502 Command not implemented" ); // No tr
00775 
00776     lastCommand = cmd;
00777 }
00778 
00779 bool ServerPI::backupRestoreGzip( const QString &file )
00780 {
00781     return (file.find( "backup" ) != -1 && // No tr
00782         file.findRev( ".tgz" ) == (int)file.length()-4 );
00783 }
00784 
00785 bool ServerPI::backupRestoreGzip( const QString &file, QStringList &targets )
00786 {
00787   if ( file.find( "backup" ) != -1 && // No tr
00788        file.findRev( ".tgz" ) == (int)file.length()-4 ) {
00789       QFileInfo info( file );
00790       targets = info.dirPath( TRUE );
00791       odebug << "ServerPI::backupRestoreGzip for " << file.latin1() << " = " << targets.join(" ").latin1() << oendl;
00792       return true;
00793   }
00794   return false;
00795 }
00796 
00797 void ServerPI::sendFile( const QString& file )
00798 {
00799     if ( passiv ) {
00800     wait[SendFile] = TRUE;
00801     waitfile = file;
00802     if ( waitsocket )
00803         newConnection( waitsocket );
00804     }
00805     else {
00806       QStringList targets;
00807       if ( backupRestoreGzip( file, targets ) )
00808       dtp->sendGzipFile( file, targets, peeraddress, peerport );
00809       else dtp->sendFile( file, peeraddress, peerport );
00810     }
00811 }
00812 
00813 void ServerPI::retrieveFile( const QString& file )
00814 {
00815     if ( passiv ) {
00816     wait[RetrieveFile] = TRUE;
00817     waitfile = file;
00818     if ( waitsocket )
00819         newConnection( waitsocket );
00820     }
00821     else {
00822       QStringList targets;
00823       if ( backupRestoreGzip( file, targets ) )
00824     dtp->retrieveGzipFile( file, peeraddress, peerport );
00825       else
00826     dtp->retrieveFile( file, peeraddress, peerport, storFileSize );
00827     }
00828 }
00829 
00830 bool ServerPI::parsePort( const QString& pp )
00831 {
00832     QStringList p = QStringList::split( ",", pp );
00833     if ( p.count() != 6 ) return FALSE;
00834 
00835     // h1,h2,h3,h4,p1,p2
00836     peeraddress = QHostAddress( ( p[0].toInt() << 24 ) + ( p[1].toInt() << 16 ) +
00837                 ( p[2].toInt() << 8 ) + p[3].toInt() );
00838     peerport = ( p[4].toInt() << 8 ) + p[5].toInt();
00839     return TRUE;
00840 }
00841 
00842 void ServerPI::dtpCompleted()
00843 {
00844     send( "226 Closing data connection, file transfer successful" ); // No tr
00845     if ( dtp->dtpMode() == ServerDTP::RetrieveFile ) {
00846     QString fn = dtp->fileName();
00847     if ( fn.right(8)==".desktop" && fn.find("/Documents/")>=0 ) {
00848         QCopEnvelope e("QPE/System", "linkChanged(QString)" );
00849         e << fn;
00850     }
00851     }
00852     waitsocket = 0;
00853     dtp->close();
00854     storFileSize = -1;
00855 }
00856 
00857 void ServerPI::dtpFailed()
00858 {
00859     dtp->close();
00860     waitsocket = 0;
00861     send( "451 Requested action aborted: local error in processing" ); // No tr
00862     storFileSize = -1;
00863 }
00864 
00865 void ServerPI::dtpError( int )
00866 {
00867     dtp->close();
00868     waitsocket = 0;
00869     send( "451 Requested action aborted: local error in processing" ); // No tr
00870     storFileSize = -1;
00871 }
00872 
00873 bool ServerPI::sendList( const QString& arg )
00874 {
00875     QByteArray listing;
00876     QBuffer buffer( listing );
00877 
00878     if ( !buffer.open( IO_WriteOnly ) )
00879     return FALSE;
00880 
00881     QTextStream ts( &buffer );
00882     QString fn = arg;
00883 
00884     if ( fn.isEmpty() )
00885     fn = directory.path();
00886 
00887     QFileInfo fi( fn );
00888     if ( !fi.exists() ) return FALSE;
00889 
00890     // return file listing
00891     if ( fi.isFile() ) {
00892     ts << fileListing( &fi ) << endl;
00893     }
00894 
00895     // return directory listing
00896     else if ( fi.isDir() ) {
00897     QDir dir( fn );
00898     const QFileInfoList *list = dir.entryInfoList( QDir::All | QDir::Hidden );
00899 
00900     QFileInfoListIterator it( *list );
00901     QFileInfo *info;
00902 
00903     unsigned long total = 0;
00904     while ( ( info = it.current() ) ) {
00905         if ( info->fileName() != "." && info->fileName() != ".." )
00906         total += info->size();
00907         ++it;
00908     }
00909 
00910     ts << "total " << QString::number( total / 1024 ) << endl; // No tr
00911 
00912     it.toFirst();
00913     while ( ( info = it.current() ) ) {
00914         if ( info->fileName() == "." || info->fileName() == ".." ) {
00915         ++it;
00916         continue;
00917         }
00918         ts << fileListing( info ) << endl;
00919         ++it;
00920     }
00921     }
00922 
00923     if ( passiv ) {
00924     waitarray = buffer.buffer();
00925     wait[SendByteArray] = TRUE;
00926     if ( waitsocket )
00927         newConnection( waitsocket );
00928     }
00929     else
00930     dtp->sendByteArray( buffer.buffer(), peeraddress, peerport );
00931     return TRUE;
00932 }
00933 
00934 QString ServerPI::fileListing( QFileInfo *info )
00935 {
00936     if ( !info ) return QString::null;
00937     QString s;
00938 
00939     // type char
00940     if ( info->isDir() )
00941     s += "d";
00942     else if ( info->isSymLink() )
00943     s += "l";
00944     else
00945     s += "-";
00946 
00947     // permisson string
00948     s += permissionString( info ) + " ";
00949 
00950     // number of hardlinks
00951     int subdirs = 1;
00952 
00953     if ( info->isDir() )
00954     subdirs = 2;
00955     // FIXME : this is to slow
00956     //if ( info->isDir() )
00957     //subdirs = QDir( info->absFilePath() ).entryList( QDir::Dirs ).count();
00958 
00959     s += QString::number( subdirs ).rightJustify( 3, ' ', TRUE ) + " ";
00960 
00961     // owner
00962     QString o = info->owner();
00963     if ( o.isEmpty() )
00964     o = QString::number(info->ownerId());
00965     s += o.leftJustify( 8, ' ', TRUE ) + " ";
00966 
00967     // group
00968     QString g = info->group();
00969     if ( g.isEmpty() )
00970     g = QString::number(info->groupId());
00971     s += g.leftJustify( 8, ' ', TRUE ) + " ";
00972 
00973     // file size in bytes
00974     s += QString::number( info->size() ).rightJustify( 9, ' ', TRUE ) + " ";
00975 
00976     // last modified date
00977     QDate date = info->lastModified().date();
00978     QTime time = info->lastModified().time();
00979     s += date.monthName( date.month() ) + " "
00980      + QString::number( date.day() ).rightJustify( 2, ' ', TRUE ) + " "
00981      + QString::number( time.hour() ).rightJustify( 2, '0', TRUE ) + ":"
00982      + QString::number( time.minute() ).rightJustify( 2,'0', TRUE ) + " ";
00983 
00984     // file name
00985     s += info->fileName();
00986 
00987     return s;
00988 }
00989 
00990 QString ServerPI::permissionString( QFileInfo *info )
00991 {
00992     if ( !info ) return QString( "---------" );
00993     QString s;
00994 
00995     // user
00996     if ( info->permission( QFileInfo::ReadUser ) ) s += "r";
00997     else s += "-";
00998     if ( info->permission( QFileInfo::WriteUser ) ) s += "w";
00999     else s += "-";
01000     if ( info->permission( QFileInfo::ExeUser ) ) s += "x";
01001     else s += "-";
01002 
01003     // group
01004     if ( info->permission( QFileInfo::ReadGroup ) ) s += "r";
01005     else s += "-";
01006     if ( info->permission( QFileInfo::WriteGroup ) )s += "w";
01007     else s += "-";
01008     if ( info->permission( QFileInfo::ExeGroup ) ) s += "x";
01009     else s += "-";
01010 
01011     // exec
01012     if ( info->permission( QFileInfo::ReadOther ) ) s += "r";
01013     else s += "-";
01014     if ( info->permission( QFileInfo::WriteOther ) ) s += "w";
01015     else s += "-";
01016     if ( info->permission( QFileInfo::ExeOther ) ) s += "x";
01017     else s += "-";
01018 
01019     return s;
01020 }
01021 
01022 void ServerPI::newConnection( int socket )
01023 {
01024     //odebug << "New incomming connection" << oendl;
01025 
01026     if ( !passiv ) return;
01027 
01028     if ( wait[SendFile] ) {
01029     QStringList targets;
01030     if ( backupRestoreGzip( waitfile, targets ) )
01031         dtp->sendGzipFile( waitfile, targets );
01032     else
01033         dtp->sendFile( waitfile );
01034     dtp->setSocket( socket );
01035     }
01036     else if ( wait[RetrieveFile] ) {
01037       odebug << "check retrieve file" << oendl;
01038       if ( backupRestoreGzip( waitfile ) )
01039     dtp->retrieveGzipFile( waitfile );
01040       else
01041     dtp->retrieveFile( waitfile, storFileSize );
01042       dtp->setSocket( socket );
01043     }
01044     else if ( wait[SendByteArray] ) {
01045     dtp->sendByteArray( waitarray );
01046     dtp->setSocket( socket );
01047     }
01048     else if ( wait[RetrieveByteArray] ) {
01049     odebug << "retrieve byte array" << oendl;
01050     dtp->retrieveByteArray();
01051     dtp->setSocket( socket );
01052     }
01053     else
01054     waitsocket = socket;
01055 
01056     for( int i = 0; i < 4; i++ )
01057     wait[i] = FALSE;
01058 }
01059 
01060 QString ServerPI::absFilePath( const QString& file )
01061 {
01062     if ( file.isEmpty() ) return file;
01063 
01064     QString filepath( file );
01065     if ( file[0] != "/" )
01066     filepath = directory.path() + "/" + file;
01067 
01068     return filepath;
01069 }
01070 
01071 
01072 void ServerPI::timerEvent( QTimerEvent * )
01073 {
01074     connectionClosed();
01075 }
01076 
01077 
01078 ServerDTP::ServerDTP( QObject *parent, const char* name)
01079   : QSocket( parent, name ), mode( Idle ), createTargzProc( 0 ),
01080     retrieveTargzProc( 0 )
01081 {
01082 
01083   connect( this, SIGNAL( connected() ), SLOT( connected() ) );
01084   connect( this, SIGNAL( connectionClosed() ), SLOT( connectionClosed() ) );
01085   connect( this, SIGNAL( bytesWritten(int) ), SLOT( bytesWritten(int) ) );
01086   connect( this, SIGNAL( readyRead() ), SLOT( readyRead() ) );
01087 
01088   createTargzProc = new QProcess( QString("tar"), this, "createTargzProc"); // No tr
01089   createTargzProc->setCommunication( QProcess::Stdout );
01090   createTargzProc->setWorkingDirectory( QDir::rootDirPath() );
01091   connect( createTargzProc, SIGNAL( processExited() ), SLOT( targzDone() ) );
01092 
01093   retrieveTargzProc = new QProcess( this, "retrieveTargzProc" );
01094   retrieveTargzProc->setCommunication( QProcess::Stdin );
01095   retrieveTargzProc->setWorkingDirectory( QDir::rootDirPath() );
01096   connect( retrieveTargzProc, SIGNAL( processExited() ),
01097        SIGNAL( completed() ) );
01098   connect( retrieveTargzProc, SIGNAL( processExited() ),
01099        SLOT( extractTarDone() ) );
01100 }
01101 
01102 ServerDTP::~ServerDTP()
01103 {
01104     buf.close();
01105     if ( RetrieveFile == mode && file.isOpen() ) {
01106     // We're being shutdown before the client closed.
01107     file.close();
01108     if ( recvFileSize >= 0 && (int)file.size() != recvFileSize ) {
01109         odebug << "STOR incomplete" << oendl;
01110         file.remove();
01111     }
01112     } else {
01113     file.close();
01114     }
01115     createTargzProc->kill();
01116 }
01117 
01118 void ServerDTP::extractTarDone()
01119 {
01120     odebug << "extract done" << oendl;
01121 #ifndef QT_NO_COP
01122     QCopEnvelope e( "QPE/System", "restoreDone(QString)" );
01123     e << file.name();
01124 #endif
01125 }
01126 
01127 void ServerDTP::connected()
01128 {
01129   // send file mode
01130   switch ( mode ) {
01131   case SendFile :
01132     if ( !file.exists() || !file.open( IO_ReadOnly) ) {
01133       emit failed();
01134       mode = Idle;
01135       return;
01136     }
01137 
01138     //odebug << "Debug: Sending file '" << file.name() << "'" << oendl;
01139 
01140     bytes_written = 0;
01141     if ( file.size() == 0 ) {
01142       //make sure it doesn't hang on empty files
01143       file.close();
01144       emit completed();
01145       mode = Idle;
01146     } else {
01147       // Don't write more if there is plenty buffered already.
01148       if ( bytesToWrite() <= block_size && !file.atEnd() ) {
01149     QCString s;
01150     s.resize( block_size );
01151     int bytes = file.readBlock( s.data(), block_size );
01152     writeBlock( s.data(), bytes );
01153       }
01154     }
01155     break;
01156   case SendGzipFile:
01157     if ( createTargzProc->isRunning() ) {
01158       // SHOULDN'T GET HERE, BUT DOING A SAFETY CHECK ANYWAY
01159       owarn << "Previous tar --gzip process is still running; killing it..." << oendl;
01160       createTargzProc->kill();
01161     }
01162 
01163     bytes_written = 0;
01164     odebug << "==>start send tar process" << oendl;
01165     if ( !createTargzProc->start() )
01166       owarn << "Error starting " << createTargzProc->arguments().join(" ").latin1() << oendl;
01167     break;
01168   case SendBuffer:
01169     if ( !buf.open( IO_ReadOnly) ) {
01170       emit failed();
01171       mode = Idle;
01172       return;
01173     }
01174 
01175     // odebug << "Debug: Sending byte array" << oendl;
01176     bytes_written = 0;
01177     while( !buf.atEnd() )
01178       putch( buf.getch() );
01179     buf.close();
01180     break;
01181   case RetrieveFile:
01182     // retrieve file mode
01183     if ( file.exists() && !file.remove() ) {
01184       emit failed();
01185       mode = Idle;
01186       return;
01187     }
01188 
01189     if ( !file.open( IO_WriteOnly) ) {
01190       emit failed();
01191       mode = Idle;
01192       return;
01193     }
01194     // odebug << "Debug: Retrieving file " << file.name() << "" << oendl;
01195     break;
01196   case RetrieveGzipFile:
01197     odebug << "=-> starting tar process to receive .tgz file" << oendl;
01198     break;
01199   case RetrieveBuffer:
01200     // retrieve buffer mode
01201     if ( !buf.open( IO_WriteOnly) ) {
01202       emit failed();
01203       mode = Idle;
01204       return;
01205     }
01206     // odebug << "Debug: Retrieving byte array" << oendl;
01207     break;
01208   case Idle:
01209     odebug << "connection established but mode set to Idle; BUG!" << oendl;
01210     break;
01211   }
01212 }
01213 
01214 void ServerDTP::connectionClosed()
01215 {
01216     //odebug << "Debug: Data connection closed " << bytes_written << " bytes written" << oendl;
01217 
01218     // send file mode
01219     if ( SendFile == mode ) {
01220     if ( bytes_written == file.size() )
01221         emit completed();
01222     else
01223         emit failed();
01224     }
01225 
01226     // send buffer mode
01227     else if ( SendBuffer == mode ) {
01228     if ( bytes_written == buf.size() )
01229         emit completed();
01230     else
01231         emit failed();
01232     }
01233 
01234     // retrieve file mode
01235     else if ( RetrieveFile == mode ) {
01236     file.close();
01237     if ( recvFileSize >= 0 && (int)file.size() != recvFileSize ) {
01238         odebug << "STOR incomplete" << oendl;
01239         file.remove();
01240         emit failed();
01241     } else {
01242         emit completed();
01243     }
01244     }
01245 
01246     else if ( RetrieveGzipFile == mode ) {
01247     odebug << "Done writing ungzip file; closing input" << oendl;
01248     retrieveTargzProc->flushStdin();
01249     retrieveTargzProc->closeStdin();
01250     }
01251 
01252     // retrieve buffer mode
01253     else if ( RetrieveBuffer == mode ) {
01254     buf.close();
01255     emit completed();
01256     }
01257 
01258     mode = Idle;
01259 }
01260 
01261 void ServerDTP::bytesWritten( int bytes )
01262 {
01263     bytes_written += bytes;
01264 
01265     // send file mode
01266     if ( SendFile == mode ) {
01267 
01268     if ( bytes_written == file.size() ) {
01269         // odebug << "Debug: Sending complete: " << file.size() << " bytes" << oendl;
01270         file.close();
01271         emit completed();
01272         mode = Idle;
01273     }
01274     else if( !file.atEnd() ) {
01275         QCString s;
01276         s.resize( block_size );
01277         int bytes = file.readBlock( s.data(), block_size );
01278         writeBlock( s.data(), bytes );
01279     }
01280     }
01281 
01282     // send buffer mode
01283     if ( SendBuffer == mode ) {
01284 
01285     if ( bytes_written == buf.size() ) {
01286         // odebug << "Debug: Sending complete: " << buf.size() << " bytes" << oendl;
01287         emit completed();
01288         mode = Idle;
01289     }
01290     }
01291 }
01292 
01293 void ServerDTP::readyRead()
01294 {
01295     // retrieve file mode
01296     if ( RetrieveFile == mode ) {
01297     QCString s;
01298     s.resize( bytesAvailable() );
01299     readBlock( s.data(), bytesAvailable() );
01300     file.writeBlock( s.data(), s.size() );
01301     }
01302     else if ( RetrieveGzipFile == mode ) {
01303     if ( !retrieveTargzProc->isRunning() )
01304         retrieveTargzProc->start();
01305 
01306         QByteArray s;
01307     s.resize( bytesAvailable() );
01308     readBlock( s.data(), bytesAvailable() );
01309     retrieveTargzProc->writeToStdin( s );
01310     odebug << "wrote " << s.size() << " bytes to ungzip " << oendl;
01311     }
01312     // retrieve buffer mode
01313     else if ( RetrieveBuffer == mode ) {
01314     QCString s;
01315     s.resize( bytesAvailable() );
01316     readBlock( s.data(), bytesAvailable() );
01317     buf.writeBlock( s.data(), s.size() );
01318     }
01319 }
01320 
01321 void ServerDTP::writeTargzBlock()
01322 {
01323     QByteArray block = createTargzProc->readStdout();
01324     writeBlock( block.data(), block.size() );
01325     odebug << "writeTargzBlock " << block.size() << "" << oendl;
01326 }
01327 
01328 void ServerDTP::targzDone()
01329 {
01330     odebug << "tar and gzip done" << oendl;
01331     emit completed();
01332     mode = Idle;
01333     disconnect( createTargzProc, SIGNAL( readyReadStdout() ),
01334             this, SLOT( writeTargzBlock() ) );
01335 }
01336 
01337 void ServerDTP::sendFile( const QString fn, const QHostAddress& host, Q_UINT16 port )
01338 {
01339     file.setName( fn );
01340     mode = SendFile;
01341     connectToHost( host.toString(), port );
01342 }
01343 
01344 void ServerDTP::sendFile( const QString fn )
01345 {
01346     file.setName( fn );
01347     mode = SendFile;
01348 }
01349 
01350 void ServerDTP::sendGzipFile( const QString &fn,
01351                   const QStringList &archiveTargets,
01352                   const QHostAddress& host, Q_UINT16 port )
01353 {
01354     sendGzipFile( fn, archiveTargets );
01355     connectToHost( host.toString(), port );
01356 }
01357 
01358 void ServerDTP::sendGzipFile( const QString &fn,
01359                   const QStringList &archiveTargets  )
01360 {
01361     mode = SendGzipFile;
01362     file.setName( fn );
01363 
01364     QStringList args = "targzip";
01365     //args += "-cv";
01366     args += archiveTargets;
01367     odebug << "sendGzipFile " << args.join(" ") << "" << oendl;
01368     createTargzProc->setArguments( args );
01369     connect( createTargzProc,
01370          SIGNAL( readyReadStdout() ), SLOT( writeTargzBlock() ) );
01371 }
01372 
01373 void ServerDTP::retrieveFile( const QString fn, const QHostAddress& host, Q_UINT16 port, int fileSize )
01374 {
01375     recvFileSize = fileSize;
01376     file.setName( fn );
01377     mode = RetrieveFile;
01378     connectToHost( host.toString(), port );
01379 }
01380 
01381 void ServerDTP::retrieveFile( const QString fn, int fileSize )
01382 {
01383     recvFileSize = fileSize;
01384     file.setName( fn );
01385     mode = RetrieveFile;
01386 }
01387 
01388 void ServerDTP::retrieveGzipFile( const QString &fn )
01389 {
01390     odebug << "retrieveGzipFile " << fn << "" << oendl;
01391     file.setName( fn );
01392     mode = RetrieveGzipFile;
01393 
01394     retrieveTargzProc->setArguments( "targunzip" );
01395     connect( retrieveTargzProc, SIGNAL( processExited() ),
01396          SLOT( extractTarDone() ) );
01397 }
01398 
01399 void ServerDTP::retrieveGzipFile( const QString &fn, const QHostAddress& host, Q_UINT16 port )
01400 {
01401     retrieveGzipFile( fn );
01402     connectToHost( host.toString(), port );
01403 }
01404 
01405 void ServerDTP::sendByteArray( const QByteArray& array, const QHostAddress& host, Q_UINT16 port )
01406 {
01407     buf.setBuffer( array );
01408     mode = SendBuffer;
01409     connectToHost( host.toString(), port );
01410 }
01411 
01412 void ServerDTP::sendByteArray( const QByteArray& array )
01413 {
01414     buf.setBuffer( array );
01415     mode = SendBuffer;
01416 }
01417 
01418 void ServerDTP::retrieveByteArray( const QHostAddress& host, Q_UINT16 port )
01419 {
01420     buf.setBuffer( QByteArray() );
01421     mode = RetrieveBuffer;
01422     connectToHost( host.toString(), port );
01423 }
01424 
01425 void ServerDTP::retrieveByteArray()
01426 {
01427     buf.setBuffer( QByteArray() );
01428     mode = RetrieveBuffer;
01429 }
01430 
01431 void ServerDTP::setSocket( int socket )
01432 {
01433     QSocket::setSocket( socket );
01434     connected();
01435 }
01436 

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