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