1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the Qt3Support module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "q3networkprotocol.h"
43 
44 #ifndef QT_NO_NETWORKPROTOCOL
45 
46 #include "q3localfs.h"
47 #include "q3urloperator.h"
48 #include "qtimer.h"
49 #include "qmap.h"
50 #include "q3ptrqueue.h"
51 #include "q3valuelist.h"
52 #include "qurlinfo.h"
53 #include <private/qobject_p.h>
54 
55 QT_BEGIN_NAMESPACE
56 
57 //#define Q3NETWORKPROTOCOL_DEBUG
58 #define NETWORK_OP_DELAY 1000
59 
60 extern Q_COMPAT_EXPORT Q3NetworkProtocolDict *q3networkProtocolRegister;
61 
62 Q3NetworkProtocolDict *q3networkProtocolRegister = 0;
63 
64 class Q3NetworkProtocolPrivate
65 {
66 public:
Q3NetworkProtocolPrivate(Q3NetworkProtocol * p)67     Q3NetworkProtocolPrivate( Q3NetworkProtocol *p )
68     {
69 	url = 0;
70 	opInProgress = 0;
71 	opStartTimer = new QTimer( p );
72 	removeTimer = new QTimer( p );
73 	operationQueue.setAutoDelete( false );
74 	autoDelete = false;
75 	removeInterval = 10000;
76 	oldOps.setAutoDelete( false );
77     }
78 
~Q3NetworkProtocolPrivate()79     ~Q3NetworkProtocolPrivate()
80     {
81 	removeTimer->stop();
82 	if ( opInProgress ) {
83 	    if ( opInProgress == operationQueue.head() )
84 		operationQueue.dequeue();
85 	    opInProgress->free();
86 	}
87 	while ( operationQueue.head() ) {
88 	    operationQueue.head()->free();
89 	    operationQueue.dequeue();
90 	}
91 	while ( oldOps.first() ) {
92 	    oldOps.first()->free();
93 	    oldOps.removeFirst();
94 	}
95 	delete opStartTimer;
96     }
97 
98     Q3UrlOperator *url;
99     Q3PtrQueue< Q3NetworkOperation > operationQueue;
100     Q3NetworkOperation *opInProgress;
101     QTimer *opStartTimer, *removeTimer;
102     int removeInterval;
103     bool autoDelete;
104     Q3PtrList< Q3NetworkOperation > oldOps;
105 };
106 
107 /*!
108     \class Q3NetworkProtocol
109     \brief The Q3NetworkProtocol class provides a common API for network protocols.
110 
111     \compat
112 
113     This is a base class which should be used for network protocols
114     implementations that can then be used in Qt (e.g. in the file
115     dialog) together with the Q3UrlOperator.
116 
117     The easiest way to implement a new network protocol is to
118     reimplement the operation*() methods, e.g. operationGet(), etc.
119     Only the supported operations should be reimplemented. To specify
120     which operations are supported, also reimplement
121     supportedOperations() and return an int that is OR'd together
122     using the supported operations from the \l
123     Q3NetworkProtocol::Operation enum.
124 
125     When you implement a network protocol this way, it is important to
126     emit the correct signals. Also, always emit the finished() signal
127     when an operation is done (on success \e and on failure). Qt
128     relies on correctly emitted finished() signals.
129 */
130 
131 /*!
132     \fn void Q3NetworkProtocol::newChildren( const Q3ValueList<QUrlInfo> &i, Q3NetworkOperation *op )
133 
134     This signal is emitted after listChildren() was called and new
135     children (files) have been read from the list of files. \a i holds
136     the information about the new children. \a op is the pointer to
137     the operation object which contains all the information about the
138     operation, including the state, etc.
139 
140     When a protocol emits this signal, Q3NetworkProtocol is smart
141     enough to let the Q3UrlOperator, which is used by the network
142     protocol, emit its corresponding signal.
143 
144     When implementing your own network protocol and reading children,
145     you usually don't read one child at once, but rather a list of
146     them. That's why this signal takes a list of QUrlInfo objects. If
147     you prefer to read just one child at a time you can use the
148     convenience signal newChild(), which takes a single QUrlInfo
149     object.
150 */
151 
152 /*!
153     \fn void Q3NetworkProtocol::newChild( const QUrlInfo &i, Q3NetworkOperation *op )
154 
155     This signal is emitted if a new child (file) has been read.
156     Q3NetworkProtocol automatically connects it to a slot which creates
157     a list of QUrlInfo objects (with just one QUrlInfo \a i) and emits
158     the newChildren() signal with this list. \a op is the pointer to
159     the operation object which contains all the information about the
160     operation that has finished, including the state, etc.
161 
162     This is just a convenience signal useful for implementing your own
163     network protocol. In all other cases connect to the newChildren()
164     signal with its list of QUrlInfo objects.
165 */
166 
167 /*!
168     \fn void Q3NetworkProtocol::finished( Q3NetworkOperation *op )
169 
170     This signal is emitted when an operation finishes. This signal is
171     always emitted, for both success and failure. \a op is the pointer
172     to the operation object which contains all the information about
173     the operation, including the state, etc. Check the state and error
174     code of the operation object to determine whether or not the
175     operation was successful.
176 
177     When a protocol emits this signal, Q3NetworkProtocol is smart
178     enough to let the Q3UrlOperator, which is used by the network
179     protocol, emit its corresponding signal.
180 */
181 
182 /*!
183     \fn void Q3NetworkProtocol::start( Q3NetworkOperation *op )
184 
185     Some operations (such as listChildren()) emit this signal when
186     they start processing the operation. \a op is the pointer to the
187     operation object which contains all the information about the
188     operation, including the state, etc.
189 
190     When a protocol emits this signal, Q3NetworkProtocol is smart
191     enough to let the Q3UrlOperator, which is used by the network
192     protocol, emit its corresponding signal.
193 */
194 
195 /*!
196     \fn void Q3NetworkProtocol::createdDirectory( const QUrlInfo &i, Q3NetworkOperation *op )
197 
198     This signal is emitted when mkdir() has been successful and the
199     directory has been created. \a i holds the information about the
200     new directory. \a op is the pointer to the operation object which
201     contains all the information about the operation, including the
202     state, etc. Using op->arg( 0 ), you can get the file name of the
203     new directory.
204 
205     When a protocol emits this signal, Q3NetworkProtocol is smart
206     enough to let the Q3UrlOperator, which is used by the network
207     protocol, emit its corresponding signal.
208 */
209 
210 /*!
211     \fn void Q3NetworkProtocol::removed( Q3NetworkOperation *op )
212 
213     This signal is emitted when remove() has been succesiisful and the
214     file has been removed. \a op holds the file name of the removed
215     file in the first argument, accessible with op->arg( 0 ). \a op is
216     the pointer to the operation object which contains all the
217     information about the operation, including the state, etc.
218 
219     When a protocol emits this signal, Q3NetworkProtocol is smart
220     enough to let the Q3UrlOperator, which is used by the network
221     protocol, emit its corresponding signal.
222 */
223 
224 /*!
225     \fn void Q3NetworkProtocol::itemChanged( Q3NetworkOperation *op )
226 
227     This signal is emitted whenever a file which is a child of this
228     URL has been changed, e.g. by successfully calling rename(). \a op
229     holds the original and the new file names in the first and second
230     arguments, accessible with op->arg( 0 ) and op->arg( 1 )
231     respectively. \a op is the pointer to the operation object which
232     contains all the information about the operation, including the
233     state, etc.
234 
235     When a protocol emits this signal, Q3NetworkProtocol is smart
236     enough to let the Q3UrlOperator, which is used by the network
237     protocol, emit its corresponding signal.
238 */
239 
240 /*!
241     \fn void Q3NetworkProtocol::data( const QByteArray &data,
242     Q3NetworkOperation *op )
243 
244     This signal is emitted when new \a data has been received after
245     calling get() or put(). \a op holds the name of the file from
246     which data is retrieved or uploaded in its first argument, and the
247     (raw) data in its second argument. You can get them with
248     op->arg( 0 ) and op->rawArg( 1 ). \a op is the pointer to the
249     operation object, which contains all the information about the
250     operation, including the state, etc.
251 
252     When a protocol emits this signal, Q3NetworkProtocol is smart
253     enough to let the Q3UrlOperator (which is used by the network
254     protocol) emit its corresponding signal.
255 */
256 
257 /*!
258     \fn void Q3NetworkProtocol::dataTransferProgress( int bytesDone, int bytesTotal, Q3NetworkOperation *op )
259 
260     This signal is emitted during the transfer of data (using put() or
261     get()). \a bytesDone is how many bytes of \a bytesTotal have been
262     transferred. \a bytesTotal may be -1, which means that the total
263     number of bytes is not known. \a op is the pointer to the
264     operation object which contains all the information about the
265     operation, including the state, etc.
266 
267     When a protocol emits this signal, Q3NetworkProtocol is smart
268     enough to let the Q3UrlOperator, which is used by the network
269     protocol, emit its corresponding signal.
270 */
271 
272 /*!
273     \fn void Q3NetworkProtocol::connectionStateChanged( int state, const QString &data )
274 
275     This signal is emitted whenever the state of the connection of the
276     network protocol is changed. \a state describes the new state,
277     which is one of, \c ConHostFound, \c ConConnected or \c ConClosed.
278     \a data is a message text.
279 */
280 
281 /*!
282     \enum Q3NetworkProtocol::State
283 
284     This enum contains the state that a Q3NetworkOperation can have.
285 
286     \value StWaiting  The operation is in the Q3NetworkProtocol's queue
287     waiting to be prcessed.
288 
289     \value StInProgress  The operation is being processed.
290 
291     \value StDone  The operation has been processed successfully.
292 
293     \value StFailed  The operation has been processed but an error occurred.
294 
295     \value StStopped  The operation has been processed but has been
296     stopped before it finished, and is waiting to be processed.
297 
298 */
299 
300 /*!
301     \enum Q3NetworkProtocol::Operation
302 
303     This enum lists the possible operations that a network protocol
304     can support. supportedOperations() returns an int of these that is
305     OR'd together. Also, the type() of a Q3NetworkOperation is always
306     one of these values.
307 
308     \value OpListChildren  List the children of a URL, e.g. of a directory.
309     \value OpMkDir  Create a directory.
310     \value OpRemove  Remove a child (e.g. a file).
311     \value OpRename  Rename a child (e.g. a file).
312     \value OpGet  Get data from a location.
313     \value OpPut  Put data to a location.
314     \omitvalue OpMkdir
315 */
316 
317 /*!
318     \enum Q3NetworkProtocol::ConnectionState
319 
320     When the connection state of a network protocol changes it emits
321     the signal connectionStateChanged(). The first argument is one of
322     the following values:
323 
324     \value ConHostFound  Host has been found.
325     \value ConConnected  Connection to the host has been established.
326     \value ConClosed  Connection has been closed.
327 */
328 
329 /*!
330     \enum Q3NetworkProtocol::Error
331 
332     When an operation fails (finishes unsuccessfully), the
333     Q3NetworkOperation of the operation returns an error code which has
334     one of the following values:
335 
336     \value NoError  No error occurred.
337 
338     \value ErrValid  The URL you are operating on is not valid.
339 
340     \value ErrUnknownProtocol  There is no protocol implementation
341     available for the protocol of the URL you are operating on (e.g.
342     if the protocol is http and no http implementation has been
343     registered).
344 
345     \value ErrUnsupported  The operation is not supported by the
346     protocol.
347 
348     \value ErrParse  The URL could not be parsed correctly.
349 
350     \value ErrLoginIncorrect  You needed to login but the username
351     or password is wrong.
352 
353     \value ErrHostNotFound  The specified host (in the URL) couldn't
354     be found.
355 
356     \value ErrListChildren  An error occurred while listing the
357     children (files).
358 
359     \value ErrMkDir  An error occurred when creating a directory.
360 
361     \value ErrRemove  An error occurred when removing a child (file).
362 
363     \value ErrRename   An error occurred when renaming a child (file).
364 
365     \value ErrGet  An error occurred while getting (retrieving) data.
366 
367     \value ErrPut  An error occurred while putting (uploading) data.
368 
369     \value ErrFileNotExisting  A file which is needed by the operation
370     doesn't exist.
371 
372     \value ErrPermissionDenied  Permission for doing the operation has
373     been denied.
374     \omitvalue ErrMkdir
375     \omitvalue ErrListChlidren
376 
377     You should also use these error codes when implementing custom
378     network protocols. If this is not possible, you can define your own
379     error codes by using integer values that don't conflict with any
380     of these values.
381 */
382 
383 /*!
384     Constructor of the network protocol base class. Does some
385     initialization and connecting of signals and slots.
386 */
387 
Q3NetworkProtocol()388 Q3NetworkProtocol::Q3NetworkProtocol()
389     : QObject()
390 {
391     d = new Q3NetworkProtocolPrivate( this );
392 
393     connect( d->opStartTimer, SIGNAL(timeout()),
394 	     this, SLOT(startOps()) );
395     connect( d->removeTimer, SIGNAL(timeout()),
396 	     this, SLOT(removeMe()) );
397 
398     if ( url() ) {
399 	connect( this, SIGNAL(data(QByteArray,Q3NetworkOperation*)),
400 		 url(), SIGNAL(data(QByteArray,Q3NetworkOperation*)) );
401 	connect( this, SIGNAL(finished(Q3NetworkOperation*)),
402 		 url(), SIGNAL(finished(Q3NetworkOperation*)) );
403 	connect( this, SIGNAL(start(Q3NetworkOperation*)),
404 		 url(), SIGNAL(start(Q3NetworkOperation*)) );
405 	connect( this, SIGNAL(newChildren(Q3ValueList<QUrlInfo>,Q3NetworkOperation*)),
406 		 url(), SIGNAL(newChildren(Q3ValueList<QUrlInfo>,Q3NetworkOperation*)) );
407 	connect( this, SIGNAL(newChildren(Q3ValueList<QUrlInfo>,Q3NetworkOperation*)),
408 		 url(), SLOT(addEntry(Q3ValueList<QUrlInfo>)) );
409 	connect( this, SIGNAL(createdDirectory(QUrlInfo,Q3NetworkOperation*)),
410 		 url(), SIGNAL(createdDirectory(QUrlInfo,Q3NetworkOperation*)) );
411 	connect( this, SIGNAL(removed(Q3NetworkOperation*)),
412 		 url(), SIGNAL(removed(Q3NetworkOperation*)) );
413 	connect( this, SIGNAL(itemChanged(Q3NetworkOperation*)),
414 		 url(), SIGNAL(itemChanged(Q3NetworkOperation*)) );
415 	connect( this, SIGNAL(dataTransferProgress(int,int,Q3NetworkOperation*)),
416 		 url(), SIGNAL(dataTransferProgress(int,int,Q3NetworkOperation*)) );
417 	connect( this, SIGNAL(connectionStateChanged(int,QString)),
418 		 url(), SIGNAL(connectionStateChanged(int,QString)) );
419     }
420 
421     connect( this, SIGNAL(finished(Q3NetworkOperation*)),
422 	     this, SLOT(processNextOperation(Q3NetworkOperation*)) );
423     connect( this, SIGNAL(newChild(QUrlInfo,Q3NetworkOperation*)),
424 	     this, SLOT(emitNewChildren(QUrlInfo,Q3NetworkOperation*)) );
425 
426 }
427 
428 /*!
429     Destructor.
430 */
431 
~Q3NetworkProtocol()432 Q3NetworkProtocol::~Q3NetworkProtocol()
433 {
434     delete d;
435 }
436 
437 /*!
438     Sets the Q3UrlOperator, on which the protocol works, to \a u.
439 
440     \sa Q3UrlOperator
441 */
442 
setUrl(Q3UrlOperator * u)443 void Q3NetworkProtocol::setUrl( Q3UrlOperator *u )
444 {
445     if ( url() ) {
446 	disconnect( this, SIGNAL(data(QByteArray,Q3NetworkOperation*)),
447 		    url(), SIGNAL(data(QByteArray,Q3NetworkOperation*)) );
448 	disconnect( this, SIGNAL(finished(Q3NetworkOperation*)),
449 		    url(), SIGNAL(finished(Q3NetworkOperation*)) );
450 	disconnect( this, SIGNAL(start(Q3NetworkOperation*)),
451 		    url(), SIGNAL(start(Q3NetworkOperation*)) );
452 	disconnect( this, SIGNAL(newChildren(Q3ValueList<QUrlInfo>,Q3NetworkOperation*)),
453 		    url(), SIGNAL(newChildren(Q3ValueList<QUrlInfo>,Q3NetworkOperation*)) );
454 	disconnect( this, SIGNAL(newChildren(Q3ValueList<QUrlInfo>,Q3NetworkOperation*)),
455 		    url(), SLOT(addEntry(Q3ValueList<QUrlInfo>)) );
456 	disconnect( this, SIGNAL(createdDirectory(QUrlInfo,Q3NetworkOperation*)),
457 		    url(), SIGNAL(createdDirectory(QUrlInfo,Q3NetworkOperation*)) );
458 	disconnect( this, SIGNAL(removed(Q3NetworkOperation*)),
459 		    url(), SIGNAL(removed(Q3NetworkOperation*)) );
460 	disconnect( this, SIGNAL(itemChanged(Q3NetworkOperation*)),
461 		    url(), SIGNAL(itemChanged(Q3NetworkOperation*)) );
462 	disconnect( this, SIGNAL(dataTransferProgress(int,int,Q3NetworkOperation*)),
463 		    url(), SIGNAL(dataTransferProgress(int,int,Q3NetworkOperation*)) );
464 	disconnect( this, SIGNAL(connectionStateChanged(int,QString)),
465 		    url(), SIGNAL(connectionStateChanged(int,QString)) );
466     }
467 
468 
469     // ### if autoDelete is true, we should delete the Q3UrlOperator (something
470     // like below; but that is not possible since it would delete this, too).
471     //if ( d->autoDelete && (d->url!=u) ) {
472     //    delete d->url; // destructor deletes the network protocol
473     //}
474     d->url = u;
475 
476     if ( url() ) {
477 	connect( this, SIGNAL(data(QByteArray,Q3NetworkOperation*)),
478 		 url(), SIGNAL(data(QByteArray,Q3NetworkOperation*)) );
479 	connect( this, SIGNAL(finished(Q3NetworkOperation*)),
480 		 url(), SIGNAL(finished(Q3NetworkOperation*)) );
481 	connect( this, SIGNAL(start(Q3NetworkOperation*)),
482 		 url(), SIGNAL(start(Q3NetworkOperation*)) );
483 	connect( this, SIGNAL(newChildren(Q3ValueList<QUrlInfo>,Q3NetworkOperation*)),
484 		 url(), SIGNAL(newChildren(Q3ValueList<QUrlInfo>,Q3NetworkOperation*)) );
485 	connect( this, SIGNAL(newChildren(Q3ValueList<QUrlInfo>,Q3NetworkOperation*)),
486 		 url(), SLOT(addEntry(Q3ValueList<QUrlInfo>)) );
487 	connect( this, SIGNAL(createdDirectory(QUrlInfo,Q3NetworkOperation*)),
488 		 url(), SIGNAL(createdDirectory(QUrlInfo,Q3NetworkOperation*)) );
489 	connect( this, SIGNAL(removed(Q3NetworkOperation*)),
490 		 url(), SIGNAL(removed(Q3NetworkOperation*)) );
491 	connect( this, SIGNAL(itemChanged(Q3NetworkOperation*)),
492 		 url(), SIGNAL(itemChanged(Q3NetworkOperation*)) );
493 	connect( this, SIGNAL(dataTransferProgress(int,int,Q3NetworkOperation*)),
494 		 url(), SIGNAL(dataTransferProgress(int,int,Q3NetworkOperation*)) );
495 	connect( this, SIGNAL(connectionStateChanged(int,QString)),
496 		 url(), SIGNAL(connectionStateChanged(int,QString)) );
497     }
498 
499     if ( !d->opInProgress && !d->operationQueue.isEmpty() )
500 	d->opStartTimer->start( 0, true );
501 }
502 
503 /*!
504     For processing operations the network protocol base class calls
505     this method quite often. This should be reimplemented by new
506     network protocols. It should return true if the connection is OK
507     (open); otherwise it should return false. If the connection is not
508     open the protocol should open it.
509 
510     If the connection can't be opened (e.g. because you already tried
511     but the host couldn't be found), set the state of \a op to
512     Q3NetworkProtocol::StFailed and emit the finished() signal with
513     this Q3NetworkOperation as argument.
514 
515     \a op is the operation that needs an open connection.
516 */
517 
checkConnection(Q3NetworkOperation *)518 bool Q3NetworkProtocol::checkConnection( Q3NetworkOperation * )
519 {
520     return true;
521 }
522 
523 /*!
524     Returns an int that is OR'd together using the enum values of
525     \l{Q3NetworkProtocol::Operation}, which describes which operations
526     are supported by the network protocol. Should be reimplemented by
527     new network protocols.
528 */
529 
supportedOperations() const530 int Q3NetworkProtocol::supportedOperations() const
531 {
532     return 0;
533 }
534 
535 /*!
536     Adds the operation \a op to the operation queue. The operation
537     will be processed as soon as possible. This method returns
538     immediately.
539 */
540 
addOperation(Q3NetworkOperation * op)541 void Q3NetworkProtocol::addOperation( Q3NetworkOperation *op )
542 {
543 #ifdef Q3NETWORKPROTOCOL_DEBUG
544     qDebug( "Q3NetworkOperation: addOperation: %p %d", op, op->operation() );
545 #endif
546     d->operationQueue.enqueue( op );
547     if ( !d->opInProgress )
548 	d->opStartTimer->start( 0, true );
549 }
550 
551 /*!
552     Static method to register a network protocol for Qt. For example,
553     if you have an implementation of NNTP (called Nntp) which is
554     derived from Q3NetworkProtocol, call:
555     \snippet doc/src/snippets/code/src_qt3support_network_q3networkprotocol.cpp 0
556     after which your implementation is registered for future nntp
557     operations.
558 
559     The name of the protocol is given in \a protocol and a pointer to
560     the protocol factory is given in \a protocolFactory.
561 */
562 
registerNetworkProtocol(const QString & protocol,Q3NetworkProtocolFactoryBase * protocolFactory)563 void Q3NetworkProtocol::registerNetworkProtocol( const QString &protocol,
564 						Q3NetworkProtocolFactoryBase *protocolFactory )
565 {
566     if ( !q3networkProtocolRegister ) {
567 	q3networkProtocolRegister = new Q3NetworkProtocolDict;
568 	Q3NetworkProtocol::registerNetworkProtocol( QLatin1String("file"), new Q3NetworkProtocolFactory< Q3LocalFs > );
569     }
570 
571     q3networkProtocolRegister->insert( protocol, protocolFactory );
572 }
573 
574 /*!
575     Static method to get a new instance of the network protocol \a
576     protocol. For example, if you need to do some FTP operations, do
577     the following:
578     \snippet doc/src/snippets/code/src_qt3support_network_q3networkprotocol.cpp 1
579     This returns a pointer to a new instance of an ftp implementation
580     or null if no protocol for ftp was registered. The ownership of
581     the pointer is transferred to you, so you must delete it if you
582     don't need it anymore.
583 
584     Normally you should not work directly with network protocols, so
585     you will not need to call this method yourself. Instead, use
586     Q3UrlOperator, which makes working with network protocols much more
587     convenient.
588 
589     \sa Q3UrlOperator
590 */
591 
getNetworkProtocol(const QString & protocol)592 Q3NetworkProtocol *Q3NetworkProtocol::getNetworkProtocol( const QString &protocol )
593 {
594     if ( !q3networkProtocolRegister ) {
595 	q3networkProtocolRegister = new Q3NetworkProtocolDict;
596 	Q3NetworkProtocol::registerNetworkProtocol( QLatin1String("file"), new Q3NetworkProtocolFactory< Q3LocalFs > );
597     }
598 
599     if ( protocol.isNull() )
600 	return 0;
601 
602     Q3NetworkProtocolFactoryBase *factory = q3networkProtocolRegister->find( protocol );
603     if ( factory )
604 	return factory->createObject();
605 
606     return 0;
607 }
608 
609 /*!
610     Returns true if the only protocol registered is for working on the
611     local filesystem; returns false if other network protocols are
612     also registered.
613 */
614 
hasOnlyLocalFileSystem()615 bool Q3NetworkProtocol::hasOnlyLocalFileSystem()
616 {
617     if ( !q3networkProtocolRegister )
618 	return false;
619 
620     Q3DictIterator< Q3NetworkProtocolFactoryBase > it( *q3networkProtocolRegister );
621     for ( ; it.current(); ++it )
622 	if ( it.currentKey() != QLatin1String("file") )
623 	    return false;
624     return true;
625 }
626 
627 /*!
628   \internal
629   Starts processing network operations.
630 */
631 
startOps()632 void Q3NetworkProtocol::startOps()
633 {
634 #ifdef Q3NETWORKPROTOCOL_DEBUG
635     qDebug( "Q3NetworkOperation: start processing operations" );
636 #endif
637     processNextOperation( 0 );
638 }
639 
640 /*!
641   \internal
642   Processes the operation \a op. It calls the
643   corresponding operation[something]( Q3NetworkOperation * )
644   methods.
645 */
646 
processOperation(Q3NetworkOperation * op)647 void Q3NetworkProtocol::processOperation( Q3NetworkOperation *op )
648 {
649     if ( !op )
650 	return;
651 
652     switch ( op->operation() ) {
653     case OpListChildren:
654 	operationListChildren( op );
655 	break;
656     case OpMkDir:
657 	operationMkDir( op );
658 	break;
659     case OpRemove:
660 	operationRemove( op );
661 	break;
662     case OpRename:
663 	operationRename( op );
664 	break;
665     case OpGet:
666 	operationGet( op );
667 	break;
668     case OpPut:
669 	operationPut( op );
670 	break;
671     }
672 }
673 
674 /*!
675     When implementing a new network protocol, this method should be
676     reimplemented if the protocol supports listing children (files);
677     this method should then process this Q3NetworkOperation.
678 
679     \a op is the pointer to the operation object which contains all
680     the information on the operation that has finished, including the
681     state, etc.
682 */
683 
operationListChildren(Q3NetworkOperation *)684 void Q3NetworkProtocol::operationListChildren( Q3NetworkOperation * )
685 {
686 }
687 
688 /*!
689     When implementing a new network protocol, this method should be
690     reimplemented if the protocol supports making directories; this
691     method should then process this Q3NetworkOperation.
692 
693     \a op is the pointer to the operation object which contains all
694     the information on the operation that has finished, including the
695     state, etc.
696 */
697 
operationMkDir(Q3NetworkOperation *)698 void Q3NetworkProtocol::operationMkDir( Q3NetworkOperation * )
699 {
700 }
701 
702 /*!
703     When implementing a new network protocol, this method should be
704     reimplemented if the protocol supports removing children (files);
705     this method should then process this Q3NetworkOperation.
706 
707     \a op is the pointer to the operation object which contains all
708     the information on the operation that has finished, including the
709     state, etc.
710 */
711 
operationRemove(Q3NetworkOperation *)712 void Q3NetworkProtocol::operationRemove( Q3NetworkOperation * )
713 {
714 }
715 
716 /*!
717     When implementing a new network protocol, this method should be
718     reimplemented if the protocol supports renaming children (files);
719     this method should then process this Q3NetworkOperation.
720 
721     \a op is the pointer to the operation object which contains all
722     the information on the operation that has finished, including the
723     state, etc.
724 */
725 
operationRename(Q3NetworkOperation *)726 void Q3NetworkProtocol::operationRename( Q3NetworkOperation * )
727 {
728 }
729 
730 /*!
731     When implementing a new network protocol, this method should be
732     reimplemented if the protocol supports getting data; this method
733     should then process the Q3NetworkOperation.
734 
735     \a op is the pointer to the operation object which contains all
736     the information on the operation that has finished, including the
737     state, etc.
738 */
739 
operationGet(Q3NetworkOperation *)740 void Q3NetworkProtocol::operationGet( Q3NetworkOperation * )
741 {
742 }
743 
744 /*!
745     When implementing a new network protocol, this method should be
746     reimplemented if the protocol supports putting (uploading) data;
747     this method should then process the Q3NetworkOperation.
748 
749     \a op is the pointer to the operation object which contains all
750     the information on the operation that has finished, including the
751     state, etc.
752 */
753 
operationPut(Q3NetworkOperation *)754 void Q3NetworkProtocol::operationPut( Q3NetworkOperation * )
755 {
756 }
757 
758 /*! \internal
759 */
760 
operationPutChunk(Q3NetworkOperation *)761 void Q3NetworkProtocol::operationPutChunk( Q3NetworkOperation * )
762 {
763 }
764 
765 /*!
766   \internal
767   Handles operations. Deletes the previous operation object and
768   tries to process the next operation. It also checks the connection state
769   and only processes the next operation, if the connection of the protocol
770   is open. Otherwise it waits until the protocol opens the connection.
771 */
772 
processNextOperation(Q3NetworkOperation * old)773 void Q3NetworkProtocol::processNextOperation( Q3NetworkOperation *old )
774 {
775 #ifdef Q3NETWORKPROTOCOL_DEBUG
776     qDebug( "Q3NetworkOperation: process next operation, old: %p", old );
777 #endif
778     d->removeTimer->stop();
779 
780     if ( old )
781 	d->oldOps.append( old );
782     if ( d->opInProgress && d->opInProgress!=old )
783 	d->oldOps.append( d->opInProgress );
784 
785     if ( d->operationQueue.isEmpty() ) {
786 	d->opInProgress = 0;
787 	if ( d->autoDelete )
788 	    d->removeTimer->start( d->removeInterval, true );
789 	return;
790     }
791 
792     Q3NetworkOperation *op = d->operationQueue.head();
793 
794     d->opInProgress = op;
795 
796     if ( !checkConnection( op ) ) {
797 	if ( op->state() != Q3NetworkProtocol::StFailed ) {
798 	    d->opStartTimer->start( 0, true );
799 	} else {
800 	    d->operationQueue.dequeue();
801 	    clearOperationQueue();
802 	    emit finished( op );
803 	}
804 
805 	return;
806     }
807 
808     d->opInProgress = op;
809     d->operationQueue.dequeue();
810     processOperation( op );
811 }
812 
813 /*!
814     Returns the Q3UrlOperator on which the protocol works.
815 */
816 
url() const817 Q3UrlOperator *Q3NetworkProtocol::url() const
818 {
819     return d->url;
820 }
821 
822 /*!
823     Returns the operation, which is being processed, or 0 of no
824     operation is being processed at the moment.
825 */
826 
operationInProgress() const827 Q3NetworkOperation *Q3NetworkProtocol::operationInProgress() const
828 {
829     return d->opInProgress;
830 }
831 
832 /*!
833     Clears the operation queue.
834 */
835 
clearOperationQueue()836 void Q3NetworkProtocol::clearOperationQueue()
837 {
838     d->operationQueue.dequeue();
839     d->operationQueue.setAutoDelete( true );
840     d->operationQueue.clear();
841 }
842 
843 /*!
844     Stops the current operation that is being processed and clears all
845     waiting operations.
846 */
847 
stop()848 void Q3NetworkProtocol::stop()
849 {
850     Q3NetworkOperation *op = d->opInProgress;
851     clearOperationQueue();
852     if ( op ) {
853 	op->setState( StStopped );
854 	op->setProtocolDetail( tr( "Operation stopped by the user" ) );
855 	emit finished( op );
856 	setUrl( 0 );
857 	op->free();
858     }
859 }
860 
861 /*!
862     Because it's sometimes hard to take care of removing network
863     protocol instances, Q3NetworkProtocol provides an auto-delete
864     mechanism. If you set \a b to true, the network protocol instance
865     is removed after it has been inactive for \a i milliseconds (i.e.
866     \a i milliseconds after the last operation has been processed).
867     If you set \a b to false the auto-delete mechanism is switched
868     off.
869 
870     If you switch on auto-delete, the Q3NetworkProtocol also deletes
871     its Q3UrlOperator.
872 */
873 
setAutoDelete(bool b,int i)874 void Q3NetworkProtocol::setAutoDelete( bool b, int i )
875 {
876     d->autoDelete = b;
877     d->removeInterval = i;
878 }
879 
880 /*!
881     Returns true if auto-deleting is enabled; otherwise returns false.
882 
883     \sa Q3NetworkProtocol::setAutoDelete()
884 */
885 
autoDelete() const886 bool Q3NetworkProtocol::autoDelete() const
887 {
888     return d->autoDelete;
889 }
890 
891 /*!
892   \internal
893 */
894 
removeMe()895 void Q3NetworkProtocol::removeMe()
896 {
897     if ( d->autoDelete ) {
898 #ifdef Q3NETWORKPROTOCOL_DEBUG
899 	qDebug( "Q3NetworkOperation:  autodelete of Q3NetworkProtocol %p", this );
900 #endif
901 	delete d->url; // destructor deletes the network protocol
902     }
903 }
904 
emitNewChildren(const QUrlInfo & i,Q3NetworkOperation * op)905 void Q3NetworkProtocol::emitNewChildren( const QUrlInfo &i, Q3NetworkOperation *op )
906 {
907     Q3ValueList<QUrlInfo> lst;
908     lst << i;
909     emit newChildren( lst, op );
910 }
911 
912 class Q3NetworkOperationPrivate
913 {
914 public:
915     Q3NetworkProtocol::Operation operation;
916     Q3NetworkProtocol::State state;
917     QMap<int, QString> args;
918     QMap<int, QByteArray> rawArgs;
919     QString protocolDetail;
920     int errorCode;
921     QTimer *deleteTimer;
922 };
923 
924 /*!
925     \class Q3NetworkOperation
926 
927     \brief The Q3NetworkOperation class provides common operations for network protocols.
928 
929     \compat
930 
931     An object is created to describe the operation and the current
932     state for each operation that a network protocol should process.
933 
934     \sa Q3NetworkProtocol
935 */
936 
937 /*!
938     Constructs a network operation object. \a operation is the type of
939     the operation, and \a arg0, \a arg1 and \a arg2 are the first
940     three arguments of the operation. The state is initialized to
941     Q3NetworkProtocol::StWaiting.
942 
943     \sa Q3NetworkProtocol::Operation Q3NetworkProtocol::State
944 */
945 
Q3NetworkOperation(Q3NetworkProtocol::Operation operation,const QString & arg0,const QString & arg1,const QString & arg2)946 Q3NetworkOperation::Q3NetworkOperation( Q3NetworkProtocol::Operation operation,
947 				      const QString &arg0, const QString &arg1,
948 				      const QString &arg2 )
949 {
950     d = new Q3NetworkOperationPrivate;
951     d->deleteTimer = new QTimer( this );
952     connect( d->deleteTimer, SIGNAL(timeout()),
953 	     this, SLOT(deleteMe()) );
954     d->operation = operation;
955     d->state = Q3NetworkProtocol::StWaiting;
956     d->args[ 0 ] = arg0;
957     d->args[ 1 ] = arg1;
958     d->args[ 2 ] = arg2;
959     d->rawArgs[ 0 ] = QByteArray( 0 );
960     d->rawArgs[ 1 ] = QByteArray( 0 );
961     d->rawArgs[ 2 ] = QByteArray( 0 );
962     d->protocolDetail.clear();
963     d->errorCode = (int)Q3NetworkProtocol::NoError;
964 }
965 
966 /*!
967     Constructs a network operation object. \a operation is the type of
968     the operation, and \a arg0, \a arg1 and \a arg2 are the first
969     three raw data arguments of the operation. The state is
970     initialized to Q3NetworkProtocol::StWaiting.
971 
972     \sa Q3NetworkProtocol::Operation Q3NetworkProtocol::State
973 */
974 
Q3NetworkOperation(Q3NetworkProtocol::Operation operation,const QByteArray & arg0,const QByteArray & arg1,const QByteArray & arg2)975 Q3NetworkOperation::Q3NetworkOperation( Q3NetworkProtocol::Operation operation,
976 				      const QByteArray &arg0, const QByteArray &arg1,
977 				      const QByteArray &arg2 )
978 {
979     d = new Q3NetworkOperationPrivate;
980     d->deleteTimer = new QTimer( this );
981     connect( d->deleteTimer, SIGNAL(timeout()),
982 	     this, SLOT(deleteMe()) );
983     d->operation = operation;
984     d->state = Q3NetworkProtocol::StWaiting;
985     d->args[ 0 ].clear();
986     d->args[ 1 ].clear();
987     d->args[ 2 ].clear();
988     d->rawArgs[ 0 ] = arg0;
989     d->rawArgs[ 1 ] = arg1;
990     d->rawArgs[ 2 ] = arg2;
991     d->protocolDetail.clear();
992     d->errorCode = (int)Q3NetworkProtocol::NoError;
993 }
994 
995 /*!
996     Destructor.
997 */
998 
~Q3NetworkOperation()999 Q3NetworkOperation::~Q3NetworkOperation()
1000 {
1001     qDeleteInEventHandler(d->deleteTimer);
1002     delete d;
1003 }
1004 
1005 /*!
1006     Sets the \a state of the operation object. This should be done by
1007     the network protocol during processing; at the end it should be
1008     set to Q3NetworkProtocol::StDone or Q3NetworkProtocol::StFailed,
1009     depending on success or failure.
1010 
1011     \sa Q3NetworkProtocol::State
1012 */
1013 
setState(Q3NetworkProtocol::State state)1014 void Q3NetworkOperation::setState( Q3NetworkProtocol::State state )
1015 {
1016     if ( d->deleteTimer->isActive() ) {
1017 	d->deleteTimer->stop();
1018 	d->deleteTimer->start( NETWORK_OP_DELAY );
1019     }
1020     d->state = state;
1021 }
1022 
1023 /*!
1024     If the operation failed, the error message can be specified as \a
1025     detail.
1026 */
1027 
setProtocolDetail(const QString & detail)1028 void Q3NetworkOperation::setProtocolDetail( const QString &detail )
1029 {
1030     if ( d->deleteTimer->isActive() ) {
1031 	d->deleteTimer->stop();
1032 	d->deleteTimer->start( NETWORK_OP_DELAY );
1033     }
1034     d->protocolDetail = detail;
1035 }
1036 
1037 /*!
1038     Sets the error code to \a ec.
1039 
1040     If the operation failed, the protocol should set an error code to
1041     describe the error in more detail. If possible, one of the error
1042     codes defined in Q3NetworkProtocol should be used.
1043 
1044     \sa setProtocolDetail() Q3NetworkProtocol::Error
1045 */
1046 
setErrorCode(int ec)1047 void Q3NetworkOperation::setErrorCode( int ec )
1048 {
1049     if ( d->deleteTimer->isActive() ) {
1050 	d->deleteTimer->stop();
1051 	d->deleteTimer->start( NETWORK_OP_DELAY );
1052     }
1053     d->errorCode = ec;
1054 }
1055 
1056 /*!
1057     Sets the network operation's \a{num}-th argument to \a arg.
1058 */
1059 
setArg(int num,const QString & arg)1060 void Q3NetworkOperation::setArg( int num, const QString &arg )
1061 {
1062     if ( d->deleteTimer->isActive() ) {
1063 	d->deleteTimer->stop();
1064 	d->deleteTimer->start( NETWORK_OP_DELAY );
1065     }
1066     d->args[ num ] = arg;
1067 }
1068 
1069 /*!
1070     Sets the network operation's \a{num}-th raw data argument to \a arg.
1071 */
1072 
setRawArg(int num,const QByteArray & arg)1073 void Q3NetworkOperation::setRawArg( int num, const QByteArray &arg )
1074 {
1075     if ( d->deleteTimer->isActive() ) {
1076 	d->deleteTimer->stop();
1077 	d->deleteTimer->start( NETWORK_OP_DELAY );
1078     }
1079     d->rawArgs[ num ] = arg;
1080 }
1081 
1082 /*!
1083     Returns the type of the operation.
1084 */
1085 
operation() const1086 Q3NetworkProtocol::Operation Q3NetworkOperation::operation() const
1087 {
1088     if ( d->deleteTimer->isActive() ) {
1089 	d->deleteTimer->stop();
1090 	d->deleteTimer->start( NETWORK_OP_DELAY );
1091     }
1092     return d->operation;
1093 }
1094 
1095 /*!
1096     Returns the state of the operation. You can determine whether an
1097     operation is still waiting to be processed, is being processed,
1098     has been processed successfully, or failed.
1099 */
1100 
state() const1101 Q3NetworkProtocol::State Q3NetworkOperation::state() const
1102 {
1103     if ( d->deleteTimer->isActive() ) {
1104 	d->deleteTimer->stop();
1105 	d->deleteTimer->start( NETWORK_OP_DELAY );
1106     }
1107     return d->state;
1108 }
1109 
1110 /*!
1111     Returns the operation's \a{num}-th argument. If this argument was
1112     not already set, an empty string is returned.
1113 */
1114 
arg(int num) const1115 QString Q3NetworkOperation::arg( int num ) const
1116 {
1117     if ( d->deleteTimer->isActive() ) {
1118 	d->deleteTimer->stop();
1119 	d->deleteTimer->start( NETWORK_OP_DELAY );
1120     }
1121     return d->args[ num ];
1122 }
1123 
1124 /*!
1125     Returns the operation's \a{num}-th raw data argument. If this
1126     argument was not already set, an empty bytearray is returned.
1127 */
1128 
rawArg(int num) const1129 QByteArray Q3NetworkOperation::rawArg( int num ) const
1130 {
1131     if ( d->deleteTimer->isActive() ) {
1132 	d->deleteTimer->stop();
1133 	d->deleteTimer->start( NETWORK_OP_DELAY );
1134     }
1135     return d->rawArgs[ num ];
1136 }
1137 
1138 /*!
1139     Returns a detailed error message for the last error. This must
1140     have been set using setProtocolDetail().
1141 */
1142 
protocolDetail() const1143 QString Q3NetworkOperation::protocolDetail() const
1144 {
1145     if ( d->deleteTimer->isActive() ) {
1146 	d->deleteTimer->stop();
1147 	d->deleteTimer->start( NETWORK_OP_DELAY );
1148     }
1149     return d->protocolDetail;
1150 }
1151 
1152 /*!
1153     Returns the error code for the last error that occurred.
1154 */
1155 
errorCode() const1156 int Q3NetworkOperation::errorCode() const
1157 {
1158     if ( d->deleteTimer->isActive() ) {
1159 	d->deleteTimer->stop();
1160 	d->deleteTimer->start( NETWORK_OP_DELAY );
1161     }
1162     return d->errorCode;
1163 }
1164 
1165 /*!
1166   \internal
1167 */
1168 
raw(int num) const1169 QByteArray& Q3NetworkOperation::raw( int num ) const
1170 {
1171     if ( d->deleteTimer->isActive() ) {
1172 	d->deleteTimer->stop();
1173 	d->deleteTimer->start( NETWORK_OP_DELAY );
1174     }
1175     return d->rawArgs[ num ];
1176 }
1177 
1178 /*!
1179     Sets this object to delete itself when it hasn't been used for one
1180     second.
1181 
1182     Because Q3NetworkOperation pointers are passed around a lot the
1183     Q3NetworkProtocol generally does not have enough knowledge to
1184     delete these at the correct time. If a Q3NetworkProtocol doesn't
1185     need an operation any more it will call this function instead.
1186 
1187     Note: you should never need to call the method yourself.
1188 */
1189 
free()1190 void Q3NetworkOperation::free()
1191 {
1192     d->deleteTimer->start( NETWORK_OP_DELAY );
1193 }
1194 
1195 /*!
1196   \internal
1197   Internal slot for auto-deletion.
1198 */
1199 
deleteMe()1200 void Q3NetworkOperation::deleteMe()
1201 {
1202     delete this;
1203 }
1204 
1205 QT_END_NAMESPACE
1206 
1207 #include "moc_q3networkprotocol.cpp"
1208 
1209 #endif
1210