summaryrefslogtreecommitdiff
authorsandman <sandman>2002-12-17 19:16:18 (UTC)
committer sandman <sandman>2002-12-17 19:16:18 (UTC)
commitf36c70938c8c2907a1b61637af3bd589262b4b5e (patch) (unidiff)
tree7ed7429477ad0b17ea131fddcc5cab9fff088b26
parentb6a03145553d7f536b04fc3355718cfdd72c590d (diff)
downloadopie-f36c70938c8c2907a1b61637af3bd589262b4b5e.zip
opie-f36c70938c8c2907a1b61637af3bd589262b4b5e.tar.gz
opie-f36c70938c8c2907a1b61637af3bd589262b4b5e.tar.bz2
replaced the private QProcess copy for the FTP server with the already
available libopie/OProcess
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--core/launcher/launcher.pro2
-rw-r--r--core/launcher/qprocess.cpp654
-rw-r--r--core/launcher/qprocess.h174
-rw-r--r--core/launcher/qprocess_unix.cpp1158
-rw-r--r--core/launcher/transferserver.cpp2145
-rw-r--r--core/launcher/transferserver.h14
6 files changed, 1097 insertions, 3050 deletions
diff --git a/core/launcher/launcher.pro b/core/launcher/launcher.pro
index 3391378..21f8374 100644
--- a/core/launcher/launcher.pro
+++ b/core/launcher/launcher.pro
@@ -1,74 +1,72 @@
1 TEMPLATE= app 1 TEMPLATE= app
2 CONFIG = qt warn_on release 2 CONFIG = qt warn_on release
3 DESTDIR = ../../bin 3 DESTDIR = ../../bin
4 HEADERS = background.h \ 4 HEADERS = background.h \
5 desktop.h \ 5 desktop.h \
6 screensaver.h \ 6 screensaver.h \
7 qprocess.h \
8 mediummountgui.h \ 7 mediummountgui.h \
9 info.h \ 8 info.h \
10 appicons.h \ 9 appicons.h \
11 taskbar.h \ 10 taskbar.h \
12 sidething.h \ 11 sidething.h \
13 runningappbar.h \ 12 runningappbar.h \
14 stabmon.h \ 13 stabmon.h \
15 inputmethods.h \ 14 inputmethods.h \
16 systray.h \ 15 systray.h \
17 wait.h \ 16 wait.h \
18 shutdownimpl.h \ 17 shutdownimpl.h \
19 launcher.h \ 18 launcher.h \
20 launcherview.h \ 19 launcherview.h \
21 ../../core/apps/calibrate/calibrate.h \ 20 ../../core/apps/calibrate/calibrate.h \
22 startmenu.h \ 21 startmenu.h \
23 transferserver.h \ 22 transferserver.h \
24 qcopbridge.h \ 23 qcopbridge.h \
25 packageslave.h \ 24 packageslave.h \
26 irserver.h \ 25 irserver.h \
27 ../../rsync/buf.h \ 26 ../../rsync/buf.h \
28 ../../rsync/checksum.h \ 27 ../../rsync/checksum.h \
29 ../../rsync/command.h \ 28 ../../rsync/command.h \
30 ../../rsync/emit.h \ 29 ../../rsync/emit.h \
31 ../../rsync/job.h \ 30 ../../rsync/job.h \
32 ../../rsync/netint.h \ 31 ../../rsync/netint.h \
33 ../../rsync/protocol.h \ 32 ../../rsync/protocol.h \
34 ../../rsync/prototab.h \ 33 ../../rsync/prototab.h \
35 ../../rsync/rsync.h \ 34 ../../rsync/rsync.h \
36 ../../rsync/search.h \ 35 ../../rsync/search.h \
37 ../../rsync/stream.h \ 36 ../../rsync/stream.h \
38 ../../rsync/sumset.h \ 37 ../../rsync/sumset.h \
39 ../../rsync/trace.h \ 38 ../../rsync/trace.h \
40 ../../rsync/types.h \ 39 ../../rsync/types.h \
41 ../../rsync/util.h \ 40 ../../rsync/util.h \
42 ../../rsync/whole.h \ 41 ../../rsync/whole.h \
43 ../../rsync/config_rsync.h \ 42 ../../rsync/config_rsync.h \
44 ../../rsync/qrsync.h \ 43 ../../rsync/qrsync.h \
45 quicklauncher.h 44 quicklauncher.h
46 SOURCES = background.cpp \ 45 SOURCES = background.cpp \
47 desktop.cpp \ 46 desktop.cpp \
48 screensaver.cpp \ 47 screensaver.cpp \
49 mediummountgui.cpp \ 48 mediummountgui.cpp \
50 qprocess.cpp qprocess_unix.cpp \
51 info.cpp \ 49 info.cpp \
52 appicons.cpp \ 50 appicons.cpp \
53 taskbar.cpp \ 51 taskbar.cpp \
54 sidething.cpp \ 52 sidething.cpp \
55 runningappbar.cpp \ 53 runningappbar.cpp \
56 stabmon.cpp \ 54 stabmon.cpp \
57 inputmethods.cpp \ 55 inputmethods.cpp \
58 systray.cpp \ 56 systray.cpp \
59 wait.cpp \ 57 wait.cpp \
60 shutdownimpl.cpp \ 58 shutdownimpl.cpp \
61 launcher.cpp \ 59 launcher.cpp \
62 launcherview.cpp \ 60 launcherview.cpp \
63 ../../core/apps/calibrate/calibrate.cpp \ 61 ../../core/apps/calibrate/calibrate.cpp \
64 transferserver.cpp \ 62 transferserver.cpp \
65 packageslave.cpp \ 63 packageslave.cpp \
66 irserver.cpp \ 64 irserver.cpp \
67 qcopbridge.cpp \ 65 qcopbridge.cpp \
68 startmenu.cpp \ 66 startmenu.cpp \
69 main.cpp \ 67 main.cpp \
70 ../../rsync/base64.c \ 68 ../../rsync/base64.c \
71 ../../rsync/buf.c \ 69 ../../rsync/buf.c \
72 ../../rsync/checksum.c \ 70 ../../rsync/checksum.c \
73 ../../rsync/command.c \ 71 ../../rsync/command.c \
74 ../../rsync/delta.c \ 72 ../../rsync/delta.c \
diff --git a/core/launcher/qprocess.cpp b/core/launcher/qprocess.cpp
deleted file mode 100644
index 618c0e0..0000000
--- a/core/launcher/qprocess.cpp
+++ b/dev/null
@@ -1,654 +0,0 @@
1/****************************************************************************
2** $Id$
3**
4** Implementation of QProcess class
5**
6** Created : 20000905
7**
8** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
9**
10** This file is part of the kernel module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#include <stdio.h>
39#include <stdlib.h>
40
41#include "qprocess.h"
42
43#ifndef QT_NO_PROCESS
44
45#include "qapplication.h"
46
47
48//#define QT_QPROCESS_DEBUG
49
50
51/*!
52 \class QProcess qprocess.h
53
54 \brief The QProcess class is used to start external programs and to
55 communicate with them.
56
57 This is a temporary class. This will be replaced by Qt 3's QProcess class.
58*/
59
60/*!
61 \enum QProcess::Communication
62
63 This enum type defines the communication channels connected to the
64 process.
65
66 \value Stdin Data can be written to the process's standard input.
67
68 \value Stdout Data can be read from the process's standard output.
69
70 \value Stderr Data can be read from the process's standard error.
71
72 \value DupStderr Duplicates standard error to standard output for new
73 processes; i.e. everything that the process writes to standard error, is
74 reported by QProcess on standard output instead. This is especially useful if
75 your application requires that the output on standard output and standard
76 error is read in the same order as the process output it. Please note that
77 this is a binary flag, so if you want to activate this together with standard
78 input, output and error redirection (the default), you have to specify
79 \c{Stdin|Stdout|Stderr|DupStderr} for the setCommunication() call.
80
81 \sa setCommunication() communication()
82*/
83
84/*!
85 Constructs a QProcess object. The \a parent and \a name parameters are passed
86 to the QObject constructor.
87
88 \sa setArguments() addArgument() start()
89*/
90QProcess::QProcess( QObject *parent, const char *name )
91 : QObject( parent, name ), ioRedirection( FALSE ), notifyOnExit( FALSE ),
92 wroteToStdinConnected( FALSE ),
93 readStdoutCalled( FALSE ), readStderrCalled( FALSE ),
94 comms( Stdin|Stdout|Stderr )
95{
96 init();
97}
98
99/*!
100 Constructs a QProcess with \a arg0 as the command to be executed. The
101 \a parent and \a name parameters are passed to the QObject constructor.
102
103 The process is not started. You must call start() or launch()
104 to start the process.
105
106 \sa setArguments() addArgument() start()
107*/
108QProcess::QProcess( const QString& arg0, QObject *parent, const char *name )
109 : QObject( parent, name ), ioRedirection( FALSE ), notifyOnExit( FALSE ),
110 wroteToStdinConnected( FALSE ),
111 readStdoutCalled( FALSE ), readStderrCalled( FALSE ),
112 comms( Stdin|Stdout|Stderr )
113{
114 init();
115 addArgument( arg0 );
116}
117
118/*!
119 Constructs a QProcess with \a args as the arguments of the process. The first
120 element in the list is the command to be executed. The other elements in the
121 list are the arguments to this command. The \a parent and \a name
122 parameters are passed to the QObject constructor.
123
124 The process is not started. You must call start() or launch()
125 to start the process.
126
127 \sa setArguments() addArgument() start()
128*/
129QProcess::QProcess( const QStringList& args, QObject *parent, const char *name )
130 : QObject( parent, name ), ioRedirection( FALSE ), notifyOnExit( FALSE ),
131 wroteToStdinConnected( FALSE ),
132 readStdoutCalled( FALSE ), readStderrCalled( FALSE ),
133 comms( Stdin|Stdout|Stderr )
134{
135 init();
136 setArguments( args );
137}
138
139
140/*!
141 Returns the list of arguments that are set for the process. Arguments can be
142 specified with the constructor or with the functions setArguments() and
143 addArgument().
144
145 \sa setArguments() addArgument()
146*/
147QStringList QProcess::arguments() const
148{
149 return _arguments;
150}
151
152/*!
153 Clears the list of arguments that are set for the process.
154
155 \sa setArguments() addArgument()
156*/
157void QProcess::clearArguments()
158{
159 _arguments.clear();
160}
161
162/*!
163 Sets \a args as the arguments for the process. The first element in the list
164 is the command to be executed. The other elements in the list are the
165 arguments to the command. Any previous arguments are deleted.
166
167 \sa arguments() addArgument()
168*/
169void QProcess::setArguments( const QStringList& args )
170{
171 _arguments = args;
172}
173
174/*!
175 Adds \a arg to the end of the list of arguments.
176
177 The first element in the list of arguments is the command to be
178 executed; the following elements are the arguments to the command.
179
180 \sa arguments() setArguments()
181*/
182void QProcess::addArgument( const QString& arg )
183{
184 _arguments.append( arg );
185}
186
187#ifndef QT_NO_DIR
188/*!
189 Returns the working directory that was set with
190 setWorkingDirectory(), or the current directory if none has been
191 set.
192
193 \sa setWorkingDirectory() QDir::current()
194*/
195QDir QProcess::workingDirectory() const
196{
197 return workingDir;
198}
199
200/*!
201 Sets \a dir as the working directory for a process. This does not affect
202 running processes; only processes that are started afterwards are affected.
203
204 Setting the working directory is especially useful for processes that try to
205 access files with relative filenames.
206
207 \sa workingDirectory() start()
208*/
209void QProcess::setWorkingDirectory( const QDir& dir )
210{
211 workingDir = dir;
212}
213#endif //QT_NO_DIR
214
215/*!
216 Returns the communication required with the process.
217
218 \sa setCommunication()
219*/
220int QProcess::communication() const
221{
222 return comms;
223}
224
225/*!
226 Sets \a commFlags as the communication required with the process.
227
228 \a commFlags is a bitwise OR between the flags defined in \c Communication.
229
230 The default is \c{Stdin|Stdout|Stderr}.
231
232 \sa communication()
233*/
234void QProcess::setCommunication( int commFlags )
235{
236 comms = commFlags;
237}
238
239/*!
240 Returns TRUE if the process has exited normally; otherwise returns
241 FALSE. This implies that this function returns FALSE if the process
242 is still running.
243
244 \sa isRunning() exitStatus() processExited()
245*/
246bool QProcess::normalExit() const
247{
248 // isRunning() has the side effect that it determines the exit status!
249 if ( isRunning() )
250 return FALSE;
251 else
252 return exitNormal;
253}
254
255/*!
256 Returns the exit status of the process or 0 if the process is still
257 running. This function returns immediately and does not wait until
258 the process is finished.
259
260 If normalExit() is FALSE (e.g. if the program was killed or
261 crashed), this function returns 0, so you should check the return
262 value of normalExit() before relying on this value.
263
264 \sa normalExit() processExited()
265*/
266int QProcess::exitStatus() const
267{
268 // isRunning() has the side effect that it determines the exit status!
269 if ( isRunning() )
270 return 0;
271 else
272 return exitStat;
273}
274
275
276/*!
277 Reads the data that the process has written to standard output. When
278 new data is written to standard output, the class emits the signal
279 readyReadStdout().
280
281 If there is no data to read, this function returns a QByteArray of
282 size 0: it does not wait until there is something to read.
283
284 \sa readyReadStdout() readLineStdout() readStderr() writeToStdin()
285*/
286QByteArray QProcess::readStdout()
287{
288 if ( readStdoutCalled ) {
289 return QByteArray();
290 }
291 readStdoutCalled = TRUE;
292
293 QByteArray buf = bufStdout()->copy();
294 consumeBufStdout( -1 ); // consume everything
295
296 readStdoutCalled = FALSE;
297 return buf;
298}
299
300/*!
301 Reads the data that the process has written to standard error. When
302 new data is written to standard error, the class emits the signal
303 readyReadStderr().
304
305 If there is no data to read, this function returns a QByteArray of
306 size 0: it does not wait until there is something to read.
307
308 \sa readyReadStderr() readLineStderr() readStdout() writeToStdin()
309*/
310QByteArray QProcess::readStderr()
311{
312 if ( readStderrCalled ) {
313 return QByteArray();
314 }
315 readStderrCalled = TRUE;
316
317 QByteArray buf = bufStderr()->copy();
318 consumeBufStderr( -1 ); // consume everything
319
320 readStderrCalled = FALSE;
321 return buf;
322}
323
324/*!
325 Returns TRUE if it's possible to read an entire line of text from
326 standard output at this time; otherwise returns FALSE.
327
328 \sa readLineStdout() canReadLineStderr()
329*/
330bool QProcess::canReadLineStdout() const
331{
332 QProcess *that = (QProcess*)this;
333 return that->scanNewline( TRUE, 0 );
334}
335
336/*!
337 Returns TRUE if it's possible to read an entire line of text from
338 standard error at this time; otherwise returns FALSE.
339
340 \sa readLineStderr() canReadLineStdout()
341*/
342bool QProcess::canReadLineStderr() const
343{
344 QProcess *that = (QProcess*)this;
345 return that->scanNewline( FALSE, 0 );
346}
347
348/*!
349 Reads a line of text from standard output, excluding any trailing newline or
350 carriage return characters, and returns it. Returns QString::null if
351 canReadLineStdout() returns FALSE.
352
353 \sa canReadLineStdout() readyReadStdout() readStdout() readLineStderr()
354*/
355QString QProcess::readLineStdout()
356{
357 QByteArray a;
358 QString s;
359 if ( scanNewline( TRUE, &a ) ) {
360 if ( a.isEmpty() )
361 s = "";
362 else
363 s = QString( a );
364 }
365 return s;
366}
367
368/*!
369 Reads a line of text from standard error, excluding any trailing newline or
370 carriage return characters and returns it. Returns QString::null if
371 canReadLineStderr() returns FALSE.
372
373 \sa canReadLineStderr() readyReadStderr() readStderr() readLineStdout()
374*/
375QString QProcess::readLineStderr()
376{
377 QByteArray a;
378 QString s;
379 if ( scanNewline( FALSE, &a ) ) {
380 if ( a.isEmpty() )
381 s = "";
382 else
383 s = QString( a );
384 }
385 return s;
386}
387
388/*!
389 This private function scans for any occurrence of \n or \r\n in the
390 buffer \e buf. It stores the text in the byte array \a store if it is
391 non-null.
392*/
393bool QProcess::scanNewline( bool stdOut, QByteArray *store )
394{
395 QByteArray *buf;
396 if ( stdOut )
397 buf = bufStdout();
398 else
399 buf = bufStderr();
400 uint n = buf->size();
401 uint i;
402 for ( i=0; i<n; i++ ) {
403 if ( buf->at(i) == '\n' ) {
404 break;
405 }
406 }
407 if ( i >= n )
408 return FALSE;
409
410 if ( store ) {
411 uint lineLength = i;
412 if ( lineLength>0 && buf->at(lineLength-1) == '\r' )
413 lineLength--; // (if there are two \r, let one stay)
414 store->resize( lineLength );
415 memcpy( store->data(), buf->data(), lineLength );
416 if ( stdOut )
417 consumeBufStdout( i+1 );
418 else
419 consumeBufStderr( i+1 );
420 }
421 return TRUE;
422}
423
424/*!
425 \fn void QProcess::launchFinished()
426
427 This signal is emitted when the process was started with launch().
428 If the start was successful, this signal is emitted after all the
429 data has been written to standard input. If the start failed, then
430 this signal is emitted immediately.
431
432 \sa launch() QObject::deleteLater()
433*/
434
435/*!
436 Runs the process and writes the data \a buf to the process's standard input.
437 If all the data is written to standard input, standard input is
438 closed. The command is searched for in the path for executable programs;
439 you can also use an absolute path in the command itself.
440
441 If \a env is null, then the process is started with the same environment as
442 the starting process. If \a env is non-null, then the values in the
443 stringlist are interpreted as environment setttings of the form \c
444 {key=value} and the process is started with these environment settings. For
445 convenience, there is a small exception to this rule under Unix: if \a env
446 does not contain any settings for the environment variable \c
447 LD_LIBRARY_PATH, then this variable is inherited from the starting process.
448
449 Returns TRUE if the process could be started; otherwise returns FALSE.
450
451 Note that you should not use the slots writeToStdin() and closeStdin() on
452 processes started with launch(), since the result is not well-defined. If you
453 need these slots, use start() instead.
454
455 The process may or may not read the \a buf data sent to its standard
456 input.
457
458 You can call this function even when a process that was started with
459 this instance is still running. Be aware that if you do this the
460 standard input of the process that was launched first will be
461 closed, with any pending data being deleted, and the process will be
462 left to run out of your control. Similarly, if the process could not
463 be started the standard input will be closed and the pending data
464 deleted. (On operating systems that have zombie processes, Qt will
465 also wait() on the old process.)
466
467 The object emits the signal launchFinished() when this function
468 call is finished. If the start was successful, this signal is
469 emitted after all the data has been written to standard input. If
470 the start failed, then this signal is emitted immediately.
471
472 \sa start() launchFinished();
473*/
474bool QProcess::launch( const QByteArray& buf, QStringList *env )
475{
476 if ( start( env ) ) {
477 if ( !buf.isEmpty() ) {
478 connect( this, SIGNAL(wroteToStdin()),
479 this, SLOT(closeStdinLaunch()) );
480 writeToStdin( buf );
481 } else {
482 closeStdin();
483 emit launchFinished();
484 }
485 return TRUE;
486 } else {
487 emit launchFinished();
488 return FALSE;
489 }
490}
491
492/*! \overload
493
494 The data \a buf is written to standard input with writeToStdin()
495 using the QString::local8Bit() representation of the strings.
496*/
497bool QProcess::launch( const QString& buf, QStringList *env )
498{
499 if ( start( env ) ) {
500 if ( !buf.isEmpty() ) {
501 connect( this, SIGNAL(wroteToStdin()),
502 this, SLOT(closeStdinLaunch()) );
503 writeToStdin( buf );
504 } else {
505 closeStdin();
506 emit launchFinished();
507 }
508 return TRUE;
509 } else {
510 emit launchFinished();
511 return FALSE;
512 }
513}
514
515/*!
516 This private slot is used by the launch() functions to close standard input.
517*/
518void QProcess::closeStdinLaunch()
519{
520 disconnect( this, SIGNAL(wroteToStdin()),
521 this, SLOT(closeStdinLaunch()) );
522 closeStdin();
523 emit launchFinished();
524}
525
526
527/*!
528 \fn void QProcess::readyReadStdout()
529
530 This signal is emitted when the process has written data to standard output.
531 You can read the data with readStdout().
532
533 Note that this signal is only emitted when there is new data and not
534 when there is old, but unread data. In the slot connected to this signal, you
535 should always read everything that is available at that moment to make sure
536 that you don't lose any data.
537
538 \sa readStdout() readLineStdout() readyReadStderr()
539*/
540/*!
541 \fn void QProcess::readyReadStderr()
542
543 This signal is emitted when the process has written data to standard error.
544 You can read the data with readStderr().
545
546 Note that this signal is only emitted when there is new data and not
547 when there is old, but unread data. In the slot connected to this signal, you
548 should always read everything that is available at that moment to make sure
549 that you don't lose any data.
550
551 \sa readStderr() readLineStderr() readyReadStdout()
552*/
553/*!
554 \fn void QProcess::processExited()
555
556 This signal is emitted when the process has exited.
557
558 \sa isRunning() normalExit() exitStatus() start() launch()
559*/
560/*!
561 \fn void QProcess::wroteToStdin()
562
563 This signal is emitted if the data sent to standard input (via
564 writeToStdin()) was actually written to the process. This does not
565 imply that the process really read the data, since this class only detects
566 when it was able to write the data to the operating system. But it is now
567 safe to close standard input without losing pending data.
568
569 \sa writeToStdin() closeStdin()
570*/
571
572
573/*! \overload
574
575 The string \a buf is handled as text using
576 the QString::local8Bit() representation.
577*/
578void QProcess::writeToStdin( const QString& buf )
579{
580 QByteArray tmp = buf.local8Bit();
581 tmp.resize( buf.length() );
582 writeToStdin( tmp );
583}
584
585
586/*
587 * Under Windows the implementation is not so nice: it is not that easy to
588 * detect when one of the signals should be emitted; therefore there are some
589 * timers that query the information.
590 * To keep it a little efficient, use the timers only when they are needed.
591 * They are needed, if you are interested in the signals. So use
592 * connectNotify() and disconnectNotify() to keep track of your interest.
593 */
594/*! \reimp
595*/
596void QProcess::connectNotify( const char * signal )
597{
598#if defined(QT_QPROCESS_DEBUG)
599 qDebug( "QProcess::connectNotify(): signal %s has been connected", signal );
600#endif
601 if ( !ioRedirection )
602 if ( qstrcmp( signal, SIGNAL(readyReadStdout()) )==0 ||
603 qstrcmp( signal, SIGNAL(readyReadStderr()) )==0
604 ) {
605#if defined(QT_QPROCESS_DEBUG)
606 qDebug( "QProcess::connectNotify(): set ioRedirection to TRUE" );
607#endif
608 setIoRedirection( TRUE );
609 return;
610 }
611 if ( !notifyOnExit && qstrcmp( signal, SIGNAL(processExited()) )==0 ) {
612#if defined(QT_QPROCESS_DEBUG)
613 qDebug( "QProcess::connectNotify(): set notifyOnExit to TRUE" );
614#endif
615 setNotifyOnExit( TRUE );
616 return;
617 }
618 if ( !wroteToStdinConnected && qstrcmp( signal, SIGNAL(wroteToStdin()) )==0 ) {
619#if defined(QT_QPROCESS_DEBUG)
620 qDebug( "QProcess::connectNotify(): set wroteToStdinConnected to TRUE" );
621#endif
622 setWroteStdinConnected( TRUE );
623 return;
624 }
625}
626
627/*! \reimp
628*/
629void QProcess::disconnectNotify( const char * )
630{
631 if ( ioRedirection &&
632 receivers( SIGNAL(readyReadStdout()) ) ==0 &&
633 receivers( SIGNAL(readyReadStderr()) ) ==0
634 ) {
635#if defined(QT_QPROCESS_DEBUG)
636 qDebug( "QProcess::disconnectNotify(): set ioRedirection to FALSE" );
637#endif
638 setIoRedirection( FALSE );
639 }
640 if ( notifyOnExit && receivers( SIGNAL(processExited()) ) == 0 ) {
641#if defined(QT_QPROCESS_DEBUG)
642 qDebug( "QProcess::disconnectNotify(): set notifyOnExit to FALSE" );
643#endif
644 setNotifyOnExit( FALSE );
645 }
646 if ( wroteToStdinConnected && receivers( SIGNAL(wroteToStdin()) ) == 0 ) {
647#if defined(QT_QPROCESS_DEBUG)
648 qDebug( "QProcess::disconnectNotify(): set wroteToStdinConnected to FALSE" );
649#endif
650 setWroteStdinConnected( FALSE );
651 }
652}
653
654#endif // QT_NO_PROCESS
diff --git a/core/launcher/qprocess.h b/core/launcher/qprocess.h
deleted file mode 100644
index 306e659..0000000
--- a/core/launcher/qprocess.h
+++ b/dev/null
@@ -1,174 +0,0 @@
1/****************************************************************************
2** $Id$
3**
4** Implementation of QProcess class
5**
6** Created : 20000905
7**
8** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
9**
10** This file is part of the kernel module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#ifndef QPROCESS_H
39#define QPROCESS_H
40
41#ifndef QT_H
42#include "qobject.h"
43#include "qstringlist.h"
44#include "qdir.h"
45#endif // QT_H
46
47#ifndef QT_NO_PROCESS
48
49class QProcessPrivate;
50
51
52class Q_EXPORT QProcess : public QObject
53{
54 Q_OBJECT
55public:
56 QProcess( QObject *parent=0, const char *name=0 );
57 QProcess( const QString& arg0, QObject *parent=0, const char *name=0 );
58 QProcess( const QStringList& args, QObject *parent=0, const char *name=0 );
59 ~QProcess();
60
61 // set and get the arguments and working directory
62 QStringList arguments() const;
63 void clearArguments();
64 virtual void setArguments( const QStringList& args );
65 virtual void addArgument( const QString& arg );
66#ifndef QT_NO_DIR
67 QDir workingDirectory() const;
68 virtual void setWorkingDirectory( const QDir& dir );
69#endif
70
71 // set and get the comms wanted
72 enum Communication { Stdin=0x01, Stdout=0x02, Stderr=0x04, DupStderr=0x08 };
73 void setCommunication( int c );
74 int communication() const;
75
76 // start the execution
77 virtual bool start( QStringList *env=0 );
78 virtual bool launch( const QString& buf, QStringList *env=0 );
79 virtual bool launch( const QByteArray& buf, QStringList *env=0 );
80
81 // inquire the status
82 bool isRunning() const;
83 bool normalExit() const;
84 int exitStatus() const;
85
86 // reading
87 virtual QByteArray readStdout();
88 virtual QByteArray readStderr();
89 bool canReadLineStdout() const;
90 bool canReadLineStderr() const;
91 virtual QString readLineStdout();
92 virtual QString readLineStderr();
93
94 // get platform dependent process information
95#if defined(Q_OS_WIN32)
96 typedef void* PID;
97#else
98 typedef long Q_LONG;
99 typedef Q_LONG PID;
100#endif
101 PID processIdentifier();
102
103 void flushStdin();
104
105signals:
106 void readyReadStdout();
107 void readyReadStderr();
108 void processExited();
109 void wroteToStdin();
110 void launchFinished();
111
112public slots:
113 // end the execution
114 void tryTerminate() const;
115 void kill() const;
116
117 // input
118 virtual void writeToStdin( const QByteArray& buf );
119 virtual void writeToStdin( const QString& buf );
120 virtual void closeStdin();
121
122protected: // ### or private?
123 void connectNotify( const char * signal );
124 void disconnectNotify( const char * signal );
125private:
126 void setIoRedirection( bool value );
127 void setNotifyOnExit( bool value );
128 void setWroteStdinConnected( bool value );
129
130 void init();
131 void reset();
132#if defined(Q_OS_WIN32)
133 uint readStddev( HANDLE dev, char *buf, uint bytes );
134#endif
135 bool scanNewline( bool stdOut, QByteArray *store );
136
137 QByteArray* bufStdout();
138 QByteArray* bufStderr();
139 void consumeBufStdout( int consume );
140 void consumeBufStderr( int consume );
141
142private slots:
143 void socketRead( int fd );
144 void socketWrite( int fd );
145 void timeout();
146 void closeStdinLaunch();
147
148private:
149 QProcessPrivate *d;
150#ifndef QT_NO_DIR
151 QDir workingDir;
152#endif
153 QStringList _arguments;
154
155 int exitStat; // exit status
156 bool exitNormal; // normal exit?
157 bool ioRedirection; // automatically set be (dis)connectNotify
158 bool notifyOnExit; // automatically set be (dis)connectNotify
159 bool wroteToStdinConnected; // automatically set be (dis)connectNotify
160
161 bool readStdoutCalled;
162 bool readStderrCalled;
163 int comms;
164
165 friend class QProcessPrivate;
166#if defined(Q_OS_UNIX) || defined(_OS_UNIX) || defined(UNIX)
167 friend class QProcessManager;
168 friend class QProc;
169#endif
170};
171
172#endif // QT_NO_PROCESS
173
174#endif // QPROCESS_H
diff --git a/core/launcher/qprocess_unix.cpp b/core/launcher/qprocess_unix.cpp
deleted file mode 100644
index 75f0f0c..0000000
--- a/core/launcher/qprocess_unix.cpp
+++ b/dev/null
@@ -1,1158 +0,0 @@
1/****************************************************************************
2** $Id$
3**
4** Implementation of QProcess class for Unix
5**
6** Created : 20000905
7**
8** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
9**
10** This file is part of the kernel module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38//#include "qplatformdefs.h"
39
40// Solaris redefines connect -> __xnet_connect with _XOPEN_SOURCE_EXTENDED.
41#if defined(connect)
42#undef connect
43#endif
44
45#include "qprocess.h"
46
47#ifndef QT_NO_PROCESS
48
49#include "qapplication.h"
50#include "qqueue.h"
51#include "qlist.h"
52#include "qsocketnotifier.h"
53#include "qtimer.h"
54#include "qregexp.h"
55
56#include "qcleanuphandler_p.h"
57
58#include <stdlib.h>
59
60// ### FOR Qt 2.3 compat
61#include <unistd.h>
62#include <signal.h>
63#include <sys/socket.h>
64#include <sys/ioctl.h>
65#include <sys/wait.h>
66#include <sys/fcntl.h>
67
68#include <errno.h>
69
70#ifdef __MIPSEL__
71# ifndef SOCK_DGRAM
72# define SOCK_DGRAM 1
73# endif
74# ifndef SOCK_STREAM
75# define SOCK_STREAM 2
76# endif
77#endif
78
79//#define QT_QPROCESS_DEBUG
80
81
82#ifdef Q_C_CALLBACKS
83extern "C" {
84#endif // Q_C_CALLBACKS
85
86#define QT_SIGNAL_RETTYPE void
87#define QT_SIGNAL_ARGS int
88#define QT_SIGNAL_IGNORE SIG_IGN
89
90 QT_SIGNAL_RETTYPE qt_C_sigchldHnd(QT_SIGNAL_ARGS);
91
92#ifdef Q_C_CALLBACKS
93}
94#endif // Q_C_CALLBACKS
95
96
97class QProc;
98class QProcessManager;
99class QProcessPrivate
100{
101public:
102 QProcessPrivate();
103 ~QProcessPrivate();
104
105 void closeOpenSocketsForChild();
106 void newProc( pid_t pid, QProcess *process );
107
108 QByteArray bufStdout;
109 QByteArray bufStderr;
110
111 QQueue<QByteArray> stdinBuf;
112
113 QSocketNotifier *notifierStdin;
114 QSocketNotifier *notifierStdout;
115 QSocketNotifier *notifierStderr;
116
117 ssize_t stdinBufRead;
118 QProc *proc;
119
120 bool exitValuesCalculated;
121 bool socketReadCalled;
122
123 static QProcessManager *procManager;
124};
125
126
127/***********************************************************************
128 *
129 * QProc
130 *
131 **********************************************************************/
132/*
133 The class QProcess does not necessarily map exactly to the running
134 child processes: if the process is finished, the QProcess class may still be
135 there; furthermore a user can use QProcess to start more than one process.
136
137 The helper-class QProc has the semantics that one instance of this class maps
138 directly to a running child process.
139*/
140class QProc
141{
142public:
143 QProc( pid_t p, QProcess *proc=0 ) : pid(p), process(proc)
144 {
145#if defined(QT_QPROCESS_DEBUG)
146 qDebug( "QProc: Constructor for pid %d and QProcess %p", pid, process );
147#endif
148 socketStdin = 0;
149 socketStdout = 0;
150 socketStderr = 0;
151 }
152 ~QProc()
153 {
154#if defined(QT_QPROCESS_DEBUG)
155 qDebug( "QProc: Destructor for pid %d and QProcess %p", pid, process );
156#endif
157 if ( process != 0 ) {
158 if ( process->d->notifierStdin )
159 process->d->notifierStdin->setEnabled( FALSE );
160 if ( process->d->notifierStdout )
161 process->d->notifierStdout->setEnabled( FALSE );
162 if ( process->d->notifierStderr )
163 process->d->notifierStderr->setEnabled( FALSE );
164 process->d->proc = 0;
165 }
166 if( socketStdin != 0 )
167 ::close( socketStdin );
168 // ### close these sockets even on parent exit or is it better only on
169 // sigchld (but what do I have to do with them on exit then)?
170 if( socketStdout != 0 )
171 ::close( socketStdout );
172 if( socketStderr != 0 )
173 ::close( socketStderr );
174 }
175
176 pid_t pid;
177 int socketStdin;
178 int socketStdout;
179 int socketStderr;
180 QProcess *process;
181};
182
183/***********************************************************************
184 *
185 * QProcessManager
186 *
187 **********************************************************************/
188class QProcessManager : public QObject
189{
190 Q_OBJECT
191
192public:
193 QProcessManager();
194 ~QProcessManager();
195
196 void append( QProc *p );
197 void remove( QProc *p );
198
199 void cleanup();
200
201public slots:
202 void removeMe();
203 void sigchldHnd( int );
204
205public:
206 struct sigaction oldactChld;
207 struct sigaction oldactPipe;
208 QList<QProc> *procList;
209 int sigchldFd[2];
210};
211
212QCleanupHandler<QProcessManager> qprocess_cleanup_procmanager;
213
214QProcessManager::QProcessManager()
215{
216 procList = new QList<QProc>;
217 procList->setAutoDelete( TRUE );
218
219 // The SIGCHLD handler writes to a socket to tell the manager that
220 // something happened. This is done to get the processing in sync with the
221 // event reporting.
222 if ( ::socketpair( AF_UNIX, SOCK_STREAM, 0, sigchldFd ) ) {
223 sigchldFd[0] = 0;
224 sigchldFd[1] = 0;
225 } else {
226#if defined(QT_QPROCESS_DEBUG)
227 qDebug( "QProcessManager: install socket notifier (%d)", sigchldFd[1] );
228#endif
229 QSocketNotifier *sn = new QSocketNotifier( sigchldFd[1],
230 QSocketNotifier::Read, this );
231 connect( sn, SIGNAL(activated(int)),
232 this, SLOT(sigchldHnd(int)) );
233 sn->setEnabled( TRUE );
234 }
235
236 // install a SIGCHLD handler and ignore SIGPIPE
237 struct sigaction act;
238
239#if defined(QT_QPROCESS_DEBUG)
240 qDebug( "QProcessManager: install a SIGCHLD handler" );
241#endif
242 act.sa_handler = qt_C_sigchldHnd;
243 sigemptyset( &(act.sa_mask) );
244 sigaddset( &(act.sa_mask), SIGCHLD );
245 act.sa_flags = SA_NOCLDSTOP;
246#if defined(SA_RESTART)
247 act.sa_flags |= SA_RESTART;
248#endif
249 if ( sigaction( SIGCHLD, &act, &oldactChld ) != 0 )
250 qWarning( "Error installing SIGCHLD handler" );
251
252#if defined(QT_QPROCESS_DEBUG)
253 qDebug( "QProcessManager: install a SIGPIPE handler (SIG_IGN)" );
254#endif
255 act.sa_handler = QT_SIGNAL_IGNORE;
256 sigemptyset( &(act.sa_mask) );
257 sigaddset( &(act.sa_mask), SIGPIPE );
258 act.sa_flags = 0;
259 if ( sigaction( SIGPIPE, &act, &oldactPipe ) != 0 )
260 qWarning( "Error installing SIGPIPE handler" );
261}
262
263QProcessManager::~QProcessManager()
264{
265 delete procList;
266
267 if ( sigchldFd[0] != 0 )
268 ::close( sigchldFd[0] );
269 if ( sigchldFd[1] != 0 )
270 ::close( sigchldFd[1] );
271
272 // restore SIGCHLD handler
273#if defined(QT_QPROCESS_DEBUG)
274 qDebug( "QProcessManager: restore old sigchild handler" );
275#endif
276 if ( sigaction( SIGCHLD, &oldactChld, 0 ) != 0 )
277 qWarning( "Error restoring SIGCHLD handler" );
278
279#if defined(QT_QPROCESS_DEBUG)
280 qDebug( "QProcessManager: restore old sigpipe handler" );
281#endif
282 if ( sigaction( SIGPIPE, &oldactPipe, 0 ) != 0 )
283 qWarning( "Error restoring SIGPIPE handler" );
284}
285
286void QProcessManager::append( QProc *p )
287{
288 procList->append( p );
289#if defined(QT_QPROCESS_DEBUG)
290 qDebug( "QProcessManager: append process (procList.count(): %d)", procList->count() );
291#endif
292}
293
294void QProcessManager::remove( QProc *p )
295{
296 procList->remove( p );
297#if defined(QT_QPROCESS_DEBUG)
298 qDebug( "QProcessManager: remove process (procList.count(): %d)", procList->count() );
299#endif
300 cleanup();
301}
302
303void QProcessManager::cleanup()
304{
305 if ( procList->count() == 0 ) {
306 QTimer::singleShot( 0, this, SLOT(removeMe()) );
307 }
308}
309
310void QProcessManager::removeMe()
311{
312 if ( procList->count() == 0 ) {
313 qprocess_cleanup_procmanager.remove( &QProcessPrivate::procManager );
314 QProcessPrivate::procManager = 0;
315 delete this;
316 }
317}
318
319void QProcessManager::sigchldHnd( int fd )
320{
321 char tmp;
322 ::read( fd, &tmp, sizeof(tmp) );
323#if defined(QT_QPROCESS_DEBUG)
324 qDebug( "QProcessManager::sigchldHnd()" );
325#endif
326 QProc *proc;
327 QProcess *process;
328 bool removeProc;
329 proc = procList->first();
330 while ( proc != 0 ) {
331 removeProc = FALSE;
332 process = proc->process;
333 if ( process != 0 ) {
334 if ( !process->isRunning() ) {
335#if defined(QT_QPROCESS_DEBUG)
336 qDebug( "QProcessManager::sigchldHnd() (PID: %d): process exited (QProcess available)", proc->pid );
337#endif
338 // read pending data
339 int nbytes = 0;
340 if ( ::ioctl(proc->socketStdout, FIONREAD, (char*)&nbytes)==0 && nbytes>0 ) {
341#if defined(QT_QPROCESS_DEBUG)
342 qDebug( "QProcessManager::sigchldHnd() (PID: %d): reading %d bytes of pending data on stdout", proc->pid, nbytes );
343#endif
344 process->socketRead( proc->socketStdout );
345 }
346 nbytes = 0;
347 if ( ::ioctl(proc->socketStderr, FIONREAD, (char*)&nbytes)==0 && nbytes>0 ) {
348#if defined(QT_QPROCESS_DEBUG)
349 qDebug( "QProcessManager::sigchldHnd() (PID: %d): reading %d bytes of pending data on stderr", proc->pid, nbytes );
350#endif
351 process->socketRead( proc->socketStderr );
352 }
353
354 if ( process->notifyOnExit )
355 emit process->processExited();
356
357 removeProc = TRUE;
358 }
359 } else {
360 int status;
361 if ( ::waitpid( proc->pid, &status, WNOHANG ) == proc->pid ) {
362#if defined(QT_QPROCESS_DEBUG)
363 qDebug( "QProcessManager::sigchldHnd() (PID: %d): process exited (QProcess not available)", proc->pid );
364#endif
365 removeProc = TRUE;
366 }
367 }
368 if ( removeProc ) {
369 QProc *oldproc = proc;
370 proc = procList->next();
371 remove( oldproc );
372 } else {
373 proc = procList->next();
374 }
375 }
376}
377
378#include "qprocess_unix.moc"
379
380
381/***********************************************************************
382 *
383 * QProcessPrivate
384 *
385 **********************************************************************/
386QProcessManager *QProcessPrivate::procManager = 0;
387
388QProcessPrivate::QProcessPrivate()
389{
390#if defined(QT_QPROCESS_DEBUG)
391 qDebug( "QProcessPrivate: Constructor" );
392#endif
393 stdinBufRead = 0;
394
395 notifierStdin = 0;
396 notifierStdout = 0;
397 notifierStderr = 0;
398
399 exitValuesCalculated = FALSE;
400 socketReadCalled = FALSE;
401
402 proc = 0;
403}
404
405QProcessPrivate::~QProcessPrivate()
406{
407#if defined(QT_QPROCESS_DEBUG)
408 qDebug( "QProcessPrivate: Destructor" );
409#endif
410
411 if ( proc != 0 ) {
412 if ( proc->socketStdin != 0 ) {
413 ::close( proc->socketStdin );
414 proc->socketStdin = 0;
415 }
416 proc->process = 0;
417 }
418
419 while ( !stdinBuf.isEmpty() ) {
420 delete stdinBuf.dequeue();
421 }
422 delete notifierStdin;
423 delete notifierStdout;
424 delete notifierStderr;
425}
426
427/*
428 Closes all open sockets in the child process that are not needed by the child
429 process. Otherwise one child may have an open socket on standard input, etc.
430 of another child.
431*/
432void QProcessPrivate::closeOpenSocketsForChild()
433{
434 if ( procManager != 0 ) {
435 if ( procManager->sigchldFd[0] != 0 )
436 ::close( procManager->sigchldFd[0] );
437 if ( procManager->sigchldFd[1] != 0 )
438 ::close( procManager->sigchldFd[1] );
439
440 // close also the sockets from other QProcess instances
441 QProc *proc;
442 for ( proc=procManager->procList->first(); proc!=0; proc=procManager->procList->next() ) {
443 ::close( proc->socketStdin );
444 ::close( proc->socketStdout );
445 ::close( proc->socketStderr );
446 }
447 }
448}
449
450void QProcessPrivate::newProc( pid_t pid, QProcess *process )
451{
452 proc = new QProc( pid, process );
453 if ( procManager == 0 ) {
454 procManager = new QProcessManager;
455 qprocess_cleanup_procmanager.add( &procManager );
456 }
457 // the QProcessManager takes care of deleting the QProc instances
458 procManager->append( proc );
459}
460
461/***********************************************************************
462 *
463 * sigchld handler callback
464 *
465 **********************************************************************/
466QT_SIGNAL_RETTYPE qt_C_sigchldHnd( QT_SIGNAL_ARGS )
467{
468 if ( QProcessPrivate::procManager == 0 )
469 return;
470 if ( QProcessPrivate::procManager->sigchldFd[0] == 0 )
471 return;
472
473 char a = 1;
474 ::write( QProcessPrivate::procManager->sigchldFd[0], &a, sizeof(a) );
475}
476
477
478/***********************************************************************
479 *
480 * QProcess
481 *
482 **********************************************************************/
483/*!
484 This private class does basic initialization.
485*/
486void QProcess::init()
487{
488 d = new QProcessPrivate();
489 exitStat = 0;
490 exitNormal = FALSE;
491}
492
493/*!
494 This private class resets the process variables, etc. so that it can be used
495 for another process to start.
496*/
497void QProcess::reset()
498{
499 delete d;
500 d = new QProcessPrivate();
501 exitStat = 0;
502 exitNormal = FALSE;
503 d->bufStdout.resize( 0 );
504 d->bufStderr.resize( 0 );
505}
506
507QByteArray* QProcess::bufStdout()
508{
509 if ( d->proc && d->proc->socketStdout ) {
510 // ### can this cause a blocking behaviour (maybe do a ioctl() to see
511 // if data is available)?
512 socketRead( d->proc->socketStdout );
513 }
514 return &d->bufStdout;
515}
516
517QByteArray* QProcess::bufStderr()
518{
519 if ( d->proc && d->proc->socketStderr ) {
520 // ### can this cause a blocking behaviour (maybe do a ioctl() to see
521 // if data is available)?
522 socketRead( d->proc->socketStderr );
523 }
524 return &d->bufStderr;
525}
526
527void QProcess::consumeBufStdout( int consume )
528{
529 uint n = d->bufStdout.size();
530 if ( consume==-1 || (uint)consume >= n ) {
531 d->bufStdout.resize( 0 );
532 } else {
533 QByteArray tmp( n - consume );
534 memcpy( tmp.data(), d->bufStdout.data()+consume, n-consume );
535 d->bufStdout = tmp;
536 }
537}
538
539void QProcess::consumeBufStderr( int consume )
540{
541 uint n = d->bufStderr.size();
542 if ( consume==-1 || (uint)consume >= n ) {
543 d->bufStderr.resize( 0 );
544 } else {
545 QByteArray tmp( n - consume );
546 memcpy( tmp.data(), d->bufStderr.data()+consume, n-consume );
547 d->bufStderr = tmp;
548 }
549}
550
551/*!
552 Destroys the class.
553
554 If the process is running, it is NOT terminated! Standard input, standard
555 output and standard error of the process are closed.
556
557 You can connect the destroyed() signal to the kill() slot, if you want the
558 process to be terminated automatically when the class is destroyed.
559
560 \sa tryTerminate() kill()
561*/
562QProcess::~QProcess()
563{
564 delete d;
565}
566
567/*!
568 Tries to run a process for the command and arguments that were specified with
569 setArguments(), addArgument() or that were specified in the constructor. The
570 command is searched in the path for executable programs; you can also use an
571 absolute path to the command.
572
573 If \a env is null, then the process is started with the same environment as
574 the starting process. If \a env is non-null, then the values in the
575 stringlist are interpreted as environment setttings of the form \c
576 {key=value} and the process is started in these environment settings. For
577 convenience, there is a small exception to this rule: under Unix, if \a env
578 does not contain any settings for the environment variable \c
579 LD_LIBRARY_PATH, then this variable is inherited from the starting process;
580 under Windows the same applies for the enverionment varialbe \c PATH.
581
582 Returns TRUE if the process could be started, otherwise FALSE.
583
584 You can write data to standard input of the process with
585 writeToStdin(), you can close standard input with closeStdin() and you can
586 terminate the process tryTerminate() resp. kill().
587
588 You can call this function even when there already is a running
589 process in this object. In this case, QProcess closes standard input
590 of the old process and deletes pending data, i.e., you loose all
591 control over that process, but the process is not terminated. This applies
592 also if the process could not be started. (On operating systems that have
593 zombie processes, Qt will also wait() on the old process.)
594
595 \sa launch() closeStdin()
596*/
597bool QProcess::start( QStringList *env )
598{
599#if defined(QT_QPROCESS_DEBUG)
600 qDebug( "QProcess::start()" );
601#endif
602 reset();
603
604 int sStdin[2];
605 int sStdout[2];
606 int sStderr[2];
607
608 // open sockets for piping
609 if ( (comms & Stdin) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sStdin ) == -1 ) {
610 return FALSE;
611 }
612 if ( (comms & Stderr) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sStderr ) == -1 ) {
613 return FALSE;
614 }
615 if ( (comms & Stdout) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sStdout ) == -1 ) {
616 return FALSE;
617 }
618
619 // the following pipe is only used to determine if the process could be
620 // started
621 int fd[2];
622 if ( pipe( fd ) < 0 ) {
623 // non critical error, go on
624 fd[0] = 0;
625 fd[1] = 0;
626 }
627
628 // construct the arguments for exec
629 QCString *arglistQ = new QCString[ _arguments.count() + 1 ];
630 const char** arglist = new const char*[ _arguments.count() + 1 ];
631 int i = 0;
632 for ( QStringList::Iterator it = _arguments.begin(); it != _arguments.end(); ++it ) {
633 arglistQ[i] = (*it).local8Bit();
634 arglist[i] = arglistQ[i];
635#if defined(QT_QPROCESS_DEBUG)
636 qDebug( "QProcess::start(): arg %d = %s", i, arglist[i] );
637#endif
638 i++;
639 }
640 arglist[i] = 0;
641
642 // Must make sure signal handlers are installed before exec'ing
643 // in case the process exits quickly.
644 if ( d->procManager == 0 ) {
645 d->procManager = new QProcessManager;
646 qprocess_cleanup_procmanager.add( &d->procManager );
647 }
648
649 // fork and exec
650 QApplication::flushX();
651 pid_t pid = fork();
652 if ( pid == 0 ) {
653 // child
654 d->closeOpenSocketsForChild();
655 if ( comms & Stdin ) {
656 ::close( sStdin[1] );
657 ::dup2( sStdin[0], STDIN_FILENO );
658 }
659 if ( comms & Stdout ) {
660 ::close( sStdout[0] );
661 ::dup2( sStdout[1], STDOUT_FILENO );
662 }
663 if ( comms & Stderr ) {
664 ::close( sStderr[0] );
665 ::dup2( sStderr[1], STDERR_FILENO );
666 }
667 if ( comms & DupStderr ) {
668 ::dup2( STDOUT_FILENO, STDERR_FILENO );
669 }
670#ifndef QT_NO_DIR
671 ::chdir( workingDir.absPath().latin1() );
672#endif
673 if ( fd[0] )
674 ::close( fd[0] );
675 if ( fd[1] )
676 ::fcntl( fd[1], F_SETFD, FD_CLOEXEC ); // close on exec shows sucess
677
678 if ( env == 0 ) { // inherit environment and start process
679 ::execvp( arglist[0], (char*const*)arglist ); // ### cast not nice
680 } else { // start process with environment settins as specified in env
681 // construct the environment for exec
682 int numEntries = env->count();
683 bool setLibraryPath =
684 env->grep( QRegExp( "^LD_LIBRARY_PATH=" ) ).isEmpty() &&
685 getenv( "LD_LIBRARY_PATH" ) != 0;
686 if ( setLibraryPath )
687 numEntries++;
688 QCString *envlistQ = new QCString[ numEntries + 1 ];
689 const char** envlist = new const char*[ numEntries + 1 ];
690 int i = 0;
691 if ( setLibraryPath ) {
692 envlistQ[i] = QString( "LD_LIBRARY_PATH=%1" ).arg( getenv( "LD_LIBRARY_PATH" ) ).local8Bit();
693 envlist[i] = envlistQ[i];
694 i++;
695 }
696 for ( QStringList::Iterator it = env->begin(); it != env->end(); ++it ) {
697 envlistQ[i] = (*it).local8Bit();
698 envlist[i] = envlistQ[i];
699 i++;
700 }
701 envlist[i] = 0;
702
703 // look for the executable in the search path
704 if ( _arguments.count()>0 && getenv("PATH")!=0 ) {
705 QString command = _arguments[0];
706 if ( !command.contains( '/' ) ) {
707 QStringList pathList = QStringList::split( ':', getenv( "PATH" ) );
708 for (QStringList::Iterator it = pathList.begin(); it != pathList.end(); ++it ) {
709 QString dir = *it;
710#ifdef Q_OS_MACX
711 if(QFile::exists(dir + "/" + command + ".app")) //look in a bundle
712 dir += "/" + command + ".app/Contents/MacOS";
713#endif
714#ifndef QT_NO_DIR
715 QFileInfo fileInfo( dir, command );
716#else
717 QFileInfo fileInfo( dir + "/" + command );
718#endif
719 if ( fileInfo.isExecutable() ) {
720 arglistQ[0] = fileInfo.filePath().local8Bit();
721 arglist[0] = arglistQ[0];
722 break;
723 }
724 }
725 }
726 }
727 ::execve( arglist[0], (char*const*)arglist, (char*const*)envlist ); // ### casts not nice
728 }
729 if ( fd[1] ) {
730 char buf = 0;
731 ::write( fd[1], &buf, 1 );
732 ::close( fd[1] );
733 }
734 ::exit( -1 );
735 } else if ( pid == -1 ) {
736 // error forking
737 goto error;
738 }
739
740 // test if exec was successful
741 if ( fd[1] )
742 ::close( fd[1] );
743 if ( fd[0] ) {
744 char buf;
745 for ( ;; ) {
746 int n = ::read( fd[0], &buf, 1 );
747 if ( n==1 ) {
748 // socket was not closed => error
749 d->proc = 0;
750 goto error;
751 } else if ( n==-1 ) {
752 if ( errno==EAGAIN || errno==EINTR )
753 // try it again
754 continue;
755 }
756 break;
757 }
758 ::close( fd[0] );
759 }
760
761 d->newProc( pid, this );
762
763 if ( comms & Stdin ) {
764 ::close( sStdin[0] );
765 d->proc->socketStdin = sStdin[1];
766 d->notifierStdin = new QSocketNotifier( sStdin[1], QSocketNotifier::Write );
767 connect( d->notifierStdin, SIGNAL(activated(int)),
768 this, SLOT(socketWrite(int)) );
769 // setup notifiers for the sockets
770 if ( !d->stdinBuf.isEmpty() ) {
771 d->notifierStdin->setEnabled( TRUE );
772 }
773 }
774 if ( comms & Stdout ) {
775 ::close( sStdout[1] );
776 d->proc->socketStdout = sStdout[0];
777 d->notifierStdout = new QSocketNotifier( sStdout[0], QSocketNotifier::Read );
778 connect( d->notifierStdout, SIGNAL(activated(int)),
779 this, SLOT(socketRead(int)) );
780 if ( ioRedirection )
781 d->notifierStdout->setEnabled( TRUE );
782 }
783 if ( comms & Stderr ) {
784 ::close( sStderr[1] );
785 d->proc->socketStderr = sStderr[0];
786 d->notifierStderr = new QSocketNotifier( sStderr[0], QSocketNotifier::Read );
787 connect( d->notifierStderr, SIGNAL(activated(int)),
788 this, SLOT(socketRead(int)) );
789 if ( ioRedirection )
790 d->notifierStderr->setEnabled( TRUE );
791 }
792
793 // cleanup and return
794 delete[] arglistQ;
795 delete[] arglist;
796 return TRUE;
797
798error:
799#if defined(QT_QPROCESS_DEBUG)
800 qDebug( "QProcess::start(): error starting process" );
801#endif
802 if ( d->procManager )
803 d->procManager->cleanup();
804 if ( comms & Stdin ) {
805 ::close( sStdin[1] );
806 ::close( sStdin[0] );
807 }
808 if ( comms & Stdout ) {
809 ::close( sStdout[0] );
810 ::close( sStdout[1] );
811 }
812 if ( comms & Stderr ) {
813 ::close( sStderr[0] );
814 ::close( sStderr[1] );
815 }
816 ::close( fd[0] );
817 ::close( fd[1] );
818 delete[] arglistQ;
819 delete[] arglist;
820 return FALSE;
821}
822
823
824/*!
825 Asks the process to terminate. Processes can ignore this wish. If you want to
826 be sure that the process really terminates, you must use kill() instead.
827
828 The slot returns immediately: it does not wait until the process has
829 finished. When the process really exited, the signal processExited() is
830 emitted.
831
832 \sa kill() processExited()
833*/
834void QProcess::tryTerminate() const
835{
836 if ( d->proc != 0 )
837 ::kill( d->proc->pid, SIGTERM );
838}
839
840/*!
841 Terminates the process. This is not a safe way to end a process since the
842 process will not be able to do cleanup. tryTerminate() is a safer way to do
843 it, but processes might ignore a tryTerminate().
844
845 The nice way to end a process and to be sure that it is finished, is doing
846 something like this:
847 \code
848 process->tryTerminate();
849 QTimer::singleShot( 5000, process, SLOT( kill() ) );
850 \endcode
851
852 This tries to terminate the process the nice way. If the process is still
853 running after 5 seconds, it terminates the process the hard way. The timeout
854 should be chosen depending on the time the process needs to do all the
855 cleanup: use a higher value if the process is likely to do heavy computation
856 on cleanup.
857
858 The slot returns immediately: it does not wait until the process has
859 finished. When the process really exited, the signal processExited() is
860 emitted.
861
862 \sa tryTerminate() processExited()
863*/
864void QProcess::kill() const
865{
866 if ( d->proc != 0 )
867 ::kill( d->proc->pid, SIGKILL );
868}
869
870/*!
871 Returns TRUE if the process is running, otherwise FALSE.
872
873 \sa normalExit() exitStatus() processExited()
874*/
875bool QProcess::isRunning() const
876{
877 if ( d->exitValuesCalculated ) {
878#if defined(QT_QPROCESS_DEBUG)
879 qDebug( "QProcess::isRunning(): FALSE (already computed)" );
880#endif
881 return FALSE;
882 }
883 if ( d->proc == 0 )
884 return FALSE;
885 int status;
886 if ( ::waitpid( d->proc->pid, &status, WNOHANG ) == d->proc->pid )
887 {
888 // compute the exit values
889 QProcess *that = (QProcess*)this; // mutable
890 that->exitNormal = WIFEXITED( status ) != 0;
891 if ( exitNormal ) {
892 that->exitStat = (char)WEXITSTATUS( status );
893 }
894 d->exitValuesCalculated = TRUE;
895#if defined(QT_QPROCESS_DEBUG)
896 qDebug( "QProcess::isRunning() (PID: %d): FALSE", d->proc->pid );
897#endif
898 return FALSE;
899 }
900#if defined(QT_QPROCESS_DEBUG)
901 qDebug( "QProcess::isRunning() (PID: %d): TRUE", d->proc->pid );
902#endif
903 return TRUE;
904}
905
906/*!
907 Writes the data \a buf to the standard input of the process. The process may
908 or may not read this data.
909
910 This function returns immediately; the QProcess class might write the data at
911 a later point (you have to enter the event loop for that). When all the data
912 is written to the process, the signal wroteToStdin() is emitted. This does
913 not mean that the process really read the data, since this class only detects
914 when it was able to write the data to the operating system.
915
916 \sa wroteToStdin() closeStdin() readStdout() readStderr()
917*/
918void QProcess::writeToStdin( const QByteArray& buf )
919{
920#if defined(QT_QPROCESS_DEBUG)
921// qDebug( "QProcess::writeToStdin(): write to stdin (%d)", d->socketStdin );
922#endif
923 d->stdinBuf.enqueue( new QByteArray(buf) );
924 if ( d->notifierStdin != 0 )
925 d->notifierStdin->setEnabled( TRUE );
926}
927
928
929/*!
930 Closes standard input of the process.
931
932 This function also deletes pending data that is not written to standard input
933 yet.
934
935 \sa wroteToStdin()
936*/
937void QProcess::closeStdin()
938{
939 if ( d->proc == 0 )
940 return;
941 if ( d->proc->socketStdin !=0 ) {
942 while ( !d->stdinBuf.isEmpty() ) {
943 delete d->stdinBuf.dequeue();
944 }
945 delete d->notifierStdin;
946 d->notifierStdin = 0;
947 if ( ::close( d->proc->socketStdin ) != 0 ) {
948 qWarning( "Could not close stdin of child process" );
949 }
950#if defined(QT_QPROCESS_DEBUG)
951 qDebug( "QProcess::closeStdin(): stdin (%d) closed", d->proc->socketStdin );
952#endif
953 d->proc->socketStdin = 0;
954 }
955}
956
957
958/*
959 This private slot is called when the process has outputted data to either
960 standard output or standard error.
961*/
962void QProcess::socketRead( int fd )
963{
964 if ( d->socketReadCalled ) {
965 // the slots that are connected to the readyRead...() signals might
966 // trigger a recursive call of socketRead(). Avoid this since you get a
967 // blocking read otherwise.
968 return;
969 }
970#if defined(QT_QPROCESS_DEBUG)
971 qDebug( "QProcess::socketRead(): %d", fd );
972#endif
973 if ( fd == 0 )
974 return;
975 const int bufsize = 4096;
976 QByteArray *buffer = 0;
977 uint oldSize;
978 int n;
979 if ( fd == d->proc->socketStdout ) {
980 buffer = &d->bufStdout;
981 } else if ( fd == d->proc->socketStderr ) {
982 buffer = &d->bufStderr;
983 } else {
984 // this case should never happen, but just to be safe
985 return;
986 }
987
988 // read data
989 oldSize = buffer->size();
990 buffer->resize( oldSize + bufsize );
991 n = ::read( fd, buffer->data()+oldSize, bufsize );
992 if ( n > 0 )
993 buffer->resize( oldSize + n );
994 else
995 buffer->resize( oldSize );
996 // eof or error?
997 if ( n == 0 || n == -1 ) {
998 if ( fd == d->proc->socketStdout ) {
999#if defined(QT_QPROCESS_DEBUG)
1000 qDebug( "QProcess::socketRead(): stdout (%d) closed", fd );
1001#endif
1002 d->notifierStdout->setEnabled( FALSE );
1003 delete d->notifierStdout;
1004 d->notifierStdout = 0;
1005 ::close( d->proc->socketStdout );
1006 d->proc->socketStdout = 0;
1007 return;
1008 } else if ( fd == d->proc->socketStderr ) {
1009#if defined(QT_QPROCESS_DEBUG)
1010 qDebug( "QProcess::socketRead(): stderr (%d) closed", fd );
1011#endif
1012 d->notifierStderr->setEnabled( FALSE );
1013 delete d->notifierStderr;
1014 d->notifierStderr = 0;
1015 ::close( d->proc->socketStderr );
1016 d->proc->socketStderr = 0;
1017 return;
1018 }
1019 }
1020 // read all data that is available
1021 while ( n == bufsize ) {
1022 oldSize = buffer->size();
1023 buffer->resize( oldSize + bufsize );
1024 n = ::read( fd, buffer->data()+oldSize, bufsize );
1025 if ( n > 0 )
1026 buffer->resize( oldSize + n );
1027 else
1028 buffer->resize( oldSize );
1029 }
1030
1031 d->socketReadCalled = TRUE;
1032 if ( fd == d->proc->socketStdout ) {
1033#if defined(QT_QPROCESS_DEBUG)
1034 qDebug( "QProcess::socketRead(): %d bytes read from stdout (%d)",
1035 buffer->size()-oldSize, fd );
1036#endif
1037 emit readyReadStdout();
1038 } else if ( fd == d->proc->socketStderr ) {
1039#if defined(QT_QPROCESS_DEBUG)
1040 qDebug( "QProcess::socketRead(): %d bytes read from stderr (%d)",
1041 buffer->size()-oldSize, fd );
1042#endif
1043 emit readyReadStderr();
1044 }
1045 d->socketReadCalled = FALSE;
1046}
1047
1048
1049/*
1050 This private slot is called when the process tries to read data from standard
1051 input.
1052*/
1053void QProcess::socketWrite( int fd )
1054{
1055 if ( fd != d->proc->socketStdin || d->proc->socketStdin == 0 )
1056 return;
1057 if ( d->stdinBuf.isEmpty() ) {
1058 d->notifierStdin->setEnabled( FALSE );
1059 return;
1060 }
1061#if defined(QT_QPROCESS_DEBUG)
1062 qDebug( "QProcess::socketWrite(): write to stdin (%d)", fd );
1063#endif
1064 ssize_t ret = ::write( fd,
1065 d->stdinBuf.head()->data() + d->stdinBufRead,
1066 d->stdinBuf.head()->size() - d->stdinBufRead );
1067 if ( ret > 0 )
1068 d->stdinBufRead += ret;
1069 if ( d->stdinBufRead == (ssize_t)d->stdinBuf.head()->size() ) {
1070 d->stdinBufRead = 0;
1071 delete d->stdinBuf.dequeue();
1072 if ( wroteToStdinConnected && d->stdinBuf.isEmpty() )
1073 emit wroteToStdin();
1074 socketWrite( fd );
1075 }
1076}
1077
1078/*!
1079 \internal
1080 Flushes standard input. This is useful if you want to use QProcess in a
1081 synchronous manner.
1082
1083 This function should probably go into the public API.
1084*/
1085void QProcess::flushStdin()
1086{
1087 socketWrite( d->proc->socketStdin );
1088}
1089
1090/*
1091 This private slot is only used under Windows (but moc does not know about #if
1092 defined()).
1093*/
1094void QProcess::timeout()
1095{
1096}
1097
1098
1099/*
1100 This private function is used by connectNotify() and disconnectNotify() to
1101 change the value of ioRedirection (and related behaviour)
1102*/
1103void QProcess::setIoRedirection( bool value )
1104{
1105 ioRedirection = value;
1106 if ( ioRedirection ) {
1107 if ( d->notifierStdout )
1108 d->notifierStdout->setEnabled( TRUE );
1109 if ( d->notifierStderr )
1110 d->notifierStderr->setEnabled( TRUE );
1111 } else {
1112 if ( d->notifierStdout )
1113 d->notifierStdout->setEnabled( FALSE );
1114 if ( d->notifierStderr )
1115 d->notifierStderr->setEnabled( FALSE );
1116 }
1117}
1118
1119/*
1120 This private function is used by connectNotify() and
1121 disconnectNotify() to change the value of notifyOnExit (and related
1122 behaviour)
1123*/
1124void QProcess::setNotifyOnExit( bool value )
1125{
1126 notifyOnExit = value;
1127}
1128
1129/*
1130 This private function is used by connectNotify() and disconnectNotify() to
1131 change the value of wroteToStdinConnected (and related behaviour)
1132*/
1133void QProcess::setWroteStdinConnected( bool value )
1134{
1135 wroteToStdinConnected = value;
1136}
1137
1138/*! \enum QProcess::PID
1139 \internal
1140*/
1141/*!
1142 Returns platform dependent information about the process. This can be used
1143 together with platform specific system calls.
1144
1145 Under Unix the return value is the PID of the process, or -1 if no process is
1146 belonging to this object.
1147
1148 Under Windows it is a pointer to the \c PROCESS_INFORMATION struct, or 0 if
1149 no process is belonging to this object.
1150*/
1151QProcess::PID QProcess::processIdentifier()
1152{
1153 if ( d->proc == 0 )
1154 return -1;
1155 return d->proc->pid;
1156}
1157
1158#endif // QT_NO_PROCESS
diff --git a/core/launcher/transferserver.cpp b/core/launcher/transferserver.cpp
index cbda247..0337a94 100644
--- a/core/launcher/transferserver.cpp
+++ b/core/launcher/transferserver.cpp
@@ -9,1381 +9,1416 @@
9** packaging of this file. 9** packaging of this file.
10** 10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 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. 12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13** 13**
14** See http://www.trolltech.com/gpl/ for GPL licensing information. 14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15** 15**
16** Contact info@trolltech.com if any conditions of this licensing are 16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you. 17** not clear to you.
18** 18**
19**********************************************************************/ 19**********************************************************************/
20#define _XOPEN_SOURCE 20#define _XOPEN_SOURCE
21#include <pwd.h> 21#include <pwd.h>
22#include <sys/types.h> 22#include <sys/types.h>
23#include <unistd.h> 23#include <unistd.h>
24#include <stdlib.h> 24#include <stdlib.h>
25#include <time.h> 25#include <time.h>
26#include <shadow.h> 26#include <shadow.h>
27 27
28/* we need the _OS_LINUX stuff first ! */ 28/* we need the _OS_LINUX stuff first ! */
29#include <qglobal.h> 29#include <qglobal.h>
30 30
31#ifndef _OS_LINUX_ 31#ifndef _OS_LINUX_
32 32
33extern "C" { 33extern "C"
34{
34#include <uuid/uuid.h> 35#include <uuid/uuid.h>
35#define UUID_H_INCLUDED 36#define UUID_H_INCLUDED
36} 37}
37 38
38#endif // not defined linux 39#endif // not defined linux
39 40
40#if defined(_OS_LINUX_) 41#if defined(_OS_LINUX_)
41#include <shadow.h> 42#include <shadow.h>
42#endif 43#endif
43 44
44#include <qdir.h> 45#include <qdir.h>
45#include <qfile.h> 46#include <qfile.h>
46#include <qtextstream.h> 47#include <qtextstream.h>
47#include <qdatastream.h> 48#include <qdatastream.h>
48#include <qmessagebox.h> 49#include <qmessagebox.h>
49#include <qstringlist.h> 50#include <qstringlist.h>
50#include <qfileinfo.h> 51#include <qfileinfo.h>
51#include <qregexp.h> 52#include <qregexp.h>
52//#include <qpe/qcopchannel_qws.h> 53//#include <qpe/qcopchannel_qws.h>
53#include <qpe/process.h> 54#include <qpe/process.h>
54#include <qpe/global.h> 55#include <qpe/global.h>
55#include <qpe/config.h> 56#include <qpe/config.h>
56#include <qpe/contact.h> 57#include <qpe/contact.h>
57#include <qpe/quuid.h> 58#include <qpe/quuid.h>
58#include <qpe/version.h> 59#include <qpe/version.h>
59#include <qpe/qcopenvelope_qws.h> 60#include <qpe/qcopenvelope_qws.h>
60 61
61#include "transferserver.h" 62#include "transferserver.h"
62#include "qprocess.h" 63#include <opie/oprocess.h>
63 64
64const int block_size = 51200; 65const int block_size = 51200;
65 66
66TransferServer::TransferServer( Q_UINT16 port, QObject *parent , 67TransferServer::TransferServer( Q_UINT16 port, QObject *parent ,
67 const char* name ) 68 const char* name )
68 : QServerSocket( port, 1, parent, name ) 69 : QServerSocket( port, 1, parent, name )
69{ 70{
70 if ( !ok() ) 71 if ( !ok() )
71 qWarning( "Failed to bind to port %d", port ); 72 qWarning( "Failed to bind to port %d", port );
72} 73}
73 74
74TransferServer::~TransferServer() 75TransferServer::~TransferServer()
75{ 76{
76
77} 77}
78 78
79void TransferServer::newConnection( int socket ) 79void TransferServer::newConnection( int socket )
80{ 80{
81 (void) new ServerPI( socket, this ); 81 (void) new ServerPI( socket, this );
82} 82}
83 83
84/* 84/*
85 * small class in anonymous namespace 85 * small class in anonymous namespace
86 * to generate a QUUid for us 86 * to generate a QUUid for us
87 */ 87 */
88namespace { 88namespace
89 struct UidGen { 89{
90 QString uuid(); 90struct UidGen
91 }; 91{
92 QString uuid();
93};
92#if !defined(_OS_LINUX_) 94#if !defined(_OS_LINUX_)
93 QString UidGen::uuid() { 95
94 uuid_t uuid; 96QString UidGen::uuid()
95 uuid_generate( uuid ); 97{
96 return QUUid( uuid ).toString(); 98 uuid_t uuid;
97 } 99 uuid_generate( uuid );
100 return QUUid( uuid ).toString();
101}
98#else 102#else
99 /* 103/*
100 * linux got a /proc/sys/kernel/random/uuid file 104* linux got a /proc/sys/kernel/random/uuid file
101 * it'll generate the uuids for us 105* it'll generate the uuids for us
102 */ 106*/
103 QString UidGen::uuid() { 107QString UidGen::uuid()
104 QFile file( "/proc/sys/kernel/random/uuid" ); 108{
105 if (!file.open(IO_ReadOnly ) ) 109 QFile file( "/proc/sys/kernel/random/uuid" );
106 return QString::null; 110 if (!file.open(IO_ReadOnly ) )
107 111 return QString::null;
108 QTextStream stream(&file); 112
109 113 QTextStream stream(&file);
110 return "{" + stream.read().stripWhiteSpace() + "}"; 114
111 } 115 return "{" + stream.read().stripWhiteSpace() + "}";
116}
112#endif 117#endif
113} 118}
114 119
115QString SyncAuthentication::serverId() 120QString SyncAuthentication::serverId()
116{ 121{
117 Config cfg("Security"); 122 Config cfg("Security");
118 cfg.setGroup("Sync"); 123 cfg.setGroup("Sync");
119 QString r=cfg.readEntry("serverid"); 124 QString r = cfg.readEntry("serverid");
120 if ( r.isEmpty() ) { 125 if ( r.isEmpty() ) {
121 UidGen gen; 126 UidGen gen;
122 r = gen.uuid(); 127 r = gen.uuid();
123 cfg.writeEntry("serverid", r ); 128 cfg.writeEntry("serverid", r );
124 } 129 }
125 return r; 130 return r;
126} 131}
127 132
128QString SyncAuthentication::ownerName() 133QString SyncAuthentication::ownerName()
129{ 134{
130 QString vfilename = Global::applicationFileName("addressbook", 135 QString vfilename = Global::applicationFileName("addressbook",
131 "businesscard.vcf"); 136 "businesscard.vcf");
132 if (QFile::exists(vfilename)) { 137 if (QFile::exists(vfilename)) {
133 Contact c; 138 Contact c;
134 c = Contact::readVCard( vfilename )[0]; 139 c = Contact::readVCard( vfilename )[0];
135 return c.fullName(); 140 return c.fullName();
136 } 141 }
137 142
138 return ""; 143 return "";
139} 144}
140 145
141QString SyncAuthentication::loginName() 146QString SyncAuthentication::loginName()
142{ 147{
143 struct passwd *pw; 148 struct passwd *pw;
144 pw = getpwuid( geteuid() ); 149 pw = getpwuid( geteuid() );
145 return QString::fromLocal8Bit( pw->pw_name ); 150 return QString::fromLocal8Bit( pw->pw_name );
146} 151}
147 152
148int SyncAuthentication::isAuthorized(QHostAddress peeraddress) 153int SyncAuthentication::isAuthorized(QHostAddress peeraddress)
149{ 154{
150 Config cfg("Security"); 155 Config cfg("Security");
151 cfg.setGroup("Sync"); 156 cfg.setGroup("Sync");
152// QString allowedstr = cfg.readEntry("auth_peer","192.168.1.0"); 157 // QString allowedstr = cfg.readEntry("auth_peer","192.168.1.0");
153 uint auth_peer = cfg.readNumEntry("auth_peer",0xc0a80100); 158 uint auth_peer = cfg.readNumEntry("auth_peer", 0xc0a80100);
154 159
155// QHostAddress allowed; 160 // QHostAddress allowed;
156// allowed.setAddress(allowedstr); 161 // allowed.setAddress(allowedstr);
157// uint auth_peer = allowed.ip4Addr(); 162 // uint auth_peer = allowed.ip4Addr();
158 uint auth_peer_bits = cfg.readNumEntry("auth_peer_bits",24); 163 uint auth_peer_bits = cfg.readNumEntry("auth_peer_bits", 24);
159 uint mask = auth_peer_bits >= 32 // shifting by 32 is not defined 164 uint mask = auth_peer_bits >= 32 // shifting by 32 is not defined
160 ? 0xffffffff : (((1<<auth_peer_bits)-1)<<(32-auth_peer_bits)); 165 ? 0xffffffff : (((1 << auth_peer_bits) - 1) << (32 - auth_peer_bits));
161 return (peeraddress.ip4Addr() & mask) == auth_peer; 166 return (peeraddress.ip4Addr() & mask) == auth_peer;
162} 167}
163 168
164bool SyncAuthentication::checkUser( const QString& user ) 169bool SyncAuthentication::checkUser( const QString& user )
165{ 170{
166 if ( user.isEmpty() ) return FALSE; 171 if ( user.isEmpty() )
167 QString euser = loginName(); 172 return FALSE;
168 return user == euser; 173 QString euser = loginName();
174 return user == euser;
169} 175}
170 176
171bool SyncAuthentication::checkPassword( const QString& password ) 177bool SyncAuthentication::checkPassword( const QString& password )
172{ 178{
173#ifdef ALLOW_UNIX_USER_FTP 179#ifdef ALLOW_UNIX_USER_FTP
174 // First, check system password... 180 // First, check system password...
175 181
176 struct passwd *pw = 0; 182 struct passwd *pw = 0;
177 struct spwd *spw = 0; 183 struct spwd *spw = 0;
178 184
179 pw = getpwuid( geteuid() ); 185 pw = getpwuid( geteuid() );
180 spw = getspnam( pw->pw_name ); 186 spw = getspnam( pw->pw_name );
181 187
182 QString cpwd = QString::fromLocal8Bit( pw->pw_passwd ); 188 QString cpwd = QString::fromLocal8Bit( pw->pw_passwd );
183 if ( cpwd == "x" && spw ) 189 if ( cpwd == "x" && spw )
184 cpwd = QString::fromLocal8Bit( spw->sp_pwdp ); 190 cpwd = QString::fromLocal8Bit( spw->sp_pwdp );
185 191
186 // Note: some systems use more than crypt for passwords. 192 // Note: some systems use more than crypt for passwords.
187 QString cpassword = QString::fromLocal8Bit( crypt( password.local8Bit(), cpwd.local8Bit() ) ); 193 QString cpassword = QString::fromLocal8Bit( crypt( password.local8Bit(), cpwd.local8Bit() ) );
188 if ( cpwd == cpassword ) 194 if ( cpwd == cpassword )
189 return TRUE; 195 return TRUE;
190#endif 196#endif
191 197
192 static int lastdenial=0; 198 static int lastdenial = 0;
193 static int denials=0; 199 static int denials = 0;
194 int now = time(0); 200 int now = time(0);
195 201
196 // Detect old Qtopia Desktop (no password) 202 // Detect old Qtopia Desktop (no password)
197 if ( password.isEmpty() ) { 203 if ( password.isEmpty() ) {
198 if ( denials < 1 || now > lastdenial+600 ) { 204 if ( denials < 1 || now > lastdenial + 600 ) {
199 QMessageBox::warning( 0,tr("Sync Connection"), 205 QMessageBox::warning( 0, tr("Sync Connection"),
200 tr("<p>An unauthorized system is requesting access to this device." 206 tr("<p>An unauthorized system is requesting access to this device."
201 "<p>If you are using a version of Qtopia Desktop older than 1.5.1, " 207 "<p>If you are using a version of Qtopia Desktop older than 1.5.1, "
202 "please upgrade."), 208 "please upgrade."),
203 tr("Deny") ); 209 tr("Deny") );
204 denials++; 210 denials++;
205 lastdenial=now; 211 lastdenial = now;
206 } 212 }
207 return FALSE; 213 return FALSE;
208 } 214 }
209 215
210 // Second, check sync password... 216 // Second, check sync password...
211 QString pass = password.left(6); 217 QString pass = password.left(6);
212 /* old QtopiaDesktops are sending 218 /* old QtopiaDesktops are sending
213 * rootme newer versions got a Qtopia 219 * rootme newer versions got a Qtopia
214 * prefixed. Qtopia prefix will suceed 220 * prefixed. Qtopia prefix will suceed
215 * until the sync software syncs up 221 * until the sync software syncs up
216 * FIXME 222 * FIXME
217 */ 223 */
218 if ( pass == "rootme" || pass == "Qtopia") { 224 if ( pass == "rootme" || pass == "Qtopia") {
219 225
220 QString cpassword = QString::fromLocal8Bit( crypt( password.mid(8).local8Bit(), "qp" ) ); 226 QString cpassword = QString::fromLocal8Bit( crypt( password.mid(8).local8Bit(), "qp" ) );
221 Config cfg("Security"); 227 Config cfg("Security");
222 cfg.setGroup("Sync"); 228 cfg.setGroup("Sync");
223 QString pwds = cfg.readEntry("Passwords"); 229 QString pwds = cfg.readEntry("Passwords");
224 if ( QStringList::split(QChar(' '),pwds).contains(cpassword) ) 230 if ( QStringList::split(QChar(' '), pwds).contains(cpassword) )
225 return TRUE; 231 return TRUE;
226 232
227 // Unrecognized system. Be careful... 233 // Unrecognized system. Be careful...
228 234
229 if ( (denials > 2 && now < lastdenial+600) 235 if ( (denials > 2 && now < lastdenial + 600)
230 || QMessageBox::warning(0,tr("Sync Connection"), 236 || QMessageBox::warning(0, tr("Sync Connection"),
231 tr("<p>An unrecognized system is requesting access to this device." 237 tr("<p>An unrecognized system is requesting access to this device."
232 "<p>If you have just initiated a Sync for the first time, this is normal."), 238 "<p>If you have just initiated a Sync for the first time, this is normal."),
233 tr("Allow"),tr("Deny"), 0, 1, 1 ) ==1 ) 239 tr("Allow"), tr("Deny"), 0, 1, 1 ) == 1 ) {
234 { 240 denials++;
235 denials++; 241 lastdenial = now;
236 lastdenial=now; 242 return FALSE;
237 return FALSE; 243 }
238 } else { 244 else {
239 denials=0; 245 denials = 0;
240 cfg.writeEntry("Passwords",pwds+" "+cpassword); 246 cfg.writeEntry("Passwords", pwds + " " + cpassword);
241 return TRUE; 247 return TRUE;
242 } 248 }
243 } 249 }
244 250
245 return FALSE; 251 return FALSE;
246} 252}
247 253
248ServerPI::ServerPI( int socket, QObject *parent , const char* name ) 254ServerPI::ServerPI( int socket, QObject *parent , const char* name )
249 : QSocket( parent, name ) , dtp( 0 ), serversocket( 0 ), waitsocket( 0 ) 255 : QSocket( parent, name ) , dtp( 0 ), serversocket( 0 ), waitsocket( 0 )
250{ 256{
251 state = Connected; 257 state = Connected;
252 258
253 setSocket( socket ); 259 setSocket( socket );
254 260
255 peerport = peerPort(); 261 peerport = peerPort();
256 peeraddress = peerAddress(); 262 peeraddress = peerAddress();
257 263
258#ifndef INSECURE 264#ifndef INSECURE
259 if ( !SyncAuthentication::isAuthorized(peeraddress) ) { 265
260 state = Forbidden; 266 if ( !SyncAuthentication::isAuthorized(peeraddress) ) {
261 startTimer( 0 ); 267 state = Forbidden;
262 } else 268 startTimer( 0 );
269 }
270 else
263#endif 271#endif
264 { 272 {
265 connect( this, SIGNAL( readyRead() ), SLOT( read() ) ); 273 connect( this, SIGNAL( readyRead() ), SLOT( read() ) );
266 connect( this, SIGNAL( connectionClosed() ), SLOT( connectionClosed() ) ); 274 connect( this, SIGNAL( connectionClosed() ), SLOT( connectionClosed() ) );
267 275
268 passiv = FALSE; 276 passiv = FALSE;
269 for( int i = 0; i < 4; i++ ) 277 for ( int i = 0; i < 4; i++ )
270 wait[i] = FALSE; 278 wait[i] = FALSE;
271 279
272 send( "220 Qtopia " QPE_VERSION " FTP Server" ); 280 send( "220 Qtopia " QPE_VERSION " FTP Server" );
273 state = Wait_USER; 281 state = Wait_USER;
274 282
275 dtp = new ServerDTP( this ); 283 dtp = new ServerDTP( this );
276 connect( dtp, SIGNAL( completed() ), SLOT( dtpCompleted() ) ); 284 connect( dtp, SIGNAL( completed() ), SLOT( dtpCompleted() ) );
277 connect( dtp, SIGNAL( failed() ), SLOT( dtpFailed() ) ); 285 connect( dtp, SIGNAL( failed() ), SLOT( dtpFailed() ) );
278 connect( dtp, SIGNAL( error( int ) ), SLOT( dtpError( int ) ) ); 286 connect( dtp, SIGNAL( error( int ) ), SLOT( dtpError( int ) ) );
279 287
280 288
281 directory = QDir::currentDirPath(); 289 directory = QDir::currentDirPath();
282 290
283 static int p = 1024; 291 static int p = 1024;
284 292
285 while ( !serversocket || !serversocket->ok() ) { 293 while ( !serversocket || !serversocket->ok() ) {
286 delete serversocket; 294 delete serversocket;
287 serversocket = new ServerSocket( ++p, this ); 295 serversocket = new ServerSocket( ++p, this );
288 } 296 }
289 connect( serversocket, SIGNAL( newIncomming( int ) ), 297 connect( serversocket, SIGNAL( newIncomming( int ) ),
290 SLOT( newConnection( int ) ) ); 298 SLOT( newConnection( int ) ) );
291 } 299 }
292} 300}
293 301
294ServerPI::~ServerPI() 302ServerPI::~ServerPI()
295{ 303{
296
297} 304}
298 305
299void ServerPI::connectionClosed() 306void ServerPI::connectionClosed()
300{ 307{
301 // qDebug( "Debug: Connection closed" ); 308 // qDebug( "Debug: Connection closed" );
302 delete this; 309 delete this;
303} 310}
304 311
305void ServerPI::send( const QString& msg ) 312void ServerPI::send( const QString& msg )
306{ 313{
307 QTextStream os( this ); 314 QTextStream os( this );
308 os << msg << endl; 315 os << msg << endl;
309 //qDebug( "Reply: %s", msg.latin1() ); 316 //qDebug( "Reply: %s", msg.latin1() );
310} 317}
311 318
312void ServerPI::read() 319void ServerPI::read()
313{ 320{
314 while ( canReadLine() ) 321 while ( canReadLine() )
315 process( readLine().stripWhiteSpace() ); 322 process( readLine().stripWhiteSpace() );
316} 323}
317 324
318bool ServerPI::checkReadFile( const QString& file ) 325bool ServerPI::checkReadFile( const QString& file )
319{ 326{
320 QString filename; 327 QString filename;
321 328
322 if ( file[0] != "/" ) 329 if ( file[0] != "/" )
323 filename = directory.path() + "/" + file; 330 filename = directory.path() + "/" + file;
324 else 331 else
325 filename = file; 332 filename = file;
326 333
327 QFileInfo fi( filename ); 334 QFileInfo fi( filename );
328 return ( fi.exists() && fi.isReadable() ); 335 return ( fi.exists() && fi.isReadable() );
329} 336}
330 337
331bool ServerPI::checkWriteFile( const QString& file ) 338bool ServerPI::checkWriteFile( const QString& file )
332{ 339{
333 QString filename; 340 QString filename;
334 341
335 if ( file[0] != "/" ) 342 if ( file[0] != "/" )
336 filename = directory.path() + "/" + file; 343 filename = directory.path() + "/" + file;
337 else 344 else
338 filename = file; 345 filename = file;
339 346
340 QFileInfo fi( filename ); 347 QFileInfo fi( filename );
341 348
342 if ( fi.exists() ) 349 if ( fi.exists() )
343 if ( !QFile( filename ).remove() ) 350 if ( !QFile( filename ).remove() )
344 return FALSE; 351 return FALSE;
345 return TRUE; 352 return TRUE;
346} 353}
347 354
348void ServerPI::process( const QString& message ) 355void ServerPI::process( const QString& message )
349{ 356{
350 //qDebug( "Command: %s", message.latin1() ); 357 //qDebug( "Command: %s", message.latin1() );
351 358
352 // split message using "," as separator 359 // split message using "," as separator
353 QStringList msg = QStringList::split( " ", message ); 360 QStringList msg = QStringList::split( " ", message );
354 if ( msg.isEmpty() ) return; 361 if ( msg.isEmpty() )
355 362 return ;
356 // command token 363
357 QString cmd = msg[0].upper(); 364 // command token
358 365 QString cmd = msg[0].upper();
359 // argument token 366
360 QString arg; 367 // argument token
361 if ( msg.count() >= 2 ) 368 QString arg;
362 arg = msg[1]; 369 if ( msg.count() >= 2 )
363 370 arg = msg[1];
364 // full argument string 371
365 QString args; 372 // full argument string
366 if ( msg.count() >= 2 ) { 373 QString args;
367 QStringList copy( msg ); 374 if ( msg.count() >= 2 ) {
368 // FIXME: for Qt3 375 QStringList copy( msg );
369 // copy.pop_front() 376 // FIXME: for Qt3
370 copy.remove( copy.begin() ); 377 // copy.pop_front()
371 args = copy.join( " " ); 378 copy.remove( copy.begin() );
372 } 379 args = copy.join( " " );
373 380 }
374 //qDebug( "args: %s", args.latin1() ); 381
375 382 //qDebug( "args: %s", args.latin1() );
376 // we always respond to QUIT, regardless of state 383
377 if ( cmd == "QUIT" ) { 384 // we always respond to QUIT, regardless of state
378 send( "211 Good bye!" ); 385 if ( cmd == "QUIT" ) {
379 delete this; 386 send( "211 Good bye!" );
380 return; 387 delete this;
381 } 388 return ;
382 389 }
383 // connected to client 390
384 if ( Connected == state ) 391 // connected to client
385 return; 392 if ( Connected == state )
386 393 return ;
387 // waiting for user name 394
388 if ( Wait_USER == state ) { 395 // waiting for user name
389 396 if ( Wait_USER == state ) {
390 if ( cmd != "USER" || msg.count() < 2 || !SyncAuthentication::checkUser( arg ) ) { 397
391 send( "530 Please login with USER and PASS" ); 398 if ( cmd != "USER" || msg.count() < 2 || !SyncAuthentication::checkUser( arg ) ) {
392 return; 399 send( "530 Please login with USER and PASS" );
393 } 400 return ;
394 send( "331 User name ok, need password" ); 401 }
395 state = Wait_PASS; 402 send( "331 User name ok, need password" );
396 return; 403 state = Wait_PASS;
397 } 404 return ;
398 405 }
399 // waiting for password 406
400 if ( Wait_PASS == state ) { 407 // waiting for password
401 408 if ( Wait_PASS == state ) {
402 if ( cmd != "PASS" || !SyncAuthentication::checkPassword( arg ) ) { 409
403 send( "530 Please login with USER and PASS" ); 410 if ( cmd != "PASS" || !SyncAuthentication::checkPassword( arg ) ) {
404 return; 411 send( "530 Please login with USER and PASS" );
405 } 412 return ;
406 send( "230 User logged in, proceed" ); 413 }
407 state = Ready; 414 send( "230 User logged in, proceed" );
408 return; 415 state = Ready;
409 } 416 return ;
410 417 }
411 // ACCESS CONTROL COMMANDS 418
412 419 // ACCESS CONTROL COMMANDS
413 420
414 // account (ACCT) 421
415 if ( cmd == "ACCT" ) { 422 // account (ACCT)
416 // even wu-ftp does not support it 423 if ( cmd == "ACCT" ) {
417 send( "502 Command not implemented" ); 424 // even wu-ftp does not support it
418 } 425 send( "502 Command not implemented" );
419 426 }
420 // change working directory (CWD) 427
421 else if ( cmd == "CWD" ) { 428 // change working directory (CWD)
422 429 else if ( cmd == "CWD" ) {
423 if ( !args.isEmpty() ) { 430
424 if ( directory.cd( args, TRUE ) ) 431 if ( !args.isEmpty() ) {
425 send( "250 Requested file action okay, completed" ); 432 if ( directory.cd( args, TRUE ) )
426 else 433 send( "250 Requested file action okay, completed" );
427 send( "550 Requested action not taken" ); 434 else
428 } 435 send( "550 Requested action not taken" );
429 else 436 }
430 send( "500 Syntax error, command unrecognized" ); 437 else
431 } 438 send( "500 Syntax error, command unrecognized" );
432 439 }
433 // change to parent directory (CDUP) 440
434 else if ( cmd == "CDUP" ) { 441 // change to parent directory (CDUP)
435 if ( directory.cdUp() ) 442 else if ( cmd == "CDUP" ) {
436 send( "250 Requested file action okay, completed" ); 443 if ( directory.cdUp() )
437 else 444 send( "250 Requested file action okay, completed" );
438 send( "550 Requested action not taken" ); 445 else
439 } 446 send( "550 Requested action not taken" );
440 447 }
441 // structure mount (SMNT) 448
442 else if ( cmd == "SMNT" ) { 449 // structure mount (SMNT)
443 // even wu-ftp does not support it 450 else if ( cmd == "SMNT" ) {
444 send( "502 Command not implemented" ); 451 // even wu-ftp does not support it
445 } 452 send( "502 Command not implemented" );
446 453 }
447 // reinitialize (REIN) 454
448 else if ( cmd == "REIN" ) { 455 // reinitialize (REIN)
449 // even wu-ftp does not support it 456 else if ( cmd == "REIN" ) {
450 send( "502 Command not implemented" ); 457 // even wu-ftp does not support it
451 } 458 send( "502 Command not implemented" );
452 459 }
453 460
454 // TRANSFER PARAMETER COMMANDS 461
455 462 // TRANSFER PARAMETER COMMANDS
456 463
457 // data port (PORT) 464
458 else if ( cmd == "PORT" ) { 465 // data port (PORT)
459 if ( parsePort( arg ) ) 466 else if ( cmd == "PORT" ) {
460 send( "200 Command okay" ); 467 if ( parsePort( arg ) )
461 else 468 send( "200 Command okay" );
462 send( "500 Syntax error, command unrecognized" ); 469 else
463 } 470 send( "500 Syntax error, command unrecognized" );
464 471 }
465 // passive (PASV) 472
466 else if ( cmd == "PASV" ) { 473 // passive (PASV)
467 passiv = TRUE; 474 else if ( cmd == "PASV" ) {
468 send( "227 Entering Passive Mode (" 475 passiv = TRUE;
469 + address().toString().replace( QRegExp( "\\." ), "," ) + "," 476 send( "227 Entering Passive Mode ("
470 + QString::number( ( serversocket->port() ) >> 8 ) + "," 477 + address().toString().replace( QRegExp( "\\." ), "," ) + ","
471 + QString::number( ( serversocket->port() ) & 0xFF ) +")" ); 478 + QString::number( ( serversocket->port() ) >> 8 ) + ","
472 } 479 + QString::number( ( serversocket->port() ) & 0xFF ) + ")" );
473 480 }
474 // representation type (TYPE) 481
475 else if ( cmd == "TYPE" ) { 482 // representation type (TYPE)
476 if ( arg.upper() == "A" || arg.upper() == "I" ) 483 else if ( cmd == "TYPE" ) {
477 send( "200 Command okay" ); 484 if ( arg.upper() == "A" || arg.upper() == "I" )
478 else 485 send( "200 Command okay" );
479 send( "504 Command not implemented for that parameter" ); 486 else
480 } 487 send( "504 Command not implemented for that parameter" );
481 488 }
482 // file structure (STRU) 489
483 else if ( cmd == "STRU" ) { 490 // file structure (STRU)
484 if ( arg.upper() == "F" ) 491 else if ( cmd == "STRU" ) {
485 send( "200 Command okay" ); 492 if ( arg.upper() == "F" )
486 else 493 send( "200 Command okay" );
487 send( "504 Command not implemented for that parameter" ); 494 else
488 } 495 send( "504 Command not implemented for that parameter" );
489 496 }
490 // transfer mode (MODE) 497
491 else if ( cmd == "MODE" ) { 498 // transfer mode (MODE)
492 if ( arg.upper() == "S" ) 499 else if ( cmd == "MODE" ) {
493 send( "200 Command okay" ); 500 if ( arg.upper() == "S" )
494 else 501 send( "200 Command okay" );
495 send( "504 Command not implemented for that parameter" ); 502 else
496 } 503 send( "504 Command not implemented for that parameter" );
497 504 }
498 505
499 // FTP SERVICE COMMANDS 506
500 507 // FTP SERVICE COMMANDS
501 508
502 // retrieve (RETR) 509
503 else if ( cmd == "RETR" ) 510 // retrieve (RETR)
504 if ( !args.isEmpty() && checkReadFile( absFilePath( args ) ) 511 else if ( cmd == "RETR" )
505 || backupRestoreGzip( absFilePath( args ) ) ) { 512 if ( !args.isEmpty() && checkReadFile( absFilePath( args ) )
506 send( "150 File status okay" ); 513 || backupRestoreGzip( absFilePath( args ) ) ) {
507 sendFile( absFilePath( args ) ); 514 send( "150 File status okay" );
508 } 515 sendFile( absFilePath( args ) );
509 else { 516 }
510 qDebug("550 Requested action not taken"); 517 else {
511 send( "550 Requested action not taken" ); 518 qDebug("550 Requested action not taken");
512 } 519 send( "550 Requested action not taken" );
513 520 }
514 // store (STOR) 521
515 else if ( cmd == "STOR" ) 522 // store (STOR)
516 if ( !args.isEmpty() && checkWriteFile( absFilePath( args ) ) ) { 523 else if ( cmd == "STOR" )
517 send( "150 File status okay" ); 524 if ( !args.isEmpty() && checkWriteFile( absFilePath( args ) ) ) {
518 retrieveFile( absFilePath( args ) ); 525 send( "150 File status okay" );
519 } 526 retrieveFile( absFilePath( args ) );
520 else 527 }
521 send( "550 Requested action not taken" ); 528 else
522 529 send( "550 Requested action not taken" );
523 // store unique (STOU) 530
524 else if ( cmd == "STOU" ) { 531 // store unique (STOU)
525 send( "502 Command not implemented" ); 532 else if ( cmd == "STOU" ) {
526 } 533 send( "502 Command not implemented" );
527 534 }
528 // append (APPE) 535
529 else if ( cmd == "APPE" ) { 536 // append (APPE)
530 send( "502 Command not implemented" ); 537 else if ( cmd == "APPE" ) {
531 } 538 send( "502 Command not implemented" );
532 539 }
533 // allocate (ALLO) 540
534 else if ( cmd == "ALLO" ) { 541 // allocate (ALLO)
535 send( "200 Command okay" ); 542 else if ( cmd == "ALLO" ) {
536 } 543 send( "200 Command okay" );
537 544 }
538 // restart (REST) 545
539 else if ( cmd == "REST" ) { 546 // restart (REST)
540 send( "502 Command not implemented" ); 547 else if ( cmd == "REST" ) {
541 } 548 send( "502 Command not implemented" );
542 549 }
543 // rename from (RNFR) 550
544 else if ( cmd == "RNFR" ) { 551 // rename from (RNFR)
545 renameFrom = QString::null; 552 else if ( cmd == "RNFR" ) {
546 if ( args.isEmpty() ) 553 renameFrom = QString::null;
547 send( "500 Syntax error, command unrecognized" ); 554 if ( args.isEmpty() )
548 else { 555 send( "500 Syntax error, command unrecognized" );
549 QFile file( absFilePath( args ) ); 556 else {
550 if ( file.exists() ) { 557 QFile file( absFilePath( args ) );
551 send( "350 File exists, ready for destination name" ); 558 if ( file.exists() ) {
552 renameFrom = absFilePath( args ); 559 send( "350 File exists, ready for destination name" );
553 } 560 renameFrom = absFilePath( args );
554 else 561 }
555 send( "550 Requested action not taken" ); 562 else
556 } 563 send( "550 Requested action not taken" );
557 } 564 }
558 565 }
559 // rename to (RNTO) 566
560 else if ( cmd == "RNTO" ) { 567 // rename to (RNTO)
561 if ( lastCommand != "RNFR" ) 568 else if ( cmd == "RNTO" ) {
562 send( "503 Bad sequence of commands" ); 569 if ( lastCommand != "RNFR" )
563 else if ( args.isEmpty() ) 570 send( "503 Bad sequence of commands" );
564 send( "500 Syntax error, command unrecognized" ); 571 else if ( args.isEmpty() )
565 else { 572 send( "500 Syntax error, command unrecognized" );
566 QDir dir( absFilePath( args ) ); 573 else {
567 if ( dir.rename( renameFrom, absFilePath( args ), TRUE ) ) 574 QDir dir( absFilePath( args ) );
568 send( "250 Requested file action okay, completed." ); 575 if ( dir.rename( renameFrom, absFilePath( args ), TRUE ) )
569 else 576 send( "250 Requested file action okay, completed." );
570 send( "550 Requested action not taken" ); 577 else
571 } 578 send( "550 Requested action not taken" );
572 } 579 }
573 580 }
574 // abort (ABOR) 581
575 else if ( cmd.contains( "ABOR" ) ) { 582 // abort (ABOR)
576 dtp->close(); 583 else if ( cmd.contains( "ABOR" ) ) {
577 if ( dtp->dtpMode() != ServerDTP::Idle ) 584 dtp->close();
578 send( "426 Connection closed; transfer aborted" ); 585 if ( dtp->dtpMode() != ServerDTP::Idle )
579 else 586 send( "426 Connection closed; transfer aborted" );
580 send( "226 Closing data connection" ); 587 else
581 } 588 send( "226 Closing data connection" );
582 589 }
583 // delete (DELE) 590
584 else if ( cmd == "DELE" ) { 591 // delete (DELE)
585 if ( args.isEmpty() ) 592 else if ( cmd == "DELE" ) {
586 send( "500 Syntax error, command unrecognized" ); 593 if ( args.isEmpty() )
587 else { 594 send( "500 Syntax error, command unrecognized" );
588 QFile file( absFilePath( args ) ) ; 595 else {
589 if ( file.remove() ) { 596 QFile file( absFilePath( args ) ) ;
590 send( "250 Requested file action okay, completed" ); 597 if ( file.remove() ) {
591 QCopEnvelope e("QPE/System", "linkChanged(QString)" ); 598 send( "250 Requested file action okay, completed" );
592 e << file.name(); 599 QCopEnvelope e("QPE/System", "linkChanged(QString)" );
593 } else { 600 e << file.name();
594 send( "550 Requested action not taken" ); 601 }
595 } 602 else {
596 } 603 send( "550 Requested action not taken" );
597 } 604 }
598 605 }
599 // remove directory (RMD) 606 }
600 else if ( cmd == "RMD" ) { 607
601 if ( args.isEmpty() ) 608 // remove directory (RMD)
602 send( "500 Syntax error, command unrecognized" ); 609 else if ( cmd == "RMD" ) {
603 else { 610 if ( args.isEmpty() )
604 QDir dir; 611 send( "500 Syntax error, command unrecognized" );
605 if ( dir.rmdir( absFilePath( args ), TRUE ) ) 612 else {
606 send( "250 Requested file action okay, completed" ); 613 QDir dir;
607 else 614 if ( dir.rmdir( absFilePath( args ), TRUE ) )
608 send( "550 Requested action not taken" ); 615 send( "250 Requested file action okay, completed" );
609 } 616 else
610 } 617 send( "550 Requested action not taken" );
611 618 }
612 // make directory (MKD) 619 }
613 else if ( cmd == "MKD" ) { 620
614 if ( args.isEmpty() ) { 621 // make directory (MKD)
615 qDebug(" Error: no arg"); 622 else if ( cmd == "MKD" ) {
616 send( "500 Syntax error, command unrecognized" ); 623 if ( args.isEmpty() ) {
617 } 624 qDebug(" Error: no arg");
618 else { 625 send( "500 Syntax error, command unrecognized" );
619 QDir dir; 626 }
620 if ( dir.mkdir( absFilePath( args ), TRUE ) ) 627 else {
621 send( "250 Requested file action okay, completed." ); 628 QDir dir;
622 else 629 if ( dir.mkdir( absFilePath( args ), TRUE ) )
623 send( "550 Requested action not taken" ); 630 send( "250 Requested file action okay, completed." );
624 } 631 else
625 } 632 send( "550 Requested action not taken" );
626 633 }
627 // print working directory (PWD) 634 }
628 else if ( cmd == "PWD" ) { 635
629 send( "257 \"" + directory.path() +"\"" ); 636 // print working directory (PWD)
630 } 637 else if ( cmd == "PWD" ) {
631 638 send( "257 \"" + directory.path() + "\"" );
632 // list (LIST) 639 }
633 else if ( cmd == "LIST" ) { 640
634 if ( sendList( absFilePath( args ) ) ) 641 // list (LIST)
635 send( "150 File status okay" ); 642 else if ( cmd == "LIST" ) {
636 else 643 if ( sendList( absFilePath( args ) ) )
637 send( "500 Syntax error, command unrecognized" ); 644 send( "150 File status okay" );
638 } 645 else
639 646 send( "500 Syntax error, command unrecognized" );
640 // size (SIZE) 647 }
641 else if ( cmd == "SIZE" ) { 648
642 QString filePath = absFilePath( args ); 649 // size (SIZE)
643 QFileInfo fi( filePath ); 650 else if ( cmd == "SIZE" ) {
644 bool gzipfile = backupRestoreGzip( filePath ); 651 QString filePath = absFilePath( args );
645 if ( !fi.exists() && !gzipfile ) 652 QFileInfo fi( filePath );
646 send( "500 Syntax error, command unrecognized" ); 653 bool gzipfile = backupRestoreGzip( filePath );
647 else { 654 if ( !fi.exists() && !gzipfile )
648 if ( !gzipfile ) 655 send( "500 Syntax error, command unrecognized" );
649 send( "213 " + QString::number( fi.size() ) ); 656 else {
650 else { 657 if ( !gzipfile )
651 Process duproc( QString("du") ); 658 send( "213 " + QString::number( fi.size() ) );
652 duproc.addArgument("-s"); 659 else {
653 QString in, out; 660 Process duproc( QString("du") );
654 if ( !duproc.exec(in, out) ) { 661 duproc.addArgument("-s");
655 qDebug("du process failed; just sending back 1K"); 662 QString in, out;
656 send( "213 1024"); 663 if ( !duproc.exec(in, out) ) {
657 } 664 qDebug("du process failed; just sending back 1K");
658 else { 665 send( "213 1024");
659 QString size = out.left( out.find("\t") ); 666 }
660 int guess = size.toInt()/5; 667 else {
661 if ( filePath.contains("doc") ) 668 QString size = out.left( out.find("\t") );
662 guess *= 1000; 669 int guess = size.toInt() / 5;
663 qDebug("sending back gzip guess of %d", guess); 670 if ( filePath.contains("doc") )
664 send( "213 " + QString::number(guess) ); 671 guess *= 1000;
665 } 672 qDebug("sending back gzip guess of %d", guess);
666 } 673 send( "213 " + QString::number(guess) );
667 } 674 }
668 } 675 }
669 // name list (NLST) 676 }
670 else if ( cmd == "NLST" ) { 677 }
671 send( "502 Command not implemented" ); 678 // name list (NLST)
672 } 679 else if ( cmd == "NLST" ) {
673 680 send( "502 Command not implemented" );
674 // site parameters (SITE) 681 }
675 else if ( cmd == "SITE" ) { 682
676 send( "502 Command not implemented" ); 683 // site parameters (SITE)
677 } 684 else if ( cmd == "SITE" ) {
678 685 send( "502 Command not implemented" );
679 // system (SYST) 686 }
680 else if ( cmd == "SYST" ) { 687
681 send( "215 UNIX Type: L8" ); 688 // system (SYST)
682 } 689 else if ( cmd == "SYST" ) {
683 690 send( "215 UNIX Type: L8" );
684 // status (STAT) 691 }
685 else if ( cmd == "STAT" ) { 692
686 send( "502 Command not implemented" ); 693 // status (STAT)
687 } 694 else if ( cmd == "STAT" ) {
688 695 send( "502 Command not implemented" );
689 // help (HELP ) 696 }
690 else if ( cmd == "HELP" ) { 697
691 send( "502 Command not implemented" ); 698 // help (HELP )
692 } 699 else if ( cmd == "HELP" ) {
693 700 send( "502 Command not implemented" );
694 // noop (NOOP) 701 }
695 else if ( cmd == "NOOP" ) { 702
696 send( "200 Command okay" ); 703 // noop (NOOP)
697 } 704 else if ( cmd == "NOOP" ) {
698 705 send( "200 Command okay" );
699 // not implemented 706 }
700 else 707
701 send( "502 Command not implemented" ); 708 // not implemented
702 709 else
703 lastCommand = cmd; 710 send( "502 Command not implemented" );
711
712 lastCommand = cmd;
704} 713}
705 714
706bool ServerPI::backupRestoreGzip( const QString &file ) 715bool ServerPI::backupRestoreGzip( const QString &file )
707{ 716{
708 return (file.find( "backup" ) != -1 && 717 return (file.find( "backup" ) != -1 &&
709 file.findRev( ".tgz" ) == (int)file.length()-4 ); 718 file.findRev( ".tgz" ) == (int)file.length() - 4 );
710} 719}
711 720
712bool ServerPI::backupRestoreGzip( const QString &file, QStringList &targets ) 721bool ServerPI::backupRestoreGzip( const QString &file, QStringList &targets )
713{ 722{
714 if ( file.find( "backup" ) != -1 && 723 if ( file.find( "backup" ) != -1 &&
715 file.findRev( ".tgz" ) == (int)file.length()-4 ) { 724 file.findRev( ".tgz" ) == (int)file.length() - 4 ) {
716 QFileInfo info( file ); 725 QFileInfo info( file );
717 targets = info.dirPath( TRUE ); 726 targets = info.dirPath( TRUE );
718 qDebug("ServerPI::backupRestoreGzip for %s = %s", file.latin1(), 727 qDebug("ServerPI::backupRestoreGzip for %s = %s", file.latin1(),
719 targets.join(" ").latin1() ); 728 targets.join(" ").latin1() );
720 return true; 729 return true;
721 } 730 }
722 return false; 731 return false;
723} 732}
724 733
725void ServerPI::sendFile( const QString& file ) 734void ServerPI::sendFile( const QString& file )
726{ 735{
727 if ( passiv ) { 736 if ( passiv ) {
728 wait[SendFile] = TRUE; 737 wait[SendFile] = TRUE;
729 waitfile = file; 738 waitfile = file;
730 if ( waitsocket ) 739 if ( waitsocket )
731 newConnection( waitsocket ); 740 newConnection( waitsocket );
732 } 741 }
733 else { 742 else {
734 QStringList targets; 743 QStringList targets;
735 if ( backupRestoreGzip( file, targets ) ) 744 if ( backupRestoreGzip( file, targets ) )
736 dtp->sendGzipFile( file, targets, peeraddress, peerport ); 745 dtp->sendGzipFile( file, targets, peeraddress, peerport );
737 else dtp->sendFile( file, peeraddress, peerport ); 746 else
738 } 747 dtp->sendFile( file, peeraddress, peerport );
748 }
739} 749}
740 750
741void ServerPI::retrieveFile( const QString& file ) 751void ServerPI::retrieveFile( const QString& file )
742{ 752{
743 if ( passiv ) { 753 if ( passiv ) {
744 wait[RetrieveFile] = TRUE; 754 wait[RetrieveFile] = TRUE;
745 waitfile = file; 755 waitfile = file;
746 if ( waitsocket ) 756 if ( waitsocket )
747 newConnection( waitsocket ); 757 newConnection( waitsocket );
748 } 758 }
749 else { 759 else {
750 QStringList targets; 760 QStringList targets;
751 if ( backupRestoreGzip( file, targets ) ) 761 if ( backupRestoreGzip( file, targets ) )
752 dtp->retrieveGzipFile( file, peeraddress, peerport ); 762 dtp->retrieveGzipFile( file, peeraddress, peerport );
753 else 763 else
754 dtp->retrieveFile( file, peeraddress, peerport ); 764 dtp->retrieveFile( file, peeraddress, peerport );
755 } 765 }
756} 766}
757 767
758bool ServerPI::parsePort( const QString& pp ) 768bool ServerPI::parsePort( const QString& pp )
759{ 769{
760 QStringList p = QStringList::split( ",", pp ); 770 QStringList p = QStringList::split( ",", pp );
761 if ( p.count() != 6 ) return FALSE; 771 if ( p.count() != 6 )
762 772 return FALSE;
763 // h1,h2,h3,h4,p1,p2 773
764 peeraddress = QHostAddress( ( p[0].toInt() << 24 ) + ( p[1].toInt() << 16 ) + 774 // h1,h2,h3,h4,p1,p2
765 ( p[2].toInt() << 8 ) + p[3].toInt() ); 775 peeraddress = QHostAddress( ( p[0].toInt() << 24 ) + ( p[1].toInt() << 16 ) +
766 peerport = ( p[4].toInt() << 8 ) + p[5].toInt(); 776 ( p[2].toInt() << 8 ) + p[3].toInt() );
767 return TRUE; 777 peerport = ( p[4].toInt() << 8 ) + p[5].toInt();
778 return TRUE;
768} 779}
769 780
770void ServerPI::dtpCompleted() 781void ServerPI::dtpCompleted()
771{ 782{
772 send( "226 Closing data connection, file transfer successful" ); 783 send( "226 Closing data connection, file transfer successful" );
773 if ( dtp->dtpMode() == ServerDTP::RetrieveFile ) { 784 if ( dtp->dtpMode() == ServerDTP::RetrieveFile ) {
774 QString fn = dtp->fileName(); 785 QString fn = dtp->fileName();
775 if ( fn.right(8)==".desktop" && fn.find("/Documents/")>=0 ) { 786 if ( fn.right(8) == ".desktop" && fn.find("/Documents/") >= 0 ) {
776 QCopEnvelope e("QPE/System", "linkChanged(QString)" ); 787 QCopEnvelope e("QPE/System", "linkChanged(QString)" );
777 e << fn; 788 e << fn;
778 } 789 }
779 } 790 }
780 waitsocket = 0; 791 waitsocket = 0;
781 dtp->close(); 792 dtp->close();
782} 793}
783 794
784void ServerPI::dtpFailed() 795void ServerPI::dtpFailed()
785{ 796{
786 dtp->close(); 797 dtp->close();
787 waitsocket = 0; 798 waitsocket = 0;
788 send( "451 Requested action aborted: local error in processing" ); 799 send( "451 Requested action aborted: local error in processing" );
789} 800}
790 801
791void ServerPI::dtpError( int ) 802void ServerPI::dtpError( int )
792{ 803{
793 dtp->close(); 804 dtp->close();
794 waitsocket = 0; 805 waitsocket = 0;
795 send( "451 Requested action aborted: local error in processing" ); 806 send( "451 Requested action aborted: local error in processing" );
796} 807}
797 808
798bool ServerPI::sendList( const QString& arg ) 809bool ServerPI::sendList( const QString& arg )
799{ 810{
800 QByteArray listing; 811 QByteArray listing;
801 QBuffer buffer( listing ); 812 QBuffer buffer( listing );
802 813
803 if ( !buffer.open( IO_WriteOnly ) ) 814 if ( !buffer.open( IO_WriteOnly ) )
804 return FALSE; 815 return FALSE;
805 816
806 QTextStream ts( &buffer ); 817 QTextStream ts( &buffer );
807 QString fn = arg; 818 QString fn = arg;
808 819
809 if ( fn.isEmpty() ) 820 if ( fn.isEmpty() )
810 fn = directory.path(); 821 fn = directory.path();
811 822
812 QFileInfo fi( fn ); 823 QFileInfo fi( fn );
813 if ( !fi.exists() ) return FALSE; 824 if ( !fi.exists() )
814 825 return FALSE;
815 // return file listing 826
816 if ( fi.isFile() ) { 827 // return file listing
817 ts << fileListing( &fi ) << endl; 828 if ( fi.isFile() ) {
818 } 829 ts << fileListing( &fi ) << endl;
819 830 }
820 // return directory listing 831
821 else if ( fi.isDir() ) { 832 // return directory listing
822 QDir dir( fn ); 833 else if ( fi.isDir() ) {
823 const QFileInfoList *list = dir.entryInfoList( QDir::All | QDir::Hidden ); 834 QDir dir( fn );
824 835 const QFileInfoList *list = dir.entryInfoList( QDir::All | QDir::Hidden );
825 QFileInfoListIterator it( *list ); 836
826 QFileInfo *info; 837 QFileInfoListIterator it( *list );
827 838 QFileInfo *info;
828 unsigned long total = 0; 839
829 while ( ( info = it.current() ) ) { 840 unsigned long total = 0;
830 if ( info->fileName() != "." && info->fileName() != ".." ) 841 while ( ( info = it.current() ) ) {
831 total += info->size(); 842 if ( info->fileName() != "." && info->fileName() != ".." )
832 ++it; 843 total += info->size();
833 } 844 ++it;
834 845 }
835 ts << "total " << QString::number( total / 1024 ) << endl; 846
836 847 ts << "total " << QString::number( total / 1024 ) << endl;
837 it.toFirst(); 848
838 while ( ( info = it.current() ) ) { 849 it.toFirst();
839 if ( info->fileName() == "." || info->fileName() == ".." ) { 850 while ( ( info = it.current() ) ) {
840 ++it; 851 if ( info->fileName() == "." || info->fileName() == ".." ) {
841 continue; 852 ++it;
842 } 853 continue;
843 ts << fileListing( info ) << endl; 854 }
844 ++it; 855 ts << fileListing( info ) << endl;
845 } 856 ++it;
846 } 857 }
847 858 }
848 if ( passiv ) { 859
849 waitarray = buffer.buffer(); 860 if ( passiv ) {
850 wait[SendByteArray] = TRUE; 861 waitarray = buffer.buffer();
851 if ( waitsocket ) 862 wait[SendByteArray] = TRUE;
852 newConnection( waitsocket ); 863 if ( waitsocket )
853 } 864 newConnection( waitsocket );
854 else 865 }
855 dtp->sendByteArray( buffer.buffer(), peeraddress, peerport ); 866 else
856 return TRUE; 867 dtp->sendByteArray( buffer.buffer(), peeraddress, peerport );
868 return TRUE;
857} 869}
858 870
859QString ServerPI::fileListing( QFileInfo *info ) 871QString ServerPI::fileListing( QFileInfo *info )
860{ 872{
861 if ( !info ) return QString::null; 873 if ( !info )
862 QString s; 874 return QString::null;
875 QString s;
863 876
864 // type char 877 // type char
865 if ( info->isDir() ) 878 if ( info->isDir() )
866 s += "d"; 879 s += "d";
867 else if ( info->isSymLink() ) 880 else if ( info->isSymLink() )
868 s += "l"; 881 s += "l";
869 else 882 else
870 s += "-"; 883 s += "-";
871 884
872 // permisson string 885 // permisson string
873 s += permissionString( info ) + " "; 886 s += permissionString( info ) + " ";
874 887
875 // number of hardlinks 888 // number of hardlinks
876 int subdirs = 1; 889 int subdirs = 1;
877 890
878 if ( info->isDir() ) 891 if ( info->isDir() )
879 subdirs = 2; 892 subdirs = 2;
880 // FIXME : this is to slow 893 // FIXME : this is to slow
881 //if ( info->isDir() ) 894 //if ( info->isDir() )
882 //subdirs = QDir( info->absFilePath() ).entryList( QDir::Dirs ).count(); 895 //subdirs = QDir( info->absFilePath() ).entryList( QDir::Dirs ).count();
883 896
884 s += QString::number( subdirs ).rightJustify( 3, ' ', TRUE ) + " "; 897 s += QString::number( subdirs ).rightJustify( 3, ' ', TRUE ) + " ";
885 898
886 // owner 899 // owner
887 s += info->owner().leftJustify( 8, ' ', TRUE ) + " "; 900 s += info->owner().leftJustify( 8, ' ', TRUE ) + " ";
888 901
889 // group 902 // group
890 s += info->group().leftJustify( 8, ' ', TRUE ) + " "; 903 s += info->group().leftJustify( 8, ' ', TRUE ) + " ";
891 904
892 // file size in bytes 905 // file size in bytes
893 s += QString::number( info->size() ).rightJustify( 9, ' ', TRUE ) + " "; 906 s += QString::number( info->size() ).rightJustify( 9, ' ', TRUE ) + " ";
894 907
895 // last modified date 908 // last modified date
896 QDate date = info->lastModified().date(); 909 QDate date = info->lastModified().date();
897 QTime time = info->lastModified().time(); 910 QTime time = info->lastModified().time();
898 s += date.monthName( date.month() ) + " " 911 s += date.monthName( date.month() ) + " "
899 + QString::number( date.day() ).rightJustify( 2, ' ', TRUE ) + " " 912 + QString::number( date.day() ).rightJustify( 2, ' ', TRUE ) + " "
900 + QString::number( time.hour() ).rightJustify( 2, '0', TRUE ) + ":" 913 + QString::number( time.hour() ).rightJustify( 2, '0', TRUE ) + ":"
901 + QString::number( time.minute() ).rightJustify( 2,'0', TRUE ) + " "; 914 + QString::number( time.minute() ).rightJustify( 2, '0', TRUE ) + " ";
902 915
903 // file name 916 // file name
904 s += info->fileName(); 917 s += info->fileName();
905 918
906 return s; 919 return s;
907} 920}
908 921
909QString ServerPI::permissionString( QFileInfo *info ) 922QString ServerPI::permissionString( QFileInfo *info )
910{ 923{
911 if ( !info ) return QString( "---------" ); 924 if ( !info )
912 QString s; 925 return QString( "---------" );
913 926 QString s;
914 // user 927
915 if ( info->permission( QFileInfo::ReadUser ) ) s += "r"; 928 // user
916 else s += "-"; 929 if ( info->permission( QFileInfo::ReadUser ) )
917 if ( info->permission( QFileInfo::WriteUser ) ) s += "w"; 930 s += "r";
918 else s += "-"; 931 else
919 if ( info->permission( QFileInfo::ExeUser ) ) s += "x"; 932 s += "-";
920 else s += "-"; 933 if ( info->permission( QFileInfo::WriteUser ) )
921 934 s += "w";
922 // group 935 else
923 if ( info->permission( QFileInfo::ReadGroup ) ) s += "r"; 936 s += "-";
924 else s += "-"; 937 if ( info->permission( QFileInfo::ExeUser ) )
925 if ( info->permission( QFileInfo::WriteGroup ) )s += "w"; 938 s += "x";
926 else s += "-"; 939 else
927 if ( info->permission( QFileInfo::ExeGroup ) ) s += "x"; 940 s += "-";
928 else s += "-"; 941
929 942 // group
930 // exec 943 if ( info->permission( QFileInfo::ReadGroup ) )
931 if ( info->permission( QFileInfo::ReadOther ) ) s += "r"; 944 s += "r";
932 else s += "-"; 945 else
933 if ( info->permission( QFileInfo::WriteOther ) ) s += "w"; 946 s += "-";
934 else s += "-"; 947 if ( info->permission( QFileInfo::WriteGroup ) )
935 if ( info->permission( QFileInfo::ExeOther ) ) s += "x"; 948 s += "w";
936 else s += "-"; 949 else
937 950 s += "-";
938 return s; 951 if ( info->permission( QFileInfo::ExeGroup ) )
952 s += "x";
953 else
954 s += "-";
955
956 // exec
957 if ( info->permission( QFileInfo::ReadOther ) )
958 s += "r";
959 else
960 s += "-";
961 if ( info->permission( QFileInfo::WriteOther ) )
962 s += "w";
963 else
964 s += "-";
965 if ( info->permission( QFileInfo::ExeOther ) )
966 s += "x";
967 else
968 s += "-";
969
970 return s;
939} 971}
940 972
941void ServerPI::newConnection( int socket ) 973void ServerPI::newConnection( int socket )
942{ 974{
943 //qDebug( "New incomming connection" ); 975 //qDebug( "New incomming connection" );
944 976
945 if ( !passiv ) return; 977 if ( !passiv )
946 978 return ;
947 if ( wait[SendFile] ) { 979
948 QStringList targets; 980 if ( wait[SendFile] ) {
949 if ( backupRestoreGzip( waitfile, targets ) ) 981 QStringList targets;
950 dtp->sendGzipFile( waitfile, targets ); 982 if ( backupRestoreGzip( waitfile, targets ) )
951 else 983 dtp->sendGzipFile( waitfile, targets );
952 dtp->sendFile( waitfile ); 984 else
953 dtp->setSocket( socket ); 985 dtp->sendFile( waitfile );
954 } 986 dtp->setSocket( socket );
955 else if ( wait[RetrieveFile] ) { 987 }
956 qDebug("check retrieve file"); 988 else if ( wait[RetrieveFile] ) {
957 if ( backupRestoreGzip( waitfile ) ) 989 qDebug("check retrieve file");
958 dtp->retrieveGzipFile( waitfile ); 990 if ( backupRestoreGzip( waitfile ) )
959 else 991 dtp->retrieveGzipFile( waitfile );
960 dtp->retrieveFile( waitfile ); 992 else
961 dtp->setSocket( socket ); 993 dtp->retrieveFile( waitfile );
962 } 994 dtp->setSocket( socket );
963 else if ( wait[SendByteArray] ) { 995 }
964 dtp->sendByteArray( waitarray ); 996 else if ( wait[SendByteArray] ) {
965 dtp->setSocket( socket ); 997 dtp->sendByteArray( waitarray );
966 } 998 dtp->setSocket( socket );
967 else if ( wait[RetrieveByteArray] ) { 999 }
968 qDebug("retrieve byte array"); 1000 else if ( wait[RetrieveByteArray] ) {
969 dtp->retrieveByteArray(); 1001 qDebug("retrieve byte array");
970 dtp->setSocket( socket ); 1002 dtp->retrieveByteArray();
971 } 1003 dtp->setSocket( socket );
972 else 1004 }
973 waitsocket = socket; 1005 else
974 1006 waitsocket = socket;
975 for( int i = 0; i < 4; i++ ) 1007
976 wait[i] = FALSE; 1008 for ( int i = 0; i < 4; i++ )
1009 wait[i] = FALSE;
977} 1010}
978 1011
979QString ServerPI::absFilePath( const QString& file ) 1012QString ServerPI::absFilePath( const QString& file )
980{ 1013{
981 if ( file.isEmpty() ) return file; 1014 if ( file.isEmpty() )
1015 return file;
982 1016
983 QString filepath( file ); 1017 QString filepath( file );
984 if ( file[0] != "/" ) 1018 if ( file[0] != "/" )
985 filepath = directory.path() + "/" + file; 1019 filepath = directory.path() + "/" + file;
986 1020
987 return filepath; 1021 return filepath;
988} 1022}
989 1023
990 1024
991void ServerPI::timerEvent( QTimerEvent * ) 1025void ServerPI::timerEvent( QTimerEvent * )
992{ 1026{
993 connectionClosed(); 1027 connectionClosed();
994} 1028}
995 1029
996 1030
997ServerDTP::ServerDTP( QObject *parent, const char* name) 1031ServerDTP::ServerDTP( QObject *parent, const char* name)
998 : QSocket( parent, name ), mode( Idle ), createTargzProc( 0 ), 1032 : QSocket( parent, name ), mode( Idle ), createTargzProc( 0 ),
999retrieveTargzProc( 0 ), gzipProc( 0 ) 1033 retrieveTargzProc( 0 ), gzipProc( 0 )
1000{ 1034{
1001 1035
1002 connect( this, SIGNAL( connected() ), SLOT( connected() ) ); 1036 connect( this, SIGNAL( connected() ), SLOT( connected() ) );
1003 connect( this, SIGNAL( connectionClosed() ), SLOT( connectionClosed() ) ); 1037 connect( this, SIGNAL( connectionClosed() ), SLOT( connectionClosed() ) );
1004 connect( this, SIGNAL( bytesWritten( int ) ), SLOT( bytesWritten( int ) ) ); 1038 connect( this, SIGNAL( bytesWritten( int ) ), SLOT( bytesWritten( int ) ) );
1005 connect( this, SIGNAL( readyRead() ), SLOT( readyRead() ) ); 1039 connect( this, SIGNAL( readyRead() ), SLOT( readyRead() ) );
1006 1040
1007 gzipProc = new QProcess( this, "gzipProc" ); 1041 gzipProc = new OProcess( this, "gzipProc" );
1008 gzipProc->setCommunication( QProcess::Stdin | QProcess::Stdout ); 1042
1009 1043 createTargzProc = new OProcess( QString("tar"), this, "createTargzProc");
1010 createTargzProc = new QProcess( QString("tar"), this, "createTargzProc"); 1044 createTargzProc->setWorkingDirectory( QDir::rootDirPath() );
1011 createTargzProc->setCommunication( QProcess::Stdout ); 1045 connect( createTargzProc, SIGNAL( processExited(OProcess *) ), SLOT( targzDone() ) );
1012 createTargzProc->setWorkingDirectory( QDir::rootDirPath() ); 1046
1013 connect( createTargzProc, SIGNAL( processExited() ), SLOT( targzDone() ) ); 1047 QStringList args = "tar";
1014 1048 args += "-xv";
1015 QStringList args = "tar"; 1049 retrieveTargzProc = new OProcess( args, this, "retrieveTargzProc" );
1016 args += "-xv"; 1050 retrieveTargzProc->setWorkingDirectory( QDir::rootDirPath() );
1017 retrieveTargzProc = new QProcess( args, this, "retrieveTargzProc" ); 1051 connect( retrieveTargzProc, SIGNAL( processExited(OProcess *) ),
1018 retrieveTargzProc->setCommunication( QProcess::Stdin ); 1052 SIGNAL( completed() ) );
1019 retrieveTargzProc->setWorkingDirectory( QDir::rootDirPath() ); 1053 connect( retrieveTargzProc, SIGNAL( processExited(OProcess *) ),
1020 connect( retrieveTargzProc, SIGNAL( processExited() ), 1054 SLOT( extractTarDone() ) );
1021 SIGNAL( completed() ) );
1022 connect( retrieveTargzProc, SIGNAL( processExited() ),
1023 SLOT( extractTarDone() ) );
1024} 1055}
1025 1056
1026ServerDTP::~ServerDTP() 1057ServerDTP::~ServerDTP()
1027{ 1058{
1028 buf.close(); 1059 buf.close();
1029 file.close(); 1060 file.close();
1030 createTargzProc->kill(); 1061 createTargzProc->kill();
1031} 1062}
1032 1063
1033void ServerDTP::extractTarDone() 1064void ServerDTP::extractTarDone()
1034{ 1065{
1035 qDebug("extract done"); 1066 qDebug("extract done");
1036#ifndef QT_NO_COP 1067#ifndef QT_NO_COP
1037 QCopEnvelope e( "QPE/Desktop", "restoreDone(QString)" ); 1068
1038 e << file.name(); 1069 QCopEnvelope e( "QPE/Desktop", "restoreDone(QString)" );
1070 e << file.name();
1039#endif 1071#endif
1040} 1072}
1041 1073
1042void ServerDTP::connected() 1074void ServerDTP::connected()
1043{ 1075{
1044 // send file mode 1076 // send file mode
1045 switch ( mode ) { 1077 switch ( mode ) {
1046 case SendFile : 1078 case SendFile :
1047 if ( !file.exists() || !file.open( IO_ReadOnly) ) { 1079 if ( !file.exists() || !file.open( IO_ReadOnly) ) {
1048 emit failed(); 1080 emit failed();
1049 mode = Idle; 1081 mode = Idle;
1050 return; 1082 return ;
1051 } 1083 }
1052 1084
1053 //qDebug( "Debug: Sending file '%s'", file.name().latin1() ); 1085 //qDebug( "Debug: Sending file '%s'", file.name().latin1() );
1054 1086
1055 bytes_written = 0; 1087 bytes_written = 0;
1056 if ( file.size() == 0 ) { 1088 if ( file.size() == 0 ) {
1057 //make sure it doesn't hang on empty files 1089 //make sure it doesn't hang on empty files
1058 file.close(); 1090 file.close();
1059 emit completed(); 1091 emit completed();
1060 mode = Idle; 1092 mode = Idle;
1061 } else { 1093 }
1062 1094 else {
1063 if( !file.atEnd() ) { 1095
1064 QCString s; 1096 if ( !file.atEnd() ) {
1065 s.resize( block_size ); 1097 QCString s;
1066 int bytes = file.readBlock( s.data(), block_size ); 1098 s.resize( block_size );
1067 writeBlock( s.data(), bytes ); 1099 int bytes = file.readBlock( s.data(), block_size );
1068 } 1100 writeBlock( s.data(), bytes );
1069 } 1101 }
1070 break; 1102 }
1071 case SendGzipFile: 1103 break;
1072 if ( createTargzProc->isRunning() ) { 1104 case SendGzipFile:
1073 // SHOULDN'T GET HERE, BUT DOING A SAFETY CHECK ANYWAY 1105 if ( createTargzProc->isRunning() ) {
1074 qWarning("Previous tar --gzip process is still running; killing it..."); 1106 // SHOULDN'T GET HERE, BUT DOING A SAFETY CHECK ANYWAY
1075 createTargzProc->kill(); 1107 qWarning("Previous tar --gzip process is still running; killing it...");
1076 } 1108 createTargzProc->kill();
1077 1109 }
1078 bytes_written = 0; 1110
1079 qDebug("==>start send tar process"); 1111 bytes_written = 0;
1080 if ( !createTargzProc->start() ) 1112 qDebug("==>start send tar process");
1081 qWarning("Error starting %s or %s", 1113 if ( !createTargzProc->start(OProcess::NotifyOnExit, OProcess::Stdout) )
1082 createTargzProc->arguments().join(" ").latin1(), 1114 qWarning("Error starting %s or %s",
1083 gzipProc->arguments().join(" ").latin1() ); 1115 createTargzProc->args()[0].data(),
1084 break; 1116 gzipProc->args()[0].data());
1085 case SendBuffer: 1117 break;
1086 if ( !buf.open( IO_ReadOnly) ) { 1118 case SendBuffer:
1087 emit failed(); 1119 if ( !buf.open( IO_ReadOnly) ) {
1088 mode = Idle; 1120 emit failed();
1089 return; 1121 mode = Idle;
1090 } 1122 return ;
1091 1123 }
1092 // qDebug( "Debug: Sending byte array" ); 1124
1093 bytes_written = 0; 1125 // qDebug( "Debug: Sending byte array" );
1094 while( !buf.atEnd() ) 1126 bytes_written = 0;
1095 putch( buf.getch() ); 1127 while ( !buf.atEnd() )
1096 buf.close(); 1128 putch( buf.getch() );
1097 break; 1129 buf.close();
1098 case RetrieveFile: 1130 break;
1099 // retrieve file mode 1131 case RetrieveFile:
1100 if ( file.exists() && !file.remove() ) { 1132 // retrieve file mode
1101 emit failed(); 1133 if ( file.exists() && !file.remove() ) {
1102 mode = Idle; 1134 emit failed();
1103 return; 1135 mode = Idle;
1104 } 1136 return ;
1105 1137 }
1106 if ( !file.open( IO_WriteOnly) ) { 1138
1107 emit failed(); 1139 if ( !file.open( IO_WriteOnly) ) {
1108 mode = Idle; 1140 emit failed();
1109 return; 1141 mode = Idle;
1110 } 1142 return ;
1111 // qDebug( "Debug: Retrieving file %s", file.name().latin1() ); 1143 }
1112 break; 1144 // qDebug( "Debug: Retrieving file %s", file.name().latin1() );
1113 case RetrieveGzipFile: 1145 break;
1114 qDebug("=-> starting tar process to receive .tgz file"); 1146 case RetrieveGzipFile:
1115 break; 1147 qDebug("=-> starting tar process to receive .tgz file");
1116 case RetrieveBuffer: 1148 break;
1117 // retrieve buffer mode 1149 case RetrieveBuffer:
1118 if ( !buf.open( IO_WriteOnly) ) { 1150 // retrieve buffer mode
1119 emit failed(); 1151 if ( !buf.open( IO_WriteOnly) ) {
1120 mode = Idle; 1152 emit failed();
1121 return; 1153 mode = Idle;
1122 } 1154 return ;
1123 // qDebug( "Debug: Retrieving byte array" ); 1155 }
1124 break; 1156 // qDebug( "Debug: Retrieving byte array" );
1125 case Idle: 1157 break;
1126 qDebug("connection established but mode set to Idle; BUG!"); 1158 case Idle:
1127 break; 1159 qDebug("connection established but mode set to Idle; BUG!");
1128 } 1160 break;
1161 }
1129} 1162}
1130 1163
1131void ServerDTP::connectionClosed() 1164void ServerDTP::connectionClosed()
1132{ 1165{
1133 //qDebug( "Debug: Data connection closed %ld bytes written", bytes_written ); 1166 //qDebug( "Debug: Data connection closed %ld bytes written", bytes_written );
1134 1167
1135 // send file mode 1168 // send file mode
1136 if ( SendFile == mode ) { 1169 if ( SendFile == mode ) {
1137 if ( bytes_written == file.size() ) 1170 if ( bytes_written == file.size() )
1138 emit completed(); 1171 emit completed();
1139 else 1172 else
1140 emit failed(); 1173 emit failed();
1141 } 1174 }
1142 1175
1143 // send buffer mode 1176 // send buffer mode
1144 else if ( SendBuffer == mode ) { 1177 else if ( SendBuffer == mode ) {
1145 if ( bytes_written == buf.size() ) 1178 if ( bytes_written == buf.size() )
1146 emit completed(); 1179 emit completed();
1147 else 1180 else
1148 emit failed(); 1181 emit failed();
1149 } 1182 }
1150 1183
1151 // retrieve file mode 1184 // retrieve file mode
1152 else if ( RetrieveFile == mode ) { 1185 else if ( RetrieveFile == mode ) {
1153 file.close(); 1186 file.close();
1154 emit completed(); 1187 emit completed();
1155 } 1188 }
1156 1189
1157 else if ( RetrieveGzipFile == mode ) { 1190 else if ( RetrieveGzipFile == mode ) {
1158 qDebug("Done writing ungzip file; closing input"); 1191 qDebug("Done writing ungzip file; closing input");
1159 gzipProc->flushStdin(); 1192 gzipProc->flushStdin();
1160 gzipProc->closeStdin(); 1193 gzipProc->closeStdin();
1161 } 1194 }
1162 1195
1163 // retrieve buffer mode 1196 // retrieve buffer mode
1164 else if ( RetrieveBuffer == mode ) { 1197 else if ( RetrieveBuffer == mode ) {
1165 buf.close(); 1198 buf.close();
1166 emit completed(); 1199 emit completed();
1167 } 1200 }
1168 1201
1169 mode = Idle; 1202 mode = Idle;
1170} 1203}
1171 1204
1172void ServerDTP::bytesWritten( int bytes ) 1205void ServerDTP::bytesWritten( int bytes )
1173{ 1206{
1174 bytes_written += bytes; 1207 bytes_written += bytes;
1175 1208
1176 // send file mode 1209 // send file mode
1177 if ( SendFile == mode ) { 1210 if ( SendFile == mode ) {
1178 1211
1179 if ( bytes_written == file.size() ) { 1212 if ( bytes_written == file.size() ) {
1180 // qDebug( "Debug: Sending complete: %d bytes", file.size() ); 1213 // qDebug( "Debug: Sending complete: %d bytes", file.size() );
1181 file.close(); 1214 file.close();
1182 emit completed(); 1215 emit completed();
1183 mode = Idle; 1216 mode = Idle;
1184 } 1217 }
1185 else if( !file.atEnd() ) { 1218 else if ( !file.atEnd() ) {
1186 QCString s; 1219 QCString s;
1187 s.resize( block_size ); 1220 s.resize( block_size );
1188 int bytes = file.readBlock( s.data(), block_size ); 1221 int bytes = file.readBlock( s.data(), block_size );
1189 writeBlock( s.data(), bytes ); 1222 writeBlock( s.data(), bytes );
1190 } 1223 }
1191 } 1224 }
1192 1225
1193 // send buffer mode 1226 // send buffer mode
1194 if ( SendBuffer == mode ) { 1227 if ( SendBuffer == mode ) {
1195 1228
1196 if ( bytes_written == buf.size() ) { 1229 if ( bytes_written == buf.size() ) {
1197 // qDebug( "Debug: Sending complete: %d bytes", buf.size() ); 1230 // qDebug( "Debug: Sending complete: %d bytes", buf.size() );
1198 emit completed(); 1231 emit completed();
1199 mode = Idle; 1232 mode = Idle;
1200 } 1233 }
1201 } 1234 }
1202} 1235}
1203 1236
1204void ServerDTP::readyRead() 1237void ServerDTP::readyRead()
1205{ 1238{
1206 // retrieve file mode 1239 // retrieve file mode
1207 if ( RetrieveFile == mode ) { 1240 if ( RetrieveFile == mode ) {
1208 QCString s; 1241 QCString s;
1209 s.resize( bytesAvailable() ); 1242 s.resize( bytesAvailable() );
1210 readBlock( s.data(), bytesAvailable() ); 1243 readBlock( s.data(), bytesAvailable() );
1211 file.writeBlock( s.data(), s.size() ); 1244 file.writeBlock( s.data(), s.size() );
1212 } 1245 }
1213 else if ( RetrieveGzipFile == mode ) { 1246 else if ( RetrieveGzipFile == mode ) {
1214 if ( !gzipProc->isRunning() ) 1247 if ( !gzipProc->isRunning() )
1215 gzipProc->start(); 1248 gzipProc->start(OProcess::NotifyOnExit, (OProcess::Communication) ( OProcess::Stdin | OProcess::Stdout ));
1216 1249
1217 QByteArray s; 1250 QByteArray s;
1218 s.resize( bytesAvailable() ); 1251 s.resize( bytesAvailable() );
1219 readBlock( s.data(), bytesAvailable() ); 1252 readBlock( s.data(), bytesAvailable() );
1220 gzipProc->writeToStdin( s ); 1253 gzipProc->writeStdin( s.data(), s.size() );
1221 qDebug("wrote %d bytes to ungzip ", s.size() ); 1254 qDebug("wrote %d bytes to ungzip ", s.size() );
1222 } 1255 }
1223 // retrieve buffer mode 1256 // retrieve buffer mode
1224 else if ( RetrieveBuffer == mode ) { 1257 else if ( RetrieveBuffer == mode ) {
1225 QCString s; 1258 QCString s;
1226 s.resize( bytesAvailable() ); 1259 s.resize( bytesAvailable() );
1227 readBlock( s.data(), bytesAvailable() ); 1260 readBlock( s.data(), bytesAvailable() );
1228 buf.writeBlock( s.data(), s.size() ); 1261 buf.writeBlock( s.data(), s.size() );
1229 } 1262 }
1230} 1263}
1231 1264
1232void ServerDTP::writeTargzBlock() 1265void ServerDTP::writeTargzBlock(OProcess *, char *buffer, int buflen)
1233{ 1266{
1234 QByteArray block = gzipProc->readStdout(); 1267 writeBlock( buffer, buflen );
1235 writeBlock( block.data(), block.size() ); 1268 qDebug("writeTargzBlock %d", buflen);
1236 qDebug("writeTargzBlock %d", block.size()); 1269 if ( !createTargzProc->isRunning() ) {
1237 if ( !createTargzProc->isRunning() ) { 1270 qDebug("tar and gzip done");
1238 qDebug("tar and gzip done"); 1271 emit completed();
1239 emit completed(); 1272 mode = Idle;
1240 mode = Idle; 1273 disconnect( gzipProc, SIGNAL( receivedStdout(OProcess *, char *, int ) ),
1241 disconnect( gzipProc, SIGNAL( readyReadStdout() ), 1274 this, SLOT( writeTargzBlock(OProcess *, char *, int) ) );
1242 this, SLOT( writeTargzBlock() ) ); 1275 }
1243 }
1244} 1276}
1245 1277
1246void ServerDTP::targzDone() 1278void ServerDTP::targzDone()
1247{ 1279{
1248 //qDebug("targz done"); 1280 //qDebug("targz done");
1249 disconnect( createTargzProc, SIGNAL( readyReadStdout() ), 1281 disconnect( createTargzProc, SIGNAL( receivedStdout(OProcess *, char *, int) ),
1250 this, SLOT( gzipTarBlock() ) ); 1282 this, SLOT( gzipTarBlock(OProcess *, char *, int) ) );
1251 gzipProc->closeStdin(); 1283 gzipProc->closeStdin();
1252} 1284}
1253 1285
1254void ServerDTP::gzipTarBlock() 1286void ServerDTP::gzipTarBlock(OProcess *, char *buffer, int buflen)
1255{ 1287{
1256 //qDebug("gzipTarBlock"); 1288 //qDebug("gzipTarBlock");
1257 if ( !gzipProc->isRunning() ) { 1289 if ( !gzipProc->isRunning() ) {
1258 //qDebug("auto start gzip proc"); 1290 //qDebug("auto start gzip proc");
1259 gzipProc->start(); 1291 gzipProc->start(OProcess::NotifyOnExit, (OProcess::Communication) ( OProcess::Stdin | OProcess::Stdout ));
1260 } 1292 }
1261 gzipProc->writeToStdin( createTargzProc->readStdout() ); 1293 gzipProc->writeStdin( buffer, buflen );
1262} 1294}
1263 1295
1264void ServerDTP::sendFile( const QString fn, const QHostAddress& host, Q_UINT16 port ) 1296void ServerDTP::sendFile( const QString fn, const QHostAddress& host, Q_UINT16 port )
1265{ 1297{
1266 file.setName( fn ); 1298 file.setName( fn );
1267 mode = SendFile; 1299 mode = SendFile;
1268 connectToHost( host.toString(), port ); 1300 connectToHost( host.toString(), port );
1269} 1301}
1270 1302
1271void ServerDTP::sendFile( const QString fn ) 1303void ServerDTP::sendFile( const QString fn )
1272{ 1304{
1273 file.setName( fn ); 1305 file.setName( fn );
1274 mode = SendFile; 1306 mode = SendFile;
1275} 1307}
1276 1308
1277void ServerDTP::sendGzipFile( const QString &fn, 1309void ServerDTP::sendGzipFile( const QString &fn,
1278 const QStringList &archiveTargets, 1310 const QStringList &archiveTargets,
1279 const QHostAddress& host, Q_UINT16 port ) 1311 const QHostAddress& host, Q_UINT16 port )
1280{ 1312{
1281 sendGzipFile( fn, archiveTargets ); 1313 sendGzipFile( fn, archiveTargets );
1282 connectToHost( host.toString(), port ); 1314 connectToHost( host.toString(), port );
1283} 1315}
1284 1316
1285void ServerDTP::sendGzipFile( const QString &fn, 1317void ServerDTP::sendGzipFile( const QString &fn,
1286 const QStringList &archiveTargets ) 1318 const QStringList &archiveTargets )
1287{ 1319{
1288 mode = SendGzipFile; 1320 mode = SendGzipFile;
1289 file.setName( fn ); 1321 file.setName( fn );
1290 1322
1291 QStringList args = "tar"; 1323 QStringList args = "tar";
1292 args += "-cv"; 1324 args += "-cv";
1293 args += archiveTargets; 1325 args += archiveTargets;
1294 qDebug("sendGzipFile %s", args.join(" ").latin1() ); 1326 qDebug("sendGzipFile %s", args.join(" ").latin1() );
1295 createTargzProc->setArguments( args ); 1327 createTargzProc->clearArguments( );
1296 connect( createTargzProc, 1328 *createTargzProc << args;
1297 SIGNAL( readyReadStdout() ), SLOT( gzipTarBlock() ) ); 1329 connect( createTargzProc,
1298 1330 SIGNAL( receivedStdout(OProcess *, char *, int) ), SLOT( gzipTarBlock(OProcess *, char *, int) ) );
1299 gzipProc->setArguments( "gzip" ); 1331
1300 connect( gzipProc, SIGNAL( readyReadStdout() ), 1332 gzipProc->clearArguments( );
1301 SLOT( writeTargzBlock() ) ); 1333 *gzipProc << "gzip";
1334 connect( gzipProc, SIGNAL( receivedStdout(OProcess *, char *, int) ),
1335 SLOT( writeTargzBlock(OProcess *, char *, int) ) );
1302} 1336}
1303 1337
1304void ServerDTP::gunzipDone() 1338void ServerDTP::gunzipDone()
1305{ 1339{
1306 qDebug("gunzipDone"); 1340 qDebug("gunzipDone");
1307 disconnect( gzipProc, SIGNAL( processExited() ), 1341 disconnect( gzipProc, SIGNAL( processExited() ),
1308 this, SLOT( gunzipDone() ) ); 1342 this, SLOT( gunzipDone() ) );
1309 retrieveTargzProc->closeStdin(); 1343 retrieveTargzProc->closeStdin();
1310 disconnect( gzipProc, SIGNAL( readyReadStdout() ), 1344 disconnect( gzipProc, SIGNAL( receivedStdout(OProcess *, char *, int) ),
1311 this, SLOT( tarExtractBlock() ) ); 1345 this, SLOT( tarExtractBlock(OProcess *, char *, int) ) );
1312} 1346}
1313 1347
1314void ServerDTP::tarExtractBlock() 1348void ServerDTP::tarExtractBlock(OProcess *, char *buffer, int buflen)
1315{ 1349{
1316 qDebug("ungzipTarBlock"); 1350 qDebug("tarExtractBlock");
1317 if ( !retrieveTargzProc->isRunning() ) { 1351 if ( !retrieveTargzProc->isRunning() ) {
1318 qDebug("auto start ungzip proc"); 1352 qDebug("auto start ungzip proc");
1319 if ( !retrieveTargzProc->start() ) 1353 if ( !retrieveTargzProc->start(OProcess::NotifyOnExit, OProcess::Stdin) )
1320 qWarning(" failed to start tar -x process"); 1354 qWarning(" failed to start tar -x process");
1321 } 1355 }
1322 retrieveTargzProc->writeToStdin( gzipProc->readStdout() ); 1356 retrieveTargzProc->writeStdin( buffer, buflen );
1323} 1357}
1324 1358
1325 1359
1326void ServerDTP::retrieveFile( const QString fn, const QHostAddress& host, Q_UINT16 port ) 1360void ServerDTP::retrieveFile( const QString fn, const QHostAddress& host, Q_UINT16 port )
1327{ 1361{
1328 file.setName( fn ); 1362 file.setName( fn );
1329 mode = RetrieveFile; 1363 mode = RetrieveFile;
1330 connectToHost( host.toString(), port ); 1364 connectToHost( host.toString(), port );
1331} 1365}
1332 1366
1333void ServerDTP::retrieveFile( const QString fn ) 1367void ServerDTP::retrieveFile( const QString fn )
1334{ 1368{
1335 file.setName( fn ); 1369 file.setName( fn );
1336 mode = RetrieveFile; 1370 mode = RetrieveFile;
1337} 1371}
1338 1372
1339void ServerDTP::retrieveGzipFile( const QString &fn ) 1373void ServerDTP::retrieveGzipFile( const QString &fn )
1340{ 1374{
1341 qDebug("retrieveGzipFile %s", fn.latin1()); 1375 qDebug("retrieveGzipFile %s", fn.latin1());
1342 file.setName( fn ); 1376 file.setName( fn );
1343 mode = RetrieveGzipFile; 1377 mode = RetrieveGzipFile;
1344 1378
1345 gzipProc->setArguments( "gunzip" ); 1379 gzipProc->clearArguments();
1346 connect( gzipProc, SIGNAL( readyReadStdout() ), 1380 *gzipProc << "gunzip";
1347 SLOT( tarExtractBlock() ) ); 1381 connect( gzipProc, SIGNAL( readyReadStdout() ),
1348 connect( gzipProc, SIGNAL( processExited() ), 1382 SLOT( tarExtractBlock() ) );
1349 SLOT( gunzipDone() ) ); 1383 connect( gzipProc, SIGNAL( processExited() ),
1384 SLOT( gunzipDone() ) );
1350} 1385}
1351 1386
1352void ServerDTP::retrieveGzipFile( const QString &fn, const QHostAddress& host, Q_UINT16 port ) 1387void ServerDTP::retrieveGzipFile( const QString &fn, const QHostAddress& host, Q_UINT16 port )
1353{ 1388{
1354 retrieveGzipFile( fn ); 1389 retrieveGzipFile( fn );
1355 connectToHost( host.toString(), port ); 1390 connectToHost( host.toString(), port );
1356} 1391}
1357 1392
1358void ServerDTP::sendByteArray( const QByteArray& array, const QHostAddress& host, Q_UINT16 port ) 1393void ServerDTP::sendByteArray( const QByteArray& array, const QHostAddress& host, Q_UINT16 port )
1359{ 1394{
1360 buf.setBuffer( array ); 1395 buf.setBuffer( array );
1361 mode = SendBuffer; 1396 mode = SendBuffer;
1362 connectToHost( host.toString(), port ); 1397 connectToHost( host.toString(), port );
1363} 1398}
1364 1399
1365void ServerDTP::sendByteArray( const QByteArray& array ) 1400void ServerDTP::sendByteArray( const QByteArray& array )
1366{ 1401{
1367 buf.setBuffer( array ); 1402 buf.setBuffer( array );
1368 mode = SendBuffer; 1403 mode = SendBuffer;
1369} 1404}
1370 1405
1371void ServerDTP::retrieveByteArray( const QHostAddress& host, Q_UINT16 port ) 1406void ServerDTP::retrieveByteArray( const QHostAddress& host, Q_UINT16 port )
1372{ 1407{
1373 buf.setBuffer( QByteArray() ); 1408 buf.setBuffer( QByteArray() );
1374 mode = RetrieveBuffer; 1409 mode = RetrieveBuffer;
1375 connectToHost( host.toString(), port ); 1410 connectToHost( host.toString(), port );
1376} 1411}
1377 1412
1378void ServerDTP::retrieveByteArray() 1413void ServerDTP::retrieveByteArray()
1379{ 1414{
1380 buf.setBuffer( QByteArray() ); 1415 buf.setBuffer( QByteArray() );
1381 mode = RetrieveBuffer; 1416 mode = RetrieveBuffer;
1382} 1417}
1383 1418
1384void ServerDTP::setSocket( int socket ) 1419void ServerDTP::setSocket( int socket )
1385{ 1420{
1386 QSocket::setSocket( socket ); 1421 QSocket::setSocket( socket );
1387 connected(); 1422 connected();
1388} 1423}
1389 1424
diff --git a/core/launcher/transferserver.h b/core/launcher/transferserver.h
index a3bb060..1c5ab4b 100644
--- a/core/launcher/transferserver.h
+++ b/core/launcher/transferserver.h
@@ -3,49 +3,49 @@
3** 3**
4** This file is part of the Qtopia Environment. 4** This file is part of the Qtopia Environment.
5** 5**
6** This file may be distributed and/or modified under the terms of the 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 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 8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file. 9** packaging of this file.
10** 10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 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. 12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13** 13**
14** See http://www.trolltech.com/gpl/ for GPL licensing information. 14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15** 15**
16** Contact info@trolltech.com if any conditions of this licensing are 16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you. 17** not clear to you.
18** 18**
19**********************************************************************/ 19**********************************************************************/
20#include <qserversocket.h> 20#include <qserversocket.h>
21#include <qsocket.h> 21#include <qsocket.h>
22#include <qdir.h> 22#include <qdir.h>
23#include <qfile.h> 23#include <qfile.h>
24#include <qbuffer.h> 24#include <qbuffer.h>
25 25
26class QFileInfo; 26class QFileInfo;
27class QProcess; 27class OProcess;
28class TransferServer : public QServerSocket 28class TransferServer : public QServerSocket
29{ 29{
30 Q_OBJECT 30 Q_OBJECT
31 31
32public: 32public:
33 TransferServer( Q_UINT16 port, QObject *parent = 0, const char* name = 0 ); 33 TransferServer( Q_UINT16 port, QObject *parent = 0, const char* name = 0 );
34 virtual ~TransferServer(); 34 virtual ~TransferServer();
35 35
36 void newConnection( int socket ); 36 void newConnection( int socket );
37}; 37};
38 38
39class SyncAuthentication : QObject 39class SyncAuthentication : QObject
40{ 40{
41 Q_OBJECT 41 Q_OBJECT
42 42
43public: 43public:
44 static int isAuthorized(QHostAddress peeraddress); 44 static int isAuthorized(QHostAddress peeraddress);
45 static bool checkPassword(const QString& pw); 45 static bool checkPassword(const QString& pw);
46 static bool checkUser(const QString& user); 46 static bool checkUser(const QString& user);
47 47
48 static QString serverId(); 48 static QString serverId();
49 static QString loginName(); 49 static QString loginName();
50 static QString ownerName(); 50 static QString ownerName();
51}; 51};
@@ -71,65 +71,65 @@ public:
71 void sendByteArray( const QByteArray& array, const QHostAddress& host, Q_UINT16 port ); 71 void sendByteArray( const QByteArray& array, const QHostAddress& host, Q_UINT16 port );
72 72
73 void retrieveFile( const QString fn ); 73 void retrieveFile( const QString fn );
74 void retrieveFile( const QString fn, const QHostAddress& host, Q_UINT16 port ); 74 void retrieveFile( const QString fn, const QHostAddress& host, Q_UINT16 port );
75 void retrieveGzipFile( const QString &fn ); 75 void retrieveGzipFile( const QString &fn );
76 void retrieveGzipFile( const QString &fn, const QHostAddress& host, Q_UINT16 port ); 76 void retrieveGzipFile( const QString &fn, const QHostAddress& host, Q_UINT16 port );
77 void retrieveByteArray(); 77 void retrieveByteArray();
78 void retrieveByteArray( const QHostAddress& host, Q_UINT16 port ); 78 void retrieveByteArray( const QHostAddress& host, Q_UINT16 port );
79 79
80 Mode dtpMode() { return mode; } 80 Mode dtpMode() { return mode; }
81 QByteArray buffer() { return buf.buffer(); } 81 QByteArray buffer() { return buf.buffer(); }
82 QString fileName() const { return file.name(); } 82 QString fileName() const { return file.name(); }
83 83
84 void setSocket( int socket ); 84 void setSocket( int socket );
85 85
86signals: 86signals:
87 void completed(); 87 void completed();
88 void failed(); 88 void failed();
89 89
90private slots: 90private slots:
91 void connectionClosed(); 91 void connectionClosed();
92 void connected(); 92 void connected();
93 void bytesWritten( int bytes ); 93 void bytesWritten( int bytes );
94 void readyRead(); 94 void readyRead();
95 void writeTargzBlock(); 95 void writeTargzBlock(OProcess *, char *, int);
96 void targzDone(); 96 void targzDone();
97 97
98 void gzipTarBlock(); 98 void gzipTarBlock(OProcess *, char *, int);
99 void tarExtractBlock(); 99 void tarExtractBlock(OProcess *, char *, int);
100 void gunzipDone(); 100 void gunzipDone();
101 void extractTarDone(); 101 void extractTarDone();
102 102
103private: 103private:
104 104
105 unsigned long bytes_written; 105 unsigned long bytes_written;
106 Mode mode; 106 Mode mode;
107 QFile file; 107 QFile file;
108 QBuffer buf; 108 QBuffer buf;
109 QProcess *createTargzProc; 109 OProcess *createTargzProc;
110 QProcess *retrieveTargzProc; 110 OProcess *retrieveTargzProc;
111 QProcess *gzipProc; 111 OProcess *gzipProc;
112}; 112};
113 113
114class ServerSocket : public QServerSocket 114class ServerSocket : public QServerSocket
115{ 115{
116 Q_OBJECT 116 Q_OBJECT
117 117
118public: 118public:
119 ServerSocket( Q_UINT16 port, QObject *parent = 0, const char* name = 0 ) 119 ServerSocket( Q_UINT16 port, QObject *parent = 0, const char* name = 0 )
120 : QServerSocket( port, 1, parent, name ) {} 120 : QServerSocket( port, 1, parent, name ) {}
121 121
122 void newConnection( int socket ) { emit newIncomming( socket ); } 122 void newConnection( int socket ) { emit newIncomming( socket ); }
123signals: 123signals:
124 void newIncomming( int socket ); 124 void newIncomming( int socket );
125}; 125};
126 126
127class ServerPI : public QSocket 127class ServerPI : public QSocket
128{ 128{
129 Q_OBJECT 129 Q_OBJECT
130 130
131 enum State { Connected, Wait_USER, Wait_PASS, Ready, Forbidden }; 131 enum State { Connected, Wait_USER, Wait_PASS, Ready, Forbidden };
132 enum Transfer { SendFile = 0, RetrieveFile = 1, SendByteArray = 2, RetrieveByteArray = 3 }; 132 enum Transfer { SendFile = 0, RetrieveFile = 1, SendByteArray = 2, RetrieveByteArray = 3 };
133 133
134public: 134public:
135 ServerPI( int socket, QObject *parent = 0, const char* name = 0 ); 135 ServerPI( int socket, QObject *parent = 0, const char* name = 0 );