summaryrefslogtreecommitdiff
path: root/core/launcher/transferserver.cpp
authorkergoth <kergoth>2002-01-25 22:14:26 (UTC)
committer kergoth <kergoth>2002-01-25 22:14:26 (UTC)
commit15318cad33835e4e2dc620d033e43cd930676cdd (patch) (unidiff)
treec2fa0399a2c47fda8e2cd0092c73a809d17f68eb /core/launcher/transferserver.cpp
downloadopie-15318cad33835e4e2dc620d033e43cd930676cdd.zip
opie-15318cad33835e4e2dc620d033e43cd930676cdd.tar.gz
opie-15318cad33835e4e2dc620d033e43cd930676cdd.tar.bz2
Initial revision
Diffstat (limited to 'core/launcher/transferserver.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--core/launcher/transferserver.cpp1245
1 files changed, 1245 insertions, 0 deletions
diff --git a/core/launcher/transferserver.cpp b/core/launcher/transferserver.cpp
new file mode 100644
index 0000000..87a49eb
--- a/dev/null
+++ b/core/launcher/transferserver.cpp
@@ -0,0 +1,1245 @@
1/**********************************************************************
2** Copyright (C) 2000 Trolltech AS. All rights reserved.
3**
4** This file is part of Qtopia Environment.
5**
6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file.
10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13**
14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15**
16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you.
18**
19**********************************************************************/
20#define _XOPEN_SOURCE
21#include <pwd.h>
22#include <sys/types.h>
23#include <unistd.h>
24#include <stdlib.h>
25
26#if defined(_OS_LINUX_)
27#include <shadow.h>
28#endif
29
30#include <qdir.h>
31#include <qfile.h>
32#include <qtextstream.h>
33#include <qdatastream.h>
34#include <qmessagebox.h>
35#include <qstringlist.h>
36#include <qfileinfo.h>
37#include <qregexp.h>
38//#include <qpe/qcopchannel_qws.h>
39#include <qpe/qprocess.h>
40#include <qpe/process.h>
41#include <qpe/config.h>
42#include <qpe/qcopenvelope_qws.h>
43
44#include "transferserver.h"
45
46const int block_size = 51200;
47
48TransferServer::TransferServer( Q_UINT16 port, QObject *parent = 0,
49 const char* name = 0)
50 : QServerSocket( port, 1, parent, name )
51{
52 if ( !ok() )
53 qWarning( "Failed to bind to port %d", port );
54}
55
56TransferServer::~TransferServer()
57{
58
59}
60
61void TransferServer::newConnection( int socket )
62{
63 (void) new ServerPI( socket, this );
64}
65
66bool accessAuthorized(QHostAddress peeraddress)
67{
68 Config cfg("Security");
69 cfg.setGroup("Sync");
70 uint auth_peer = cfg.readNumEntry("auth_peer",0xc0a80100);
71 uint auth_peer_bits = cfg.readNumEntry("auth_peer_bits",24);
72 bool ok = (peeraddress.ip4Addr() & (((1<<auth_peer_bits)-1)<<(32-auth_peer_bits)))
73 == auth_peer;
74 /* Allows denial-of-service attack.
75 if ( !ok ) {
76 QMessageBox::warning(0,tr("Security"),
77 tr("<p>An attempt to access this device from %1 has been denied.")
78 .arg(peeraddress.toString()));
79 }
80 */
81 return ok;
82}
83
84ServerPI::ServerPI( int socket, QObject *parent = 0, const char* name = 0 )
85 : QSocket( parent, name ) , dtp( 0 ), serversocket( 0 ), waitsocket( 0 )
86{
87 state = Connected;
88
89 setSocket( socket );
90
91 peerport = peerPort();
92 peeraddress = peerAddress();
93
94#ifndef INSECURE
95 if ( !accessAuthorized(peeraddress) ) {
96 state = Forbidden;
97 startTimer( 0 );
98 } else
99 #endif
100 {
101 connect( this, SIGNAL( readyRead() ), SLOT( read() ) );
102 connect( this, SIGNAL( connectionClosed() ), SLOT( connectionClosed() ) );
103
104 passiv = FALSE;
105 for( int i = 0; i < 4; i++ )
106 wait[i] = FALSE;
107
108 send( "220 Qtopia transfer service ready!" );
109 state = Wait_USER;
110
111 dtp = new ServerDTP( this );
112 connect( dtp, SIGNAL( completed() ), SLOT( dtpCompleted() ) );
113 connect( dtp, SIGNAL( failed() ), SLOT( dtpFailed() ) );
114 connect( dtp, SIGNAL( error( int ) ), SLOT( dtpError( int ) ) );
115
116
117 directory = QDir::currentDirPath();
118
119 static int p = 1024;
120
121 while ( !serversocket || !serversocket->ok() ) {
122 delete serversocket;
123 serversocket = new ServerSocket( ++p, this );
124 }
125 connect( serversocket, SIGNAL( newIncomming( int ) ),
126 SLOT( newConnection( int ) ) );
127 }
128}
129
130ServerPI::~ServerPI()
131{
132
133}
134
135void ServerPI::connectionClosed()
136{
137 // qDebug( "Debug: Connection closed" );
138 delete this;
139}
140
141void ServerPI::send( const QString& msg )
142{
143 QTextStream os( this );
144 os << msg << endl;
145 //qDebug( "Reply: %s", msg.latin1() );
146}
147
148void ServerPI::read()
149{
150 while ( canReadLine() )
151 process( readLine().stripWhiteSpace() );
152}
153
154bool ServerPI::checkUser( const QString& user )
155{
156 if ( user.isEmpty() ) return FALSE;
157
158 struct passwd *pw;
159 pw = getpwuid( geteuid() );
160 QString euser = QString::fromLocal8Bit( pw->pw_name );
161 return user == euser;
162}
163
164bool ServerPI::checkPassword( const QString& /* password */ )
165{
166 // ### HACK for testing on local host
167 return true;
168
169 /*
170 struct passwd *pw = 0;
171 struct spwd *spw = 0;
172
173 pw = getpwuid( geteuid() );
174 spw = getspnam( pw->pw_name );
175
176 QString cpwd = QString::fromLocal8Bit( pw->pw_passwd );
177 if ( cpwd == "x" && spw )
178 cpwd = QString::fromLocal8Bit( spw->sp_pwdp );
179
180 QString cpassword = QString::fromLocal8Bit( crypt( password.local8Bit(), cpwd.local8Bit() ) );
181 return cpwd == cpassword;
182*/
183}
184
185bool ServerPI::checkReadFile( const QString& file )
186{
187 QString filename;
188
189 if ( file[0] != "/" )
190 filename = directory.path() + "/" + file;
191 else
192 filename = file;
193
194 QFileInfo fi( filename );
195 return ( fi.exists() && fi.isReadable() );
196}
197
198bool ServerPI::checkWriteFile( const QString& file )
199{
200 QString filename;
201
202 if ( file[0] != "/" )
203 filename = directory.path() + "/" + file;
204 else
205 filename = file;
206
207 QFileInfo fi( filename );
208
209 if ( fi.exists() )
210 if ( !QFile( filename ).remove() )
211 return FALSE;
212 return TRUE;
213}
214
215void ServerPI::process( const QString& message )
216{
217 //qDebug( "Command: %s", message.latin1() );
218
219 // split message using "," as separator
220 QStringList msg = QStringList::split( " ", message );
221 if ( msg.isEmpty() ) return;
222
223 // command token
224 QString cmd = msg[0].upper();
225
226 // argument token
227 QString arg;
228 if ( msg.count() >= 2 )
229 arg = msg[1];
230
231 // full argument string
232 QString args;
233 if ( msg.count() >= 2 ) {
234 QStringList copy( msg );
235 // FIXME: for Qt3
236 // copy.pop_front()
237 copy.remove( copy.begin() );
238 args = copy.join( " " );
239 }
240
241 //qDebug( "args: %s", args.latin1() );
242
243 // we always respond to QUIT, regardless of state
244 if ( cmd == "QUIT" ) {
245 send( "211 Good bye!" );
246 delete this;
247 return;
248 }
249
250 // connected to client
251 if ( Connected == state )
252 return;
253
254 // waiting for user name
255 if ( Wait_USER == state ) {
256
257 if ( cmd != "USER" || msg.count() < 2 || !checkUser( arg ) ) {
258 send( "530 Please login with USER and PASS" );
259 return;
260 }
261 send( "331 User name ok, need password" );
262 state = Wait_PASS;
263 return;
264 }
265
266 // waiting for password
267 if ( Wait_PASS == state ) {
268
269 if ( cmd != "PASS" || !checkPassword( arg ) ) {
270 //if ( cmd != "PASS" || msg.count() < 2 || !checkPassword( arg ) ) {
271 send( "530 Please login with USER and PASS" );
272 return;
273 }
274 send( "230 User logged in, proceed" );
275 state = Ready;
276 return;
277 }
278
279 // ACCESS CONTROL COMMANDS
280
281
282 // account (ACCT)
283 if ( cmd == "ACCT" ) {
284 // even wu-ftp does not support it
285 send( "502 Command not implemented" );
286 }
287
288 // change working directory (CWD)
289 else if ( cmd == "CWD" ) {
290
291 if ( !args.isEmpty() ) {
292 if ( directory.cd( args, TRUE ) )
293 send( "250 Requested file action okay, completed" );
294 else
295 send( "550 Requested action not taken" );
296 }
297 else
298 send( "500 Syntax error, command unrecognized" );
299 }
300
301 // change to parent directory (CDUP)
302 else if ( cmd == "CDUP" ) {
303 if ( directory.cdUp() )
304 send( "250 Requested file action okay, completed" );
305 else
306 send( "550 Requested action not taken" );
307 }
308
309 // structure mount (SMNT)
310 else if ( cmd == "SMNT" ) {
311 // even wu-ftp does not support it
312 send( "502 Command not implemented" );
313 }
314
315 // reinitialize (REIN)
316 else if ( cmd == "REIN" ) {
317 // even wu-ftp does not support it
318 send( "502 Command not implemented" );
319 }
320
321
322 // TRANSFER PARAMETER COMMANDS
323
324
325 // data port (PORT)
326 else if ( cmd == "PORT" ) {
327 if ( parsePort( arg ) )
328 send( "200 Command okay" );
329 else
330 send( "500 Syntax error, command unrecognized" );
331 }
332
333 // passive (PASV)
334 else if ( cmd == "PASV" ) {
335 passiv = TRUE;
336 send( "227 Entering Passive Mode ("
337 + address().toString().replace( QRegExp( "\\." ), "," ) + ","
338 + QString::number( ( serversocket->port() ) >> 8 ) + ","
339 + QString::number( ( serversocket->port() ) & 0xFF ) +")" );
340 }
341
342 // representation type (TYPE)
343 else if ( cmd == "TYPE" ) {
344 if ( arg.upper() == "A" || arg.upper() == "I" )
345 send( "200 Command okay" );
346 else
347 send( "504 Command not implemented for that parameter" );
348 }
349
350 // file structure (STRU)
351 else if ( cmd == "STRU" ) {
352 if ( arg.upper() == "F" )
353 send( "200 Command okay" );
354 else
355 send( "504 Command not implemented for that parameter" );
356 }
357
358 // transfer mode (MODE)
359 else if ( cmd == "MODE" ) {
360 if ( arg.upper() == "S" )
361 send( "200 Command okay" );
362 else
363 send( "504 Command not implemented for that parameter" );
364 }
365
366
367 // FTP SERVICE COMMANDS
368
369
370 // retrieve (RETR)
371 else if ( cmd == "RETR" )
372 if ( !args.isEmpty() && checkReadFile( absFilePath( args ) )
373 || backupRestoreGzip( absFilePath( args ) ) ) {
374 send( "150 File status okay" );
375 sendFile( absFilePath( args ) );
376 }
377 else {
378 qDebug("550 Requested action not taken");
379 send( "550 Requested action not taken" );
380 }
381
382 // store (STOR)
383 else if ( cmd == "STOR" )
384 if ( !args.isEmpty() && checkWriteFile( absFilePath( args ) ) ) {
385 send( "150 File status okay" );
386 retrieveFile( absFilePath( args ) );
387 }
388 else
389 send( "550 Requested action not taken" );
390
391 // store unique (STOU)
392 else if ( cmd == "STOU" ) {
393 send( "502 Command not implemented" );
394 }
395
396 // append (APPE)
397 else if ( cmd == "APPE" ) {
398 send( "502 Command not implemented" );
399 }
400
401 // allocate (ALLO)
402 else if ( cmd == "ALLO" ) {
403 send( "200 Command okay" );
404 }
405
406 // restart (REST)
407 else if ( cmd == "REST" ) {
408 send( "502 Command not implemented" );
409 }
410
411 // rename from (RNFR)
412 else if ( cmd == "RNFR" ) {
413 renameFrom = QString::null;
414 if ( args.isEmpty() )
415 send( "500 Syntax error, command unrecognized" );
416 else {
417 QFile file( absFilePath( args ) );
418 if ( file.exists() ) {
419 send( "350 File exists, ready for destination name" );
420 renameFrom = absFilePath( args );
421 }
422 else
423 send( "550 Requested action not taken" );
424 }
425 }
426
427 // rename to (RNTO)
428 else if ( cmd == "RNTO" ) {
429 if ( lastCommand != "RNFR" )
430 send( "503 Bad sequence of commands" );
431 else if ( args.isEmpty() )
432 send( "500 Syntax error, command unrecognized" );
433 else {
434 QDir dir( absFilePath( args ) );
435 if ( dir.rename( renameFrom, absFilePath( args ), TRUE ) )
436 send( "250 Requested file action okay, completed." );
437 else
438 send( "550 Requested action not taken" );
439 }
440 }
441
442 // abort (ABOR)
443 else if ( cmd.contains( "ABOR" ) ) {
444 dtp->close();
445 if ( dtp->dtpMode() != ServerDTP::Idle )
446 send( "426 Connection closed; transfer aborted" );
447 else
448 send( "226 Closing data connection" );
449 }
450
451 // delete (DELE)
452 else if ( cmd == "DELE" ) {
453 if ( args.isEmpty() )
454 send( "500 Syntax error, command unrecognized" );
455 else {
456 QFile file( absFilePath( args ) ) ;
457 if ( file.remove() )
458 send( "250 Requested file action okay, completed" );
459 else
460 send( "550 Requested action not taken" );
461 }
462 }
463
464 // remove directory (RMD)
465 else if ( cmd == "RMD" ) {
466 if ( args.isEmpty() )
467 send( "500 Syntax error, command unrecognized" );
468 else {
469 QDir dir;
470 if ( dir.rmdir( absFilePath( args ), TRUE ) )
471 send( "250 Requested file action okay, completed" );
472 else
473 send( "550 Requested action not taken" );
474 }
475 }
476
477 // make directory (MKD)
478 else if ( cmd == "MKD" ) {
479 if ( args.isEmpty() ) {
480 qDebug(" Error: no arg");
481 send( "500 Syntax error, command unrecognized" );
482 }
483 else {
484 QDir dir;
485 if ( dir.mkdir( absFilePath( args ), TRUE ) )
486 send( "250 Requested file action okay, completed." );
487 else
488 send( "550 Requested action not taken" );
489 }
490 }
491
492 // print working directory (PWD)
493 else if ( cmd == "PWD" ) {
494 send( "257 \"" + directory.path() +"\"" );
495 }
496
497 // list (LIST)
498 else if ( cmd == "LIST" ) {
499 if ( sendList( absFilePath( args ) ) )
500 send( "150 File status okay" );
501 else
502 send( "500 Syntax error, command unrecognized" );
503 }
504
505 // size (SIZE)
506 else if ( cmd == "SIZE" ) {
507 QString filePath = absFilePath( args );
508 QFileInfo fi( filePath );
509 bool gzipfile = backupRestoreGzip( filePath );
510 if ( !fi.exists() && !gzipfile )
511 send( "500 Syntax error, command unrecognized" );
512 else {
513 if ( !gzipfile )
514 send( "213 " + QString::number( fi.size() ) );
515 else {
516 Process duproc( QString("du") );
517 duproc.addArgument("-s");
518 QString in, out;
519 if ( !duproc.exec(in, out) ) {
520 qDebug("du process failed; just sending back 1K");
521 send( "213 1024");
522 }
523 else {
524 QString size = out.left( out.find("\t") );
525 int guess = size.toInt()/5;
526 if ( filePath.contains("doc") )
527 guess *= 1000;
528 qDebug("sending back gzip guess of %d", guess);
529 send( "213 " + QString::number(guess) );
530 }
531 }
532 }
533 }
534 // name list (NLST)
535 else if ( cmd == "NLST" ) {
536 send( "502 Command not implemented" );
537 }
538
539 // site parameters (SITE)
540 else if ( cmd == "SITE" ) {
541 send( "502 Command not implemented" );
542 }
543
544 // system (SYST)
545 else if ( cmd == "SYST" ) {
546 send( "215 UNIX Type: L8" );
547 }
548
549 // status (STAT)
550 else if ( cmd == "STAT" ) {
551 send( "502 Command not implemented" );
552 }
553
554 // help (HELP )
555 else if ( cmd == "HELP" ) {
556 send( "502 Command not implemented" );
557 }
558
559 // noop (NOOP)
560 else if ( cmd == "NOOP" ) {
561 send( "200 Command okay" );
562 }
563
564 // not implemented
565 else
566 send( "502 Command not implemented" );
567
568 lastCommand = cmd;
569}
570
571bool ServerPI::backupRestoreGzip( const QString &file )
572{
573 return (file.find( "backup" ) != -1 &&
574 file.findRev( ".tgz" ) == (int)file.length()-4 );
575}
576
577bool ServerPI::backupRestoreGzip( const QString &file, QStringList &targets )
578{
579 if ( file.find( "backup" ) != -1 &&
580 file.findRev( ".tgz" ) == (int)file.length()-4 ) {
581 QFileInfo info( file );
582 targets = info.dirPath( TRUE );
583 qDebug("ServerPI::backupRestoreGzip for %s = %s", file.latin1(),
584 targets.join(" ").latin1() );
585 return true;
586 }
587 return false;
588}
589
590void ServerPI::sendFile( const QString& file )
591{
592 if ( passiv ) {
593 wait[SendFile] = TRUE;
594 waitfile = file;
595 if ( waitsocket )
596 newConnection( waitsocket );
597 }
598 else {
599 QStringList targets;
600 if ( backupRestoreGzip( file, targets ) )
601 dtp->sendGzipFile( file, targets, peeraddress, peerport );
602 else dtp->sendFile( file, peeraddress, peerport );
603 }
604}
605
606void ServerPI::retrieveFile( const QString& file )
607{
608 if ( passiv ) {
609 wait[RetrieveFile] = TRUE;
610 waitfile = file;
611 if ( waitsocket )
612 newConnection( waitsocket );
613 }
614 else {
615 QStringList targets;
616 if ( backupRestoreGzip( file, targets ) )
617 dtp->retrieveGzipFile( file, peeraddress, peerport );
618 else
619 dtp->retrieveFile( file, peeraddress, peerport );
620 }
621}
622
623bool ServerPI::parsePort( const QString& pp )
624{
625 QStringList p = QStringList::split( ",", pp );
626 if ( p.count() != 6 ) return FALSE;
627
628 // h1,h2,h3,h4,p1,p2
629 peeraddress = QHostAddress( ( p[0].toInt() << 24 ) + ( p[1].toInt() << 16 ) +
630 ( p[2].toInt() << 8 ) + p[3].toInt() );
631 peerport = ( p[4].toInt() << 8 ) + p[5].toInt();
632 return TRUE;
633}
634
635void ServerPI::dtpCompleted()
636{
637 dtp->close();
638 waitsocket = 0;
639 send( "226 Closing data connection, file transfer successful" );
640}
641
642void ServerPI::dtpFailed()
643{
644 dtp->close();
645 waitsocket = 0;
646 send( "451 Requested action aborted: local error in processing" );
647}
648
649void ServerPI::dtpError( int )
650{
651 dtp->close();
652 waitsocket = 0;
653 send( "451 Requested action aborted: local error in processing" );
654}
655
656bool ServerPI::sendList( const QString& arg )
657{
658 QByteArray listing;
659 QBuffer buffer( listing );
660
661 if ( !buffer.open( IO_WriteOnly ) )
662 return FALSE;
663
664 QTextStream ts( &buffer );
665 QString fn = arg;
666
667 if ( fn.isEmpty() )
668 fn = directory.path();
669
670 QFileInfo fi( fn );
671 if ( !fi.exists() ) return FALSE;
672
673 // return file listing
674 if ( fi.isFile() ) {
675 ts << fileListing( &fi ) << endl;
676 }
677
678 // return directory listing
679 else if ( fi.isDir() ) {
680 QDir dir( fn );
681 const QFileInfoList *list = dir.entryInfoList( QDir::All | QDir::Hidden );
682
683 QFileInfoListIterator it( *list );
684 QFileInfo *info;
685
686 unsigned long total = 0;
687 while ( ( info = it.current() ) ) {
688 if ( info->fileName() != "." && info->fileName() != ".." )
689 total += info->size();
690 ++it;
691 }
692
693 ts << "total " << QString::number( total / 1024 ) << endl;
694
695 it.toFirst();
696 while ( ( info = it.current() ) ) {
697 if ( info->fileName() == "." || info->fileName() == ".." ) {
698 ++it;
699 continue;
700 }
701 ts << fileListing( info ) << endl;
702 ++it;
703 }
704 }
705
706 if ( passiv ) {
707 waitarray = buffer.buffer();
708 wait[SendByteArray] = TRUE;
709 if ( waitsocket )
710 newConnection( waitsocket );
711 }
712 else
713 dtp->sendByteArray( buffer.buffer(), peeraddress, peerport );
714 return TRUE;
715}
716
717QString ServerPI::fileListing( QFileInfo *info )
718{
719 if ( !info ) return QString::null;
720 QString s;
721
722 // type char
723 if ( info->isDir() )
724 s += "d";
725 else if ( info->isSymLink() )
726 s += "l";
727 else
728 s += "-";
729
730 // permisson string
731 s += permissionString( info ) + " ";
732
733 // number of hardlinks
734 int subdirs = 1;
735
736 if ( info->isDir() )
737 subdirs = 2;
738 // FIXME : this is to slow
739 //if ( info->isDir() )
740 //subdirs = QDir( info->absFilePath() ).entryList( QDir::Dirs ).count();
741
742 s += QString::number( subdirs ).rightJustify( 3, ' ', TRUE ) + " ";
743
744 // owner
745 s += info->owner().leftJustify( 8, ' ', TRUE ) + " ";
746
747 // group
748 s += info->group().leftJustify( 8, ' ', TRUE ) + " ";
749
750 // file size in bytes
751 s += QString::number( info->size() ).rightJustify( 9, ' ', TRUE ) + " ";
752
753 // last modified date
754 QDate date = info->lastModified().date();
755 QTime time = info->lastModified().time();
756 s += date.monthName( date.month() ) + " "
757 + QString::number( date.day() ).rightJustify( 2, ' ', TRUE ) + " "
758 + QString::number( time.hour() ).rightJustify( 2, '0', TRUE ) + ":"
759 + QString::number( time.minute() ).rightJustify( 2,'0', TRUE ) + " ";
760
761 // file name
762 s += info->fileName();
763
764 return s;
765}
766
767QString ServerPI::permissionString( QFileInfo *info )
768{
769 if ( !info ) return QString( "---------" );
770 QString s;
771
772 // user
773 if ( info->permission( QFileInfo::ReadUser ) ) s += "r";
774 else s += "-";
775 if ( info->permission( QFileInfo::WriteUser ) ) s += "w";
776 else s += "-";
777 if ( info->permission( QFileInfo::ExeUser ) ) s += "x";
778 else s += "-";
779
780 // group
781 if ( info->permission( QFileInfo::ReadGroup ) ) s += "r";
782 else s += "-";
783 if ( info->permission( QFileInfo::WriteGroup ) )s += "w";
784 else s += "-";
785 if ( info->permission( QFileInfo::ExeGroup ) ) s += "x";
786 else s += "-";
787
788 // exec
789 if ( info->permission( QFileInfo::ReadOther ) ) s += "r";
790 else s += "-";
791 if ( info->permission( QFileInfo::WriteOther ) ) s += "w";
792 else s += "-";
793 if ( info->permission( QFileInfo::ExeOther ) ) s += "x";
794 else s += "-";
795
796 return s;
797}
798
799void ServerPI::newConnection( int socket )
800{
801 //qDebug( "New incomming connection" );
802
803 if ( !passiv ) return;
804
805 if ( wait[SendFile] ) {
806 QStringList targets;
807 if ( backupRestoreGzip( waitfile, targets ) )
808 dtp->sendGzipFile( waitfile, targets );
809 else
810 dtp->sendFile( waitfile );
811 dtp->setSocket( socket );
812 }
813 else if ( wait[RetrieveFile] ) {
814 qDebug("check retrieve file");
815 if ( backupRestoreGzip( waitfile ) )
816 dtp->retrieveGzipFile( waitfile );
817 else
818 dtp->retrieveFile( waitfile );
819 dtp->setSocket( socket );
820 }
821 else if ( wait[SendByteArray] ) {
822 dtp->sendByteArray( waitarray );
823 dtp->setSocket( socket );
824 }
825 else if ( wait[RetrieveByteArray] ) {
826 qDebug("retrieve byte array");
827 dtp->retrieveByteArray();
828 dtp->setSocket( socket );
829 }
830 else
831 waitsocket = socket;
832
833 for( int i = 0; i < 4; i++ )
834 wait[i] = FALSE;
835}
836
837QString ServerPI::absFilePath( const QString& file )
838{
839 if ( file.isEmpty() ) return file;
840
841 QString filepath( file );
842 if ( file[0] != "/" )
843 filepath = directory.path() + "/" + file;
844
845 return filepath;
846}
847
848
849void ServerPI::timerEvent( QTimerEvent * )
850{
851 connectionClosed();
852}
853
854
855ServerDTP::ServerDTP( QObject *parent = 0, const char* name = 0)
856 : QSocket( parent, name ), mode( Idle ), createTargzProc( 0 ),
857retrieveTargzProc( 0 ), gzipProc( 0 )
858{
859
860 connect( this, SIGNAL( connected() ), SLOT( connected() ) );
861 connect( this, SIGNAL( connectionClosed() ), SLOT( connectionClosed() ) );
862 connect( this, SIGNAL( bytesWritten( int ) ), SLOT( bytesWritten( int ) ) );
863 connect( this, SIGNAL( readyRead() ), SLOT( readyRead() ) );
864
865 gzipProc = new QProcess( this, "gzipProc" );
866 gzipProc->setCommunication( QProcess::Stdin | QProcess::Stdout );
867
868 createTargzProc = new QProcess( QString("tar"), this, "createTargzProc");
869 createTargzProc->setCommunication( QProcess::Stdout );
870 createTargzProc->setWorkingDirectory( QDir::rootDirPath() );
871 connect( createTargzProc, SIGNAL( processExited() ), SLOT( targzDone() ) );
872
873 QStringList args = "tar";
874 args += "-xv";
875 retrieveTargzProc = new QProcess( args, this, "retrieveTargzProc" );
876 retrieveTargzProc->setCommunication( QProcess::Stdin );
877 retrieveTargzProc->setWorkingDirectory( QDir::rootDirPath() );
878 connect( retrieveTargzProc, SIGNAL( processExited() ),
879 SIGNAL( completed() ) );
880 connect( retrieveTargzProc, SIGNAL( processExited() ),
881 SLOT( extractTarDone() ) );
882}
883
884ServerDTP::~ServerDTP()
885{
886 buf.close();
887 file.close();
888 createTargzProc->kill();
889}
890
891void ServerDTP::extractTarDone()
892{
893 qDebug("extract done");
894 QCopEnvelope e( "QPE/Desktop", "restoreDone(QString)" );
895 e << file.name();
896}
897
898void ServerDTP::connected()
899{
900 // send file mode
901 switch ( mode ) {
902 case SendFile :
903 if ( !file.exists() || !file.open( IO_ReadOnly) ) {
904 emit failed();
905 mode = Idle;
906 return;
907 }
908
909 //qDebug( "Debug: Sending file '%s'", file.name().latin1() );
910
911 bytes_written = 0;
912 if ( file.size() == 0 ) {
913 //make sure it doesn't hang on empty files
914 file.close();
915 emit completed();
916 mode = Idle;
917 } else {
918
919 if( !file.atEnd() ) {
920 QCString s;
921 s.resize( block_size );
922 int bytes = file.readBlock( s.data(), block_size );
923 writeBlock( s.data(), bytes );
924 }
925 }
926 break;
927 case SendGzipFile:
928 if ( createTargzProc->isRunning() ) {
929 // SHOULDN'T GET HERE, BUT DOING A SAFETY CHECK ANYWAY
930 qWarning("Previous tar --gzip process is still running; killing it...");
931 createTargzProc->kill();
932 }
933
934 bytes_written = 0;
935 qDebug("==>start send tar process");
936 if ( !createTargzProc->start() )
937 qWarning("Error starting %s or %s",
938 createTargzProc->arguments().join(" ").latin1(),
939 gzipProc->arguments().join(" ").latin1() );
940 break;
941 case SendBuffer:
942 if ( !buf.open( IO_ReadOnly) ) {
943 emit failed();
944 mode = Idle;
945 return;
946 }
947
948 // qDebug( "Debug: Sending byte array" );
949 bytes_written = 0;
950 while( !buf.atEnd() )
951 putch( buf.getch() );
952 buf.close();
953 break;
954 case RetrieveFile:
955 // retrieve file mode
956 if ( file.exists() && !file.remove() ) {
957 emit failed();
958 mode = Idle;
959 return;
960 }
961
962 if ( !file.open( IO_WriteOnly) ) {
963 emit failed();
964 mode = Idle;
965 return;
966 }
967 // qDebug( "Debug: Retrieving file %s", file.name().latin1() );
968 break;
969 case RetrieveGzipFile:
970 qDebug("=-> starting tar process to receive .tgz file");
971 break;
972 case RetrieveBuffer:
973 // retrieve buffer mode
974 if ( !buf.open( IO_WriteOnly) ) {
975 emit failed();
976 mode = Idle;
977 return;
978 }
979 // qDebug( "Debug: Retrieving byte array" );
980 break;
981 case Idle:
982 qDebug("connection established but mode set to Idle; BUG!");
983 break;
984 }
985}
986
987void ServerDTP::connectionClosed()
988{
989 //qDebug( "Debug: Data connection closed %ld bytes written", bytes_written );
990
991 // send file mode
992 if ( SendFile == mode ) {
993 if ( bytes_written == file.size() )
994 emit completed();
995 else
996 emit failed();
997 }
998
999 // send buffer mode
1000 else if ( SendBuffer == mode ) {
1001 if ( bytes_written == buf.size() )
1002 emit completed();
1003 else
1004 emit failed();
1005 }
1006
1007 // retrieve file mode
1008 else if ( RetrieveFile == mode ) {
1009 file.close();
1010 emit completed();
1011 }
1012
1013 else if ( RetrieveGzipFile == mode ) {
1014 qDebug("Done writing ungzip file; closing input");
1015 gzipProc->flushStdin();
1016 gzipProc->closeStdin();
1017 }
1018
1019 // retrieve buffer mode
1020 else if ( RetrieveBuffer == mode ) {
1021 buf.close();
1022 emit completed();
1023 }
1024
1025 mode = Idle;
1026}
1027
1028void ServerDTP::bytesWritten( int bytes )
1029{
1030 bytes_written += bytes;
1031
1032 // send file mode
1033 if ( SendFile == mode ) {
1034
1035 if ( bytes_written == file.size() ) {
1036 // qDebug( "Debug: Sending complete: %d bytes", file.size() );
1037 file.close();
1038 emit completed();
1039 mode = Idle;
1040 }
1041 else if( !file.atEnd() ) {
1042 QCString s;
1043 s.resize( block_size );
1044 int bytes = file.readBlock( s.data(), block_size );
1045 writeBlock( s.data(), bytes );
1046 }
1047 }
1048
1049 // send buffer mode
1050 if ( SendBuffer == mode ) {
1051
1052 if ( bytes_written == buf.size() ) {
1053 // qDebug( "Debug: Sending complete: %d bytes", buf.size() );
1054 emit completed();
1055 mode = Idle;
1056 }
1057 }
1058}
1059
1060void ServerDTP::readyRead()
1061{
1062 // retrieve file mode
1063 if ( RetrieveFile == mode ) {
1064 QCString s;
1065 s.resize( bytesAvailable() );
1066 readBlock( s.data(), bytesAvailable() );
1067 file.writeBlock( s.data(), s.size() );
1068 }
1069 else if ( RetrieveGzipFile == mode ) {
1070 if ( !gzipProc->isRunning() )
1071 gzipProc->start();
1072
1073 QByteArray s;
1074 s.resize( bytesAvailable() );
1075 readBlock( s.data(), bytesAvailable() );
1076 gzipProc->writeToStdin( s );
1077 qDebug("wrote %d bytes to ungzip ", s.size() );
1078 }
1079 // retrieve buffer mode
1080 else if ( RetrieveBuffer == mode ) {
1081 QCString s;
1082 s.resize( bytesAvailable() );
1083 readBlock( s.data(), bytesAvailable() );
1084 buf.writeBlock( s.data(), s.size() );
1085 }
1086}
1087
1088void ServerDTP::writeTargzBlock()
1089{
1090 QByteArray block = gzipProc->readStdout();
1091 writeBlock( block.data(), block.size() );
1092 qDebug("writeTargzBlock %d", block.size());
1093 if ( !createTargzProc->isRunning() ) {
1094 qDebug("tar and gzip done");
1095 emit completed();
1096 mode = Idle;
1097 disconnect( gzipProc, SIGNAL( readyReadStdout() ),
1098 this, SLOT( writeTargzBlock() ) );
1099 }
1100}
1101
1102void ServerDTP::targzDone()
1103{
1104 //qDebug("targz done");
1105 disconnect( createTargzProc, SIGNAL( readyReadStdout() ),
1106 this, SLOT( gzipTarBlock() ) );
1107 gzipProc->closeStdin();
1108}
1109
1110void ServerDTP::gzipTarBlock()
1111{
1112 //qDebug("gzipTarBlock");
1113 if ( !gzipProc->isRunning() ) {
1114 //qDebug("auto start gzip proc");
1115 gzipProc->start();
1116 }
1117 gzipProc->writeToStdin( createTargzProc->readStdout() );
1118}
1119
1120void ServerDTP::sendFile( const QString fn, const QHostAddress& host, Q_UINT16 port )
1121{
1122 file.setName( fn );
1123 mode = SendFile;
1124 connectToHost( host.toString(), port );
1125}
1126
1127void ServerDTP::sendFile( const QString fn )
1128{
1129 file.setName( fn );
1130 mode = SendFile;
1131}
1132
1133void ServerDTP::sendGzipFile( const QString &fn,
1134 const QStringList &archiveTargets,
1135 const QHostAddress& host, Q_UINT16 port )
1136{
1137 sendGzipFile( fn, archiveTargets );
1138 connectToHost( host.toString(), port );
1139}
1140
1141void ServerDTP::sendGzipFile( const QString &fn,
1142 const QStringList &archiveTargets )
1143{
1144 mode = SendGzipFile;
1145 file.setName( fn );
1146
1147 QStringList args = "tar";
1148 args += "-cv";
1149 args += archiveTargets;
1150 qDebug("sendGzipFile %s", args.join(" ").latin1() );
1151 createTargzProc->setArguments( args );
1152 connect( createTargzProc,
1153 SIGNAL( readyReadStdout() ), SLOT( gzipTarBlock() ) );
1154
1155 gzipProc->setArguments( "gzip" );
1156 connect( gzipProc, SIGNAL( readyReadStdout() ),
1157 SLOT( writeTargzBlock() ) );
1158}
1159
1160void ServerDTP::gunzipDone()
1161{
1162 qDebug("gunzipDone");
1163 disconnect( gzipProc, SIGNAL( processExited() ),
1164 this, SLOT( gunzipDone() ) );
1165 retrieveTargzProc->closeStdin();
1166 disconnect( gzipProc, SIGNAL( readyReadStdout() ),
1167 this, SLOT( tarExtractBlock() ) );
1168}
1169
1170void ServerDTP::tarExtractBlock()
1171{
1172 qDebug("ungzipTarBlock");
1173 if ( !retrieveTargzProc->isRunning() ) {
1174 qDebug("auto start ungzip proc");
1175 if ( !retrieveTargzProc->start() )
1176 qWarning(" failed to start tar -x process");
1177 }
1178 retrieveTargzProc->writeToStdin( gzipProc->readStdout() );
1179}
1180
1181
1182void ServerDTP::retrieveFile( const QString fn, const QHostAddress& host, Q_UINT16 port )
1183{
1184 file.setName( fn );
1185 mode = RetrieveFile;
1186 connectToHost( host.toString(), port );
1187}
1188
1189void ServerDTP::retrieveFile( const QString fn )
1190{
1191 file.setName( fn );
1192 mode = RetrieveFile;
1193}
1194
1195void ServerDTP::retrieveGzipFile( const QString &fn )
1196{
1197 qDebug("retrieveGzipFile %s", fn.latin1());
1198 file.setName( fn );
1199 mode = RetrieveGzipFile;
1200
1201 gzipProc->setArguments( "gunzip" );
1202 connect( gzipProc, SIGNAL( readyReadStdout() ),
1203 SLOT( tarExtractBlock() ) );
1204 connect( gzipProc, SIGNAL( processExited() ),
1205 SLOT( gunzipDone() ) );
1206}
1207
1208void ServerDTP::retrieveGzipFile( const QString &fn, const QHostAddress& host, Q_UINT16 port )
1209{
1210 retrieveGzipFile( fn );
1211 connectToHost( host.toString(), port );
1212}
1213
1214void ServerDTP::sendByteArray( const QByteArray& array, const QHostAddress& host, Q_UINT16 port )
1215{
1216 buf.setBuffer( array );
1217 mode = SendBuffer;
1218 connectToHost( host.toString(), port );
1219}
1220
1221void ServerDTP::sendByteArray( const QByteArray& array )
1222{
1223 buf.setBuffer( array );
1224 mode = SendBuffer;
1225}
1226
1227void ServerDTP::retrieveByteArray( const QHostAddress& host, Q_UINT16 port )
1228{
1229 buf.setBuffer( QByteArray() );
1230 mode = RetrieveBuffer;
1231 connectToHost( host.toString(), port );
1232}
1233
1234void ServerDTP::retrieveByteArray()
1235{
1236 buf.setBuffer( QByteArray() );
1237 mode = RetrieveBuffer;
1238}
1239
1240void ServerDTP::setSocket( int socket )
1241{
1242 QSocket::setSocket( socket );
1243 connected();
1244}
1245