summaryrefslogtreecommitdiffstats
path: root/kftpgrabber/src/engine/socket.h
blob: 2bc360427a32658a3de805fa78f92695c6bdf923 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
/*
 * This file is part of the KFTPGrabber project
 *
 * Copyright (C) 2003-2006 by the KFTPGrabber developers
 * Copyright (C) 2003-2006 Jernej Kos <kostko@jweb-network.net>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
 * NON-INFRINGEMENT.  See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 *
 * In addition, as a special exception, the copyright holders give
 * permission to link the code of portions of this program with the
 * OpenSSL library under certain conditions as described in each
 * individual source file, and distribute linked combinations
 * including the two.
 *
 * You must obey the GNU General Public License in all respects
 * for all of the code used other than OpenSSL.  If you modify
 * file(s) with this exception, you may extend this exception to your
 * version of the file(s), but you are not obligated to do so.  If you
 * do not wish to do so, delete this exception statement from your
 * version.  If you delete this exception statement from all source
 * files in the program, then also delete it here.
 */
#ifndef KFTPENGINESOCKET_H
#define KFTPENGINESOCKET_H

#include <kurl.h>
#include <kremoteencoding.h>

#include <tqptrlist.h>
#include <tqguardedptr.h>
#include <tqdatetime.h>

#include "commands.h"

namespace KFTPEngine {

class ConnectionRetry;

enum SocketFeatures {
  SF_FXP_TRANSFER = 1,
  SF_RAW_COMMAND  = 2
};

/**
 * The socket class provides an abstract class for all implemented protocols. It
 * provides basic methods and also some remote operations (recursive scan,
 * recursive removal).
 *
 * @author Jernej Kos <kostko@jweb-network.net>
 */
class Socket
{
friend class Thread;
friend class FtpCommandStat;
public:
    /**
     * Constructs a new socket.
     *
     * @param thread The thread that created this socket
     * @param protocol The protocol name
     */
    Socket(Thread *thread, const TQString &protocol);
    ~Socket();
    
    /**
     * Set an internal config value.
     *
     * @param key Key
     * @param value Value
     */
    void setConfig(const TQString &key, const TQString &value) { m_config[key] = value; }
    
    /**
     * Set an internal config value.
     *
     * @param key Key
     * @param value Value
     */
    void setConfig(const TQString &key, int value) { m_config[key] = TQString::number(value); }
    
    /**
     * Set an internal config value.
     *
     * @param key Key
     * @param value Value
     */
    void setConfig(const TQString &key, filesize_t value) { m_config[key] = TQString::number(value); }
    
    /**
     * Get an internal config value as string.
     *
     * @param key Key
     * @return The key's value or an empty string if the key doesn't exist
     */
    TQString getConfig(const TQString &key) { return m_config[key]; }
    
    /**
     * Get an internal config value as an integer.
     *
     * @param key Key
     * @return The key's value or 0 if the key doesn't exist
     */
    int getConfigInt(const TQString &key) { return m_config[key].toInt(); }
    
    /**
     * Get an internal config value as filesize.
     *
     * @param key Key
     * @return The key's value or 0 if the key doesn't exist
     */
    filesize_t getConfigFs(const TQString &key) { return m_config[key].toULongLong(); }
    
    /**
     * This method should initialize the configuration map.
     */
    virtual void initConfig();
    
    /**
     * This method should trigger the connection process.
     *
     * @param url Remote url to connect to
     */
    virtual void protoConnect(const KURL &url) = 0;
    
    /**
     * This method should disconnect from the remote host.
     */
    virtual void protoDisconnect();
    
    /**
     * This method should abort any ongoing action.
     */
    virtual void protoAbort();
    
    /**
     * This method should download a remote file and save it localy.
     *
     * @param source The source url
     * @param destination The destination url
     */
    virtual void protoGet(const KURL &source, const KURL &destination) = 0;
    
    /**
     * This method should upload a local file and save it remotely.
     *
     * @param source The source url
     * @param destination The destination url
     */
    virtual void protoPut(const KURL &source, const KURL &destination) = 0;
    
    /**
     * Each protocol should implement this method. It should remove just one
     * single entry. A config variable "params.remove.directory" will be set
     * to 1 if the entry to remove is a directory and to 0 if it should expect
     * a file.
     *
     * @warning You should NOT use this method directly! Use @ref protoDelete
     *          instead!
     * @param path The path to the entry to remove
     */
    virtual void protoRemove(const KURL &path) = 0;
    
    /**
     * This method should rename/move a remote file.
     *
     * @param source The source file path
     * @param destination The destination file path
     */
    virtual void protoRename(const KURL &source, const KURL &destination) = 0;
    
    /**
     * This method should change file's mode.
     *
     * * @warning You should NOT use this method directly! Use @ref protoChmod
     *            instead!
     * @param path The file's path
     * @param mode The new file mode
     */
    virtual void protoChmodSingle(const KURL &path, int mode) = 0;
    
    /**
     * This method should create a new remote directory.
     *
     * @param path Path of the newly created remote directory
     */
    virtual void protoMkdir(const KURL &path) = 0;
    
    /**
     * This method should fetch the remote directory listing for a specified
     * directory. Note that this method could be called as a chained command,
     * so it MUST NOT emit an EventDirectoryListing event if isChained returns
     * true! In this case it should save the directory listing to the
     * m_lastDirectoryListing member variable.
     *
     * @param path The path to list
     */
    virtual void protoList(const KURL &path) = 0;
    
    /**
     * This method should fetch the information about the given path. It is
     * usualy called as a chained command.
     *
     * @param path The path to stat
     */
    virtual void protoStat(const KURL &path);
    
    /**
     * This method should send a raw command in case the protocol supports it
     * (the SF_RAW_COMMAND is among features).
     *
     * @param command The command to send
     */
    virtual void protoRaw(const TQString&) {}
    
    /**
     * This method should initiate a site to site transfer in case the protocol
     * supports it (the SF_FXP_TRANSFER is among features).
     *
     * @param socket The destination socket
     * @param source The source url
     * @param destination The destination url
     */
    virtual void protoSiteToSite(Socket*, const KURL&, const KURL&) {}
    
    /**
     * Send a packet to keep the connection alive.
     */
    virtual void protoKeepAlive() {}
    
    /**
     * Recursively scan a directory and emit a DirectoryTree that can be used to
     * create new transfers for addition to the queue.
     *
     * @param path The path to recursively scan
     */
    void protoScan(const KURL &path);
    
    /**
     * Identify if the remote path is a file or a directory and recursively remove
     * it if so. The difference between this command and @ref protoRemove is, that
     * protoRemove removes just one entry, and doesn't identify file type.
     *
     * @param path The path to remove
     */
    void protoDelete(const KURL &path);
    
    /**
     * Change file or directory mode. Also supports recursive mode changes.
     *
     * @param path The file's path
     * @param mode The new file mode
     * @param recursive Should the mode be recursively changed
     */
    void protoChmod(const KURL &path, int mode, bool recursive);
    
    /**
     * Returns this socket's parent thread.
     *
     * @return Socket's parent thread
     */
    Thread *thread() { return m_thread; }
    
    /**
     * Returns the protocol name of this socket.
     *
     * @return This socket's protocol name
     */
    TQString protocolName() { return m_protocol; }
    
    /**
     * This method should return the socket's features by or-ing the values in
     * SocketFeatures enum.
     *
     * @return Socket's features
     */
    virtual int features() = 0;
    
    /**
     * This method should return true if this socket is connected.
     *
     * @return True if the socket has successfully connected
     */
    virtual bool isConnected() = 0;
    
    /**
     * This method should return true if the connection is encrypted by some method.
     *
     * @return True if the connection is encrypted
     */
    virtual bool isEncrypted() = 0;
    
    /**
     * Returns true if the socket is currently busy performing an action.
     *
     * @return True if the socket is busy
     */
    virtual bool isBusy() { return m_currentCommand != Commands::CmdNone; }

    /**
     * Emit an engine error code.
     *
     * @param code The error code
     * @param param1 Optional string parameter
     */
    void emitError(ErrorCode code, const TQString &param1 = 0);
    
    /**
     * Emit an engine event.
     *
     * @param type Event type
     * @param param1 Optional string parameter
     * @param param2 Optional string parameter
     */
    void emitEvent(Event::Type type, const TQString &param1 = 0, const TQString &param2 = 0);
    
    /**
     * Emit an engine event containing a directory listing.
     *
     * @param type Event type
     * @param param1 The DirectoryListing parameter
     */
    void emitEvent(Event::Type type, DirectoryListing param1);
    
    /**
     * Emit an engine event containing a filesize.
     *
     * @param type Event type
     * @param param1 The filesize parameter
     */
    void emitEvent(Event::Type type, filesize_t param1);
    
    /**
     * Emit an engine event containing a custom pointer.
     *
     * @param type Event type
     * @param param1 The custom pointer parameter
     */
    void emitEvent(Event::Type type, void *param1);
    
    /**
     * This method will set the socket's remote encoding which will be used when
     * converting filenames into UTF-8 and back.
     *
     * @param encoding A valid encoding name
     */
    virtual void changeEncoding(const TQString &encoding);
    
    /**
     * Retrieve the KRemoteEncoding object for this socket set to the appropriate
     * encoding.
     *
     * @return The KRemoteEncoding object
     */
    KRemoteEncoding *remoteEncoding() { return m_remoteEncoding; }
    
    /**
     * Sets the current directory path.
     *
     * @param path The current directory path
     */
    void setCurrentDirectory(const TQString &path) { m_currentDirectory = path; }
    
    /**
     * Get the current directory path.
     *
     * @return The current directory path.
     */
    virtual TQString getCurrentDirectory() { return m_currentDirectory; }
    
    /**
     * Sets the default directory path (like a remote home directory).
     *
     * @param path The default directory path
     */
    void setDefaultDirectory(const TQString &path) { m_defaultDirectory = path; }
    
    /**
     * Get the default directory path.
     *
     * @return The default directory path
     */
    virtual TQString getDefaultDirectory() { return m_defaultDirectory; }
    
    /**
     * Sets the url this socket is connected to.
     *
     * @param url The url this socket is connected to
     */
    void setCurrentUrl(const KURL &url) { m_currentUrl = url; }
    
    /**
     * Get the url this socket is connected to.
     *
     * @return The url this socket is currently connected to
     */
    KURL getCurrentUrl() { return m_currentUrl; }
    
    /**
     * Sets the command the socket is currently executing.
     *
     * @param type Command type
     */
    void setCurrentCommand(Commands::Type type) { m_currentCommand = type; }
    
    /**
     * Get the current socket command.
     *
     * @return The current socket command
     */
    Commands::Type getCurrentCommand();
    
    /**
     * Get the toplevel socket command in the command chain.
     *
     * @return The toplevel socket command
     */
    Commands::Type getToplevelCommand();
    
    /**
     * Get the command that executed the current command. Note that this
     * is valid only if the current command is chained. Otherwise this
     * method returns Commands::CmdNone.
     *
     * @return The previous command
     */
    Commands::Type getPreviousCommand();
    
    /**
     * Get the last directory listing made by protoList.
     *
     * @return The last directory listing
     */
    DirectoryListing getLastDirectoryListing() { return m_lastDirectoryListing; }
    
    /**
     * Get the last stat response made by protoStat.
     *
     * @return The last stat response
     */
    DirectoryEntry getStatResponse() { return m_lastStatResponse; }
    
    /**
     * Get the number of bytes transfered from the beginning of the transfer.
     *
     * @return The number of bytes transfered
     */
    filesize_t getTransferBytes() { return m_transferBytes; }
    
    /**
     * Get the current transfer speed.
     *
     * @return The current transfer speed.
     */
    filesize_t getTransferSpeed();
    
    /**
     * This method will be called every cycle. It should be usually used to
     * poll the data transfer socket.
     */
    virtual void poll() = 0;
    
    /**
     * Wakeup the last command processor with a specific wakeup event. This
     * is used for async two-way communication between the engine and the
     * GUI (wakeup event is a reply from the GUI).
     *
     * By default this method just passes the event to the currently active
     * command processor.
     *
     * @param event The wakeup event that should be passed to the command class
     */
    virtual void wakeup(WakeupEvent *event);
    
    /**
     * Reset the current command class, possibly invoking the calling chained
     * command class or completing the operation.
     *
     * @param code The result code
     */
    virtual void resetCommandClass(ResetCode code = Ok);
    
    /**
     * Add a command class to the command chain so that it will be executed next.
     *
     * @param cmd The command class to add
     */
    void addToCommandChain(Commands::Base *cmd) { m_commandChain.append(cmd); }
    
    /**
     * Execute the next command.
     */
    void nextCommand();
    
    /**
     * Schedule the execution of the next command in the next thread loop.
     */
    void nextCommandAsync();
    
    /**
     * Returns true if the current command has been chained from another command class.
     *
     * @return True if the current command has been chained
     */
    bool isChained() { return m_commandChain.count() > 0; }
    
    /**
     * Set the error reporting on or off. This variable is then used by some
     * command classes do determine if they should emit errors and reset with
     * failure or if they should just silently ignore the error and reset
     * the command class with an Ok code.
     *
     * @param value Error reporting value
     */
    void setErrorReporting(bool value) { m_errorReporting = value; }
    
    /**
     * Get the current error reporting setting. This only makes sense if the
     * class is chained - otherwise this allways returns true.
     *
     * @return The current error reporting setting
     */
    bool errorReporting() { return m_errorReporting || !isChained(); }
    
    /**
     * Returns true if the current operation should abort. This method should be
     * used when the underlying socket implementation is doing blocking operations.
     *
     * @return True if the operation should be aborted
     */
    bool shouldAbort() { return m_shouldAbort; }
protected:
    /**
     * Call this method when a long wait period has started or ended. If the wait
     * isn't nulled before the timeout is reached the current action will be aborted
     * and the socket will be disconnected.
     *
     * @param start True if the wait period should start, false if it should end
     */
    void timeoutWait(bool start);
    
    /**
     * Reset the timeout counter. Call this once in a while during long wait periods
     * to notify the engine that the socket is still responsive.
     */
    void timeoutPing();
    
    /**
     * Check if we should timeout. This method might cause a disconnect if the timeout
     * value is reached.
     */
    void timeoutCheck();
    
    /**
     * Enable the issue of keepalive packets.
     */
    void keepaliveStart();
    
    /**
     * Check if we should transmit a new keepalive packet.
     */
    void keepaliveCheck();
protected:
    KRemoteEncoding *m_remoteEncoding;
    
    Commands::Base *m_cmdData;
    TQPtrList<Commands::Base> m_commandChain;
    
    Thread *m_thread;
    DirectoryListing m_lastDirectoryListing;
    DirectoryEntry m_lastStatResponse;
    
    filesize_t m_transferBytes;
    time_t m_speedLastTime;
    filesize_t m_speedLastBytes;
    
    TQTime m_timeoutCounter;
    TQTime m_keepaliveCounter;
private:
    TQMap<TQString, TQString> m_config;
    TQString m_currentDirectory;
    TQString m_defaultDirectory;
    KURL m_currentUrl;
    TQString m_protocol;
    Commands::Type m_currentCommand;
    bool m_errorReporting;
    bool m_shouldAbort;
    TQGuardedPtr<ConnectionRetry> m_connectionRetry;
};

}

#endif