ftp_paradise 1.4.5 → 1.5.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +155 -28
  3. data/bin/{iftp → ftp_paradise_shell} +1 -1
  4. data/doc/README.gen +97 -15
  5. data/doc/todo/{TODO_FOR_FTP_PARADISE_PROJECT.md → todo_for_the_ftp_paradise_project.md} +11 -1
  6. data/ftp_paradise.gemspec +30 -39
  7. data/lib/ftp_paradise/base/base.rb +375 -0
  8. data/lib/ftp_paradise/colours/colours.rb +27 -27
  9. data/lib/ftp_paradise/colours/use_colours.rb +6 -1
  10. data/lib/ftp_paradise/configuration/configuration.rb +7 -4
  11. data/lib/ftp_paradise/connection/README.md +0 -0
  12. data/lib/ftp_paradise/connection/connection.rb +2782 -15
  13. data/lib/ftp_paradise/constants/constants.rb +91 -5
  14. data/lib/ftp_paradise/entry/entry.rb +42 -5
  15. data/lib/ftp_paradise/{connection → gui/gtk3/ftp_client}/constants.rb +33 -21
  16. data/lib/ftp_paradise/gui/{shared_code/ftp_paradise/ftp_paradise_module.rb → gtk3/ftp_client/ftp_client.rb} +658 -170
  17. data/lib/ftp_paradise/gui/gtk3/ftp_client/misc.rb +27 -0
  18. data/lib/ftp_paradise/project/project.rb +11 -15
  19. data/lib/ftp_paradise/requires/require_class_connection.rb +7 -0
  20. data/lib/ftp_paradise/requires/require_net_ftp.rb +7 -0
  21. data/lib/ftp_paradise/requires/require_the_ftp_paradise_project.rb +4 -3
  22. data/lib/ftp_paradise/requires/require_the_ftp_paradise_project_with_the_GUI_bindings.rb +1 -1
  23. data/lib/ftp_paradise/requires/require_the_toplevel_methods.rb +1 -0
  24. data/lib/ftp_paradise/{interactive_ftp → shell}/menu.rb +564 -449
  25. data/lib/ftp_paradise/shell/shell.rb +2321 -0
  26. data/lib/ftp_paradise/toplevel_methods/connect.rb +3 -0
  27. data/lib/ftp_paradise/toplevel_methods/dataset.rb +111 -0
  28. data/lib/ftp_paradise/toplevel_methods/file_related_actions.rb +4 -3
  29. data/lib/ftp_paradise/toplevel_methods/ftp_object.rb +6 -5
  30. data/lib/ftp_paradise/toplevel_methods/login_name.rb +6 -4
  31. data/lib/ftp_paradise/toplevel_methods/misc.rb +19 -0
  32. data/lib/ftp_paradise/toplevel_methods/opn.rb +1 -1
  33. data/lib/ftp_paradise/toplevel_methods/password.rb +4 -2
  34. data/lib/ftp_paradise/toplevel_methods/port.rb +4 -1
  35. data/lib/ftp_paradise/toplevel_methods/remote_url.rb +11 -5
  36. data/lib/ftp_paradise/toplevel_methods/upload_and_download.rb +1 -0
  37. data/lib/ftp_paradise/version/version.rb +6 -1
  38. data/lib/ftp_paradise/www/web_interface.cgi +1 -1
  39. data/lib/ftp_paradise/yaml/automatically_connect_on_startup_of_the_interactive_ftp_shell.yml +0 -0
  40. data/lib/ftp_paradise/yaml/debug.yml +0 -0
  41. data/lib/ftp_paradise/yaml/open_in_default_editor.yml +0 -0
  42. data/lib/ftp_paradise/yaml/show_full_names.yml +0 -0
  43. data/lib/ftp_paradise/yaml/use_colours.yml +0 -0
  44. data/test/testing_minimal_pure_net_ftp_example_to_connect.rb +13 -3
  45. metadata +52 -126
  46. data/lib/ftp_paradise/base/cliner.rb +0 -23
  47. data/lib/ftp_paradise/base/colours.rb +0 -83
  48. data/lib/ftp_paradise/base/prototype.rb +0 -171
  49. data/lib/ftp_paradise/base/reset.rb +0 -29
  50. data/lib/ftp_paradise/connection/data.rb +0 -164
  51. data/lib/ftp_paradise/connection/debug.rb +0 -78
  52. data/lib/ftp_paradise/connection/directory_handling.rb +0 -271
  53. data/lib/ftp_paradise/connection/do_login.rb +0 -108
  54. data/lib/ftp_paradise/connection/download.rb +0 -86
  55. data/lib/ftp_paradise/connection/file_handling.rb +0 -174
  56. data/lib/ftp_paradise/connection/ftp_object.rb +0 -21
  57. data/lib/ftp_paradise/connection/initialize.rb +0 -88
  58. data/lib/ftp_paradise/connection/initialize_a_new_net_ftp_object_with_this_url.rb +0 -20
  59. data/lib/ftp_paradise/connection/is_connected.rb +0 -46
  60. data/lib/ftp_paradise/connection/misc.rb +0 -474
  61. data/lib/ftp_paradise/connection/notify.rb +0 -71
  62. data/lib/ftp_paradise/connection/password.rb +0 -47
  63. data/lib/ftp_paradise/connection/port.rb +0 -33
  64. data/lib/ftp_paradise/connection/remote_pwd.rb +0 -72
  65. data/lib/ftp_paradise/connection/remote_url.rb +0 -164
  66. data/lib/ftp_paradise/connection/remove.rb +0 -143
  67. data/lib/ftp_paradise/connection/reset.rb +0 -78
  68. data/lib/ftp_paradise/connection/run.rb +0 -18
  69. data/lib/ftp_paradise/connection/set_array_available_hosts.rb +0 -27
  70. data/lib/ftp_paradise/connection/set_input.rb +0 -18
  71. data/lib/ftp_paradise/connection/show.rb +0 -153
  72. data/lib/ftp_paradise/connection/sync_ftp_object_onto_the_main_namespace.rb +0 -24
  73. data/lib/ftp_paradise/connection/transfer_mode.rb +0 -163
  74. data/lib/ftp_paradise/connection/upload.rb +0 -253
  75. data/lib/ftp_paradise/connection/use_default_dataset.rb +0 -40
  76. data/lib/ftp_paradise/connection/username.rb +0 -42
  77. data/lib/ftp_paradise/constants/misc.rb +0 -57
  78. data/lib/ftp_paradise/constants/namespace.rb +0 -14
  79. data/lib/ftp_paradise/constants/newline.rb +0 -14
  80. data/lib/ftp_paradise/constants/roebe.rb +0 -31
  81. data/lib/ftp_paradise/constants/roebe_ftp_constants.rb +0 -233
  82. data/lib/ftp_paradise/gui/gtk2/ftp_paradise.rb +0 -34
  83. data/lib/ftp_paradise/gui/gtk3/ftp_paradise.rb +0 -34
  84. data/lib/ftp_paradise/interactive_ftp/constants.rb +0 -103
  85. data/lib/ftp_paradise/interactive_ftp/directory_handling.rb +0 -216
  86. data/lib/ftp_paradise/interactive_ftp/help.rb +0 -50
  87. data/lib/ftp_paradise/interactive_ftp/initialize.rb +0 -27
  88. data/lib/ftp_paradise/interactive_ftp/interactive_ftp.rb +0 -998
  89. data/lib/ftp_paradise/interactive_ftp/main_loop.rb +0 -51
  90. data/lib/ftp_paradise/interactive_ftp/misc.rb +0 -208
  91. data/lib/ftp_paradise/interactive_ftp/mode.rb +0 -124
  92. data/lib/ftp_paradise/interactive_ftp/readline.rb +0 -113
  93. data/lib/ftp_paradise/interactive_ftp/remove.rb +0 -97
  94. data/lib/ftp_paradise/interactive_ftp/reset.rb +0 -90
  95. data/lib/ftp_paradise/interactive_ftp/run.rb +0 -22
  96. data/lib/ftp_paradise/interactive_ftp/show.rb +0 -184
  97. data/lib/ftp_paradise/interactive_ftp/upload.rb +0 -90
  98. data/lib/ftp_paradise/interactive_ftp/user_input.rb +0 -53
  99. data/lib/ftp_paradise/toplevel_methods/can_connect_to_remote_site.rb +0 -28
  100. data/lib/ftp_paradise/toplevel_methods/clear_user_dataset.rb +0 -28
  101. data/lib/ftp_paradise/toplevel_methods/data.rb +0 -31
  102. data/lib/ftp_paradise/toplevel_methods/determine_user_dataset_from_this_hash.rb +0 -37
@@ -2,34 +2,2801 @@
2
2
  # Encoding: UTF-8
3
3
  # frozen_string_literal: true
4
4
  # =========================================================================== #
5
+ # === FtpParadise::Connection
6
+ #
5
7
  # This is the "connection class". It will have methods that can be use
6
- # when we are connected to a remote site (via the FTP protocol).
8
+ # when the user is connected to a remote site (via the FTP protocol).
7
9
  #
8
10
  # Rather than keeping FTP-related state within this class, such as remote
9
- # URL and such, we will instead use FtpParadise module methods.
11
+ # URL and such, we will instead use FtpParadise toplevel-module methods.
12
+ # Or, at the least, we will tap into that dataset if it has been
13
+ # assigned by the user.
14
+ #
15
+ # Usage example:
16
+ #
17
+ # FtpParadise::Connection.new(ARGV)
18
+ #
10
19
  # =========================================================================== #
11
20
  # Possible errors and failures when we are trying to connect:
12
21
  #
13
22
  # Net::FTPPermError: 530 Please login with USER and PASS.
14
23
  #
15
- # Net::FTPConnectionError is raised if we are no longer connected to
16
- # the remote FTP site.
24
+ # Net::FTPConnectionError is raised if we are no longer connected
25
+ # to the remote FTP site.
17
26
  #
18
27
  # Errno::ETIMEDOUT is raised when a timeout event occurred.
28
+ #
19
29
  # =========================================================================== #
20
30
  # The official documentation for Ruby-FTP can be found here:
21
31
  #
22
32
  # https://ruby-doc.org/stdlib/libdoc/net/ftp/rdoc/Net/FTP.html
23
33
  #
24
34
  # =========================================================================== #
25
- require 'ftp_paradise/connection/initialize.rb'
26
- require 'ftp_paradise/connection/data.rb'
27
- require 'ftp_paradise/connection/debug.rb'
28
- require 'ftp_paradise/connection/misc.rb'
29
- require 'ftp_paradise/connection/notify.rb'
30
- require 'ftp_paradise/connection/remote_pwd.rb'
31
- require 'ftp_paradise/connection/remove.rb'
32
- require 'ftp_paradise/connection/show.rb'
33
- require 'ftp_paradise/connection/upload.rb'
34
- require 'ftp_paradise/version/version.rb'
35
- require 'ftp_paradise/configuration/configuration.rb'
35
+ # require 'ftp_paradise/connection/connection.rb'
36
+ # =========================================================================== #
37
+ module FtpParadise
38
+
39
+ class Connection # === FtpParadise::Connection
40
+
41
+ require 'ftp_paradise/base/base.rb'
42
+ include ::FtpParadise::Base
43
+
44
+ require 'ftp_paradise/requires/require_net_ftp.rb'
45
+ require 'ftp_paradise/requires/require_the_toplevel_methods.rb'
46
+ require 'ftp_paradise/entry/entry.rb'
47
+ require 'ftp_paradise/configuration/configuration.rb'
48
+
49
+ # ========================================================================= #
50
+ # === NAMESPACE
51
+ # ========================================================================= #
52
+ NAMESPACE = inspect
53
+
54
+ # ========================================================================= #
55
+ # === BE_VERBOSE
56
+ # ========================================================================= #
57
+ BE_VERBOSE = true
58
+
59
+ # ========================================================================= #
60
+ # === DEFAULT_TRANSFER_MODE
61
+ # ========================================================================= #
62
+ DEFAULT_TRANSFER_MODE = :ascii # Which transfer mode to use by default.
63
+
64
+ # ========================================================================= #
65
+ # === DEFAULT_PORT
66
+ # ========================================================================= #
67
+ DEFAULT_PORT = 21
68
+
69
+ # ========================================================================= #
70
+ # === DEFAULT_USER_NAME
71
+ #
72
+ # In the past this was set to a String (the user name); but since as
73
+ # of October 2018, it will default to nil, so that we really initialize
74
+ # the whole project to a nil-state (as the default). This thus allows
75
+ # us to determine whether this has been changed, aka initialized.
76
+ # ========================================================================= #
77
+ DEFAULT_USER_NAME = nil
78
+
79
+ # ========================================================================= #
80
+ # === RUN_ALREADY
81
+ # ========================================================================= #
82
+ RUN_ALREADY = true
83
+
84
+ # ========================================================================= #
85
+ # === initialize
86
+ #
87
+ # The first argument to this method should be the remote host's URL.
88
+ # ========================================================================= #
89
+ def initialize(
90
+ i = ARGV,
91
+ run_already = RUN_ALREADY
92
+ )
93
+ reset
94
+ # ======================================================================= #
95
+ # - If we pass in a Hash as the first argument, then we will use
96
+ # set_data(), otherwise we will set individually it all individually.
97
+ # ======================================================================= #
98
+ if i.is_a? Hash
99
+ set_data(i)
100
+ else
101
+ set_input(i)
102
+ end
103
+ case i
104
+ # ======================================================================= #
105
+ # === :dont_run_yet
106
+ # ======================================================================= #
107
+ when :dont_run_yet,
108
+ :do_not_run_yet
109
+ run_already = false
110
+ end
111
+ case run_already
112
+ # ======================================================================= #
113
+ # === :dont_run_yet
114
+ # ======================================================================= #
115
+ when :dont_run_yet
116
+ run_already = false
117
+ end
118
+ if run_already.is_a? Hash
119
+ _ = run_already
120
+ if _.has_key? :connect_to_this_host
121
+ set_this_host(
122
+ _.delete(:connect_to_this_host)
123
+ )
124
+ end
125
+ run_already = RUN_ALREADY # Restore to the default in this case.
126
+ end
127
+ # ======================================================================= #
128
+ # === Handle blocks given to this method next
129
+ # ======================================================================= #
130
+ if block_given?
131
+ yielded = yield
132
+ case yielded
133
+ # ===================================================================== #
134
+ # === :do_not_run_yet
135
+ # ===================================================================== #
136
+ when :do_not_run_yet
137
+ run_already = false
138
+ # ===================================================================== #
139
+ # The "default" dataset defaults to my personal FTP login dataset.
140
+ # ===================================================================== #
141
+ when :use_default_dataset,
142
+ :default_dataset,
143
+ :default
144
+ use_default_dataset
145
+ end
146
+ end
147
+ run if run_already
148
+ end
149
+
150
+ # ========================================================================= #
151
+ # === reset (reset tag)
152
+ # ========================================================================= #
153
+ def reset
154
+ super()
155
+ # ======================================================================= #
156
+ # === @namespace
157
+ # ======================================================================= #
158
+ @namespace = NAMESPACE
159
+ # ======================================================================= #
160
+ # === @ftp_object
161
+ # ======================================================================= #
162
+ @ftp_object = nil
163
+ # ======================================================================= #
164
+ # === @input
165
+ # ======================================================================= #
166
+ @input = nil
167
+ populate_internal_hash_with_default_values
168
+ # ======================================================================= #
169
+ # The next method-call must come after
170
+ # populate_internal_hash_with_default_values().
171
+ # ======================================================================= #
172
+ set_be_verbose if BE_VERBOSE
173
+ set_port
174
+ set_array_available_hosts
175
+ set_default_transfer_mode :be_quiet
176
+ set_username
177
+ end
178
+
179
+ # ========================================================================= #
180
+ # === binary=
181
+ # ========================================================================= #
182
+ def binary=(i = true)
183
+ @internal_hash[:transfer_mode] = :binary
184
+ ftp_object?.binary = i
185
+ end
186
+
187
+ # ========================================================================= #
188
+ # === binary_mode?
189
+ # ========================================================================= #
190
+ def binary_mode?
191
+ @internal_hash[:transfer_mode] == :binary
192
+ end
193
+
194
+ # ========================================================================= #
195
+ # === passive=
196
+ # ========================================================================= #
197
+ def passive=(i = true)
198
+ if ftp_object?
199
+ ftp_object?.passive = i
200
+ else
201
+ e 'In .passive=: No ftp-object has been instantiated yet.'
202
+ end
203
+ end; alias set_passive passive= # === set_passive
204
+
205
+ # ========================================================================= #
206
+ # === try_to_download_this_remote_file
207
+ # ========================================================================= #
208
+ def try_to_download_this_remote_file(
209
+ i, be_verbose = false, &block
210
+ )
211
+ if block_given?
212
+ yielded = yield
213
+ case yielded
214
+ when :be_verbose
215
+ be_verbose = true
216
+ end
217
+ end
218
+ e 'Trying to download `'+steelblue(i)+'` next.' if be_verbose
219
+ @ftp_object.getbinaryfile(i)
220
+ if be_verbose
221
+ e 'Download of '+steelblue(i)+' has finished! It is '\
222
+ 'now at '+sfile(return_pwd+i)
223
+ end
224
+ end; alias getbinaryfile try_to_download_this_remote_file # === getbinaryfile
225
+ alias download_binary_file try_to_download_this_remote_file # === download_binary_file
226
+
227
+ # ========================================================================= #
228
+ # === list (raw tag)
229
+ #
230
+ # This method must yield the result of .list(), as Array.
231
+ # ========================================================================= #
232
+ def list(i = '*')
233
+ ftp_object?.list(i)
234
+ end; alias raw_list list # === raw_list
235
+
236
+ # ========================================================================= #
237
+ # === nlst?
238
+ #
239
+ # This method will return an array of filenames in the remote
240
+ # directory. This will yield less information than the "ls -l"
241
+ # variant, aka list().
242
+ #
243
+ # Documentation:
244
+ #
245
+ # https://ruby-doc.org/stdlib/libdoc/net/ftp/rdoc/Net/FTP.html#method-i-nlst
246
+ #
247
+ # ========================================================================= #
248
+ def nlst?
249
+ ftp_object?.nlst
250
+ end; alias nlst nlst? # === nlst
251
+
252
+ # ========================================================================= #
253
+ # === sendcmd
254
+ #
255
+ # Sends a command and returns the response of the server.
256
+ #
257
+ # This has to be rescued, because there are lots of different errors
258
+ # possible.
259
+ # ========================================================================= #
260
+ def sendcmd(i)
261
+ begin
262
+ ftp_object?.sendcmd(i)
263
+ rescue Exception => error
264
+ pp error
265
+ e '(This error may be due to the remote file not existing.)'
266
+ end
267
+ end
268
+
269
+ # ========================================================================= #
270
+ # === remove_file
271
+ #
272
+ # This method will delete a remote file.
273
+ #
274
+ # The API should remain fairly flexible.
275
+ #
276
+ # Example:
277
+ #
278
+ # ftp_connection?.remove_file(i.text?) { :be_verbose }
279
+ #
280
+ # ========================================================================= #
281
+ def remove_file(
282
+ i, be_verbose = false, &block
283
+ )
284
+ if block_given?
285
+ yielded = yield
286
+ case yielded
287
+ # ===================================================================== #
288
+ # === :be_verbose
289
+ # ===================================================================== #
290
+ when :be_verbose
291
+ be_verbose = true
292
+ end
293
+ end
294
+ e 'Deleting the remote file at '+steelblue(i)+' next:' if be_verbose
295
+ ftp_connection?.delete(i)
296
+ e 'Deleting the remote file at '+steelblue(i)+' has been completed.' if be_verbose
297
+ end; alias delete_file remove_file # === delete_file
298
+ alias delete remove_file # === delete
299
+
300
+ # ========================================================================= #
301
+ # === option
302
+ #
303
+ # This method will issue an OPTS command. The first argument should
304
+ # be the name of the option that is to be set. Additional arguments
305
+ # are treated as parameter to that command.
306
+ #
307
+ # Example:
308
+ #
309
+ # option('UTF8', 'ON') => 'OPTS UTF8 ON'
310
+ #
311
+ # ========================================================================= #
312
+ def option(i, optional_argument = nil)
313
+ ftp_connection?.option(i, optional_argument)
314
+ end
315
+
316
+ # ========================================================================= #
317
+ # === set_remote_url
318
+ #
319
+ # This method will do some sanitizing before it sets a proper and
320
+ # valid hostname. Remember to keep the 'default' entry at the
321
+ # current main FTP host you use.
322
+ # ========================================================================= #
323
+ def set_remote_url(
324
+ i = :default,
325
+ be_verbose = true
326
+ )
327
+ i = :default? if i.nil?
328
+ if i.is_a? Hash # Handle Hash as input here.
329
+ if i.has_key?(:to)
330
+ i = i[:to]
331
+ end
332
+ end
333
+ # ======================================================================= #
334
+ # The next block is mostly for my custom constants.
335
+ # You can simply pass in your own Hash.
336
+ # ======================================================================= #
337
+ case i # Do some sanitizing. This is a String here. (case tag)
338
+ # ======================================================================= #
339
+ # === bplaced (this is equivalent to shevy)
340
+ # ======================================================================= #
341
+ when /^-?-?bplaced$/i,
342
+ /^-?-?shevy$/i,
343
+ 'default'
344
+ set_data(:bplaced)
345
+ i = BPLACED.first
346
+ # ======================================================================= #
347
+ # === ?
348
+ # ======================================================================= #
349
+ when '?'
350
+ feedback_login_hosts
351
+ # ======================================================================= #
352
+ # === uniwien_homepage
353
+ # ======================================================================= #
354
+ when /^uniwien_?homepage/
355
+ set_data(UNIWIEN_HOMEPAGE)
356
+ i = UNIWIEN_HOMEPAGE.first
357
+ # ======================================================================= #
358
+ # === unet
359
+ # ======================================================================= #
360
+ when 'unet','uni',
361
+ 'uniftp'
362
+ set_data(UNIVIE)
363
+ i = UNIVIE.first
364
+ # ======================================================================= #
365
+ # === a1
366
+ # ======================================================================= #
367
+ when /^a1/
368
+ set_data(A1)
369
+ i = A1.first
370
+ # ======================================================================= #
371
+ # === byte
372
+ # ======================================================================= #
373
+ when /^byte/ # This also includese bytehost.
374
+ set_data(BYTEHOST)
375
+ i = BYTEHOST.first
376
+ # ======================================================================= #
377
+ # === zerofees
378
+ # ======================================================================= #
379
+ when 'ZEROFEES','zero','ZERO'
380
+ set_data(ZEROFEES)
381
+ i = ZEROFEES.first
382
+ # ======================================================================= #
383
+ # === ucoz
384
+ # ======================================================================= #
385
+ when 'ucoz','UCOZ',
386
+ 'LAST',
387
+ /tanriel/i,
388
+ 'last'
389
+ set_data(UCOZ)
390
+ i = UCOZ.first
391
+ end
392
+ case i.to_s
393
+ # ======================================================================= #
394
+ # === shevy
395
+ # ======================================================================= #
396
+ when 'shevy','5','default' # Current default entry.
397
+ i = SQUARE7.first
398
+ # ======================================================================= #
399
+ # === a1
400
+ # ======================================================================= #
401
+ when '1','a1'
402
+ i = A1.first
403
+ # ======================================================================= #
404
+ # === unet
405
+ # ======================================================================= #
406
+ when '2','unet','uni','uniftp'
407
+ i = UNIVIE.first
408
+ # ======================================================================= #
409
+ # === geas
410
+ # ======================================================================= #
411
+ when '3',
412
+ 'geas'
413
+ i = GEAS.first
414
+ # ======================================================================= #
415
+ # === byte
416
+ # ======================================================================= #
417
+ when '4',
418
+ 'byte'
419
+ i = BYTEHOST.first
420
+ end
421
+ i = i.to_s # Need a String here.
422
+ # ======================================================================= #
423
+ # === Provide more information to the user
424
+ # ======================================================================= #
425
+ if debug?
426
+ opnn; e "The remote URL was set to: #{sfancy(i)}"
427
+ end
428
+ if be_verbose
429
+ e "Setting url to #{sfancy(i)} now."
430
+ end
431
+ FtpParadise.set_remote_url(i)
432
+ # ======================================================================= #
433
+ # And we will always initialize a new ftp-object as well, whenever
434
+ # we call this method:
435
+ # ======================================================================= #
436
+ initialize_a_new_net_ftp_object_with_this_remote_url(i)
437
+ end; alias set_this_host set_remote_url # === set_this_host
438
+ alias set_host set_remote_url # === set_host
439
+ alias set_url set_remote_url # === set_url
440
+ alias host= set_remote_url # === host=
441
+ alias url= set_remote_url # === url=
442
+ alias set_remote_host set_remote_url # === set_remote_host
443
+
444
+ # ========================================================================= #
445
+ # === show_host_user_name_port_and_password
446
+ #
447
+ # Inform us about the basic settings.
448
+ # ========================================================================= #
449
+ def show_host_user_name_port_and_password(
450
+ do_use_spacer_around_the_output = true
451
+ )
452
+ ljust = 15
453
+ e if do_use_spacer_around_the_output
454
+ e ('Host: ' ).ljust(ljust)+sfancy(host?)
455
+ e ('User-Name: ').ljust(ljust)+sfancy(user_name?.to_s)
456
+ e ('Port: ' ).ljust(ljust)+sfancy(port?)
457
+ e ('Password: ' ).ljust(ljust)+sfancy(password?)
458
+ e if do_use_spacer_around_the_output
459
+ end
460
+
461
+ # ========================================================================= #
462
+ # === use_default_dataset
463
+ #
464
+ # This method will just take the default dataset for my FTP connections,
465
+ # hence the "File.exist?" check.
466
+ #
467
+ # Additionally we will initialize the default net-ftp object.
468
+ #
469
+ # Up to 20.07.2022 we also automatically tried to log in, but since
470
+ # that day we no longer do this.
471
+ # ========================================================================= #
472
+ def use_default_dataset(
473
+ i = :default # ← This is the default.
474
+ )
475
+ if File.exist? FILE_ROEBE_FTP
476
+ dataset = YAML.load_file(FILE_ROEBE_FTP)
477
+ # ===================================================================== #
478
+ # Set remote-url, username and password through the following method:
479
+ # ===================================================================== #
480
+ FtpParadise.determine_user_dataset_from_this_hash(dataset, i)
481
+ # do_login
482
+ end
483
+ end
484
+
485
+ # ========================================================================= #
486
+ # === show_full_names?
487
+ # ========================================================================= #
488
+ def show_full_names?
489
+ @internal_hash[:show_full_names]
490
+ end
491
+
492
+ # ========================================================================= #
493
+ # === show_remote_listing
494
+ #
495
+ # Use this method whenever you want to show the remote entries.
496
+ #
497
+ # As of June 2016, you can pass in your own dataset into this method
498
+ # as well. It must conform to the Array with the four entries, which
499
+ # is also returned via the method sanitized_remote_directory_content?.
500
+ # ========================================================================= #
501
+ def show_remote_listing(
502
+ dataset = sanitized_remote_directory_content?,
503
+ be_verbose = be_verbose?
504
+ )
505
+ n_rjust = 10
506
+ _ = dataset
507
+ if show_full_names?
508
+ _.map! {|entry|
509
+ filename = entry[0]
510
+ entry[0] = remote_pwd?+filename # This is the file size.
511
+ entry
512
+ }
513
+ end
514
+ _.each_with_index { |array, index|
515
+ if be_verbose # Display only when in verbose mode, which is the default.
516
+ file_or_directory = array[1]
517
+ name_of_the_file = array.first
518
+ # =================================================================== #
519
+ # Get a pointer to the filesize as well.
520
+ # =================================================================== #
521
+ filesize = array[2].to_s.rjust(n_rjust)
522
+ if file_or_directory == 'directory'
523
+ name_of_the_file << '/' unless name_of_the_file.end_with? '/'
524
+ end
525
+ # =================================================================== #
526
+ # === Put a proper padding to the index
527
+ # =================================================================== #
528
+ new_index = (index+1).to_s.rjust(_.size.to_s.size)
529
+ n_pad = 125
530
+ case file_or_directory
531
+ when 'directory' # Display for directories.
532
+ name_of_the_file = sdir(name_of_the_file)
533
+ e (padding?+sdir(new_index+') ')+name_of_the_file).ljust(n_pad)+' '+
534
+ filesize
535
+ else
536
+ e (padding?+sfancy(new_index+') ')+sfancy(name_of_the_file)).ljust(n_pad)+' '+
537
+ filesize
538
+ end
539
+ end
540
+ }
541
+ end; alias show_file_listing show_remote_listing # === show_file_listing
542
+ alias show_remote_file_listing show_remote_listing # === show_remote_file_listing
543
+
544
+ # ========================================================================= #
545
+ # === show_remote_directories
546
+ # ========================================================================= #
547
+ def show_remote_directories
548
+ show_remote_directory_listing :default, :show_only_directories
549
+ end
550
+
551
+ # ========================================================================= #
552
+ # === show_full_names=
553
+ # ========================================================================= #
554
+ def show_full_names=(i = true)
555
+ @internal_hash[:show_full_names] = i
556
+ end; alias show_full_names show_full_names= # === show_full_names
557
+
558
+ # ========================================================================= #
559
+ # === show_user_and_password
560
+ # ========================================================================= #
561
+ def show_user_and_password
562
+ ljust = 12
563
+ e
564
+ e ('User-Name: ').ljust(ljust)+sfancy(user_name?.to_s)
565
+ e ('Password: ' ).ljust(ljust)+sfancy(password?)
566
+ e
567
+ end; alias show_user_name_and_password show_user_and_password # === show_user_name_and_password
568
+
569
+ # ========================================================================= #
570
+ # === sync_ftp_object_onto_the_main_namespace
571
+ #
572
+ # Invoke this method only after having made sure that ftp_object?
573
+ # returns a non-nil object.
574
+ # ========================================================================= #
575
+ def sync_ftp_object_onto_the_main_namespace
576
+ ::FtpParadise.ftp_object = self
577
+ end
578
+
579
+ # ========================================================================= #
580
+ # === upload_binary_file
581
+ #
582
+ # Use this method to upload a binary file to a remote host.
583
+ #
584
+ # The first argument `i` is the file that we wish to upload.
585
+ #
586
+ # The method will make use of the method .putbinaryfile().
587
+ #
588
+ # Documentation for that file can be found here:
589
+ #
590
+ # https://ruby-doc.org/stdlib/libdoc/net/ftp/rdoc/Net/FTP.html#method-i-putbinaryfile
591
+ #
592
+ # ========================================================================= #
593
+ def upload_binary_file(
594
+ i,
595
+ be_verbose = be_verbose?
596
+ )
597
+ be_verbose = false if be_verbose == :be_silent
598
+ if i.is_a? Array
599
+ i.each {|entry| upload_binary_file(entry, be_verbose) }
600
+ else
601
+ i = i.strip.delete(N) # Added Feb 2014.
602
+ if be_verbose
603
+ notify_the_user_about(i, __method__)
604
+ end
605
+ begin
606
+ # =================================================================== #
607
+ # Next we will delegate towards the @ftp_object:
608
+ # =================================================================== #
609
+ ftp_object?.putbinaryfile(i) # We will use the method .putbinaryfile()
610
+ @internal_hash[:uploaded_these_files] << i
611
+ if be_verbose
612
+ remote_path = rds(remote_path?+'/'+File.basename(i))
613
+ opnn; e 'Done uploading! The remote path is: '
614
+ e " #{simp(remote_path)}"
615
+ report_finished_uploading_of_this_file(i)
616
+ end
617
+ rescue Exception => error
618
+ e 'An error happened as we tried to use the method '+simp('upload_binary()')+'.'
619
+ e 'The method we used was: '+simp('ftp?.putbinaryfile(i)')
620
+ e 'We will feedback this error now (of class '+sfancy(error.class.to_s)+'):'
621
+ pp error
622
+ end
623
+ end
624
+ end; alias upload_binary upload_binary_file # === upload_binary
625
+ alias upload_this_binary_file upload_binary_file # === upload_this_binary_file()
626
+
627
+ # ========================================================================= #
628
+ # === upload_file
629
+ #
630
+ # This method will distinguish between a binary file or a text file,
631
+ # based on the transfer mode in use. The default is to work on a
632
+ # text file.
633
+ # ========================================================================= #
634
+ def upload_file(
635
+ i,
636
+ be_verbose = be_verbose?
637
+ )
638
+ if File.exist? i
639
+ case transfer_mode?
640
+ # ===================================================================== #
641
+ # === :ascii
642
+ # ===================================================================== #
643
+ when :ascii,
644
+ :text,
645
+ :default
646
+ upload_this_text_file(i, be_verbose)
647
+ # ===================================================================== #
648
+ # === :binary
649
+ # ===================================================================== #
650
+ when :binary
651
+ upload_this_binary_file(i, be_verbose)
652
+ end
653
+ update_raw_listing(:be_quiet)
654
+ else
655
+ opnn; e "No file called `#{sfile(i)}` appears to exist locally."
656
+ end
657
+ end; alias upload_this_file upload_file # === upload_this_file
658
+
659
+ # ========================================================================= #
660
+ # === set_array_available_hosts
661
+ #
662
+ # Use this method if you wish to define the available hosts. This is
663
+ # useful whenever you already have some pre-defined hosts that you wish
664
+ # to use.
665
+ # ========================================================================= #
666
+ def set_array_available_hosts(i = nil)
667
+ i = [i].flatten.compact
668
+ @internal_hash[:array_available_hosts] = i
669
+ end
670
+
671
+ # ========================================================================= #
672
+ # === set_input
673
+ # ========================================================================= #
674
+ def set_input(i)
675
+ if is_a? Symbol
676
+ i = '' # For now all Symbols are ignored here.
677
+ end
678
+ @input = i
679
+ end
680
+
681
+ # ========================================================================= #
682
+ # === set_username
683
+ #
684
+ # Set the username that you wish to use here. If the input is nil, a
685
+ # default name will be used instead.
686
+ # ========================================================================= #
687
+ def set_username(
688
+ i = DEFAULT_USER_NAME
689
+ )
690
+ i = i.first if i.is_a? Array
691
+ i = DEFAULT_USER_NAME if i.nil?
692
+ # ======================================================================= #
693
+ # The username will be stored on the toplevel-module.
694
+ # ======================================================================= #
695
+ FtpParadise.set_username(i)
696
+ end; alias set_user_name set_username # === set_user_name
697
+ alias login_name= set_username # === login_name?
698
+ alias set_name set_username # === set_name
699
+ alias set_user set_username # === set_user
700
+ alias set_login_name set_username # === set_login_name
701
+ alias user_name= set_username # === user_name?
702
+
703
+ # ========================================================================= #
704
+ # === username?
705
+ # ========================================================================= #
706
+ def username?
707
+ FtpParadise.username?.to_s
708
+ end; alias user_name? username? # === user_name?
709
+
710
+ # ========================================================================= #
711
+ # === download_remote_file (download tag)
712
+ #
713
+ # Use this method to download a remote file. If you are sure to have
714
+ # a binary file, the method download_binary_file() could be used
715
+ # instead.
716
+ #
717
+ # gettextfile(remotefile, localfile = File.basename(remotefile)) {|line| ...}
718
+ # ========================================================================= #
719
+ def download_remote_file(
720
+ i, be_verbose = be_verbose?
721
+ )
722
+ if i.is_a? Array # Handle arrays first.
723
+ i.each {|entry| download_remote_file(entry, be_verbose) }
724
+ else
725
+ if i =~ /^\d+$/ # if is a number
726
+ update_file_listing
727
+ i = return_remote_files[i.to_i - 1].first
728
+ end
729
+ if i == '*' # Here we want to download all files, as we passed in '*'.
730
+ i = []
731
+ update_file_listing
732
+ return_remote_files.each { |a,b| i << FtpParadise.rds(a) }
733
+ end
734
+ if be_verbose
735
+ notify_the_user_about(i, __method__)
736
+ end
737
+ set_file(i) # This assigns to @internal_hash[:file].
738
+ begin # We can use @file because we called set_file() before.
739
+ ftp_object?.gettextfile(file?)
740
+ basename = File.basename(file?)
741
+ e "Finished downloading `#{sandybrown(file?)}`"
742
+ e 'into `'+sdir(rds(Dir.pwd+'/'+basename))+'`.'
743
+ return file?
744
+ rescue Net::FTPPermError => error
745
+ pp error
746
+ e 'An exception occurred in the method '+sfancy('download()')+'.'
747
+ e 'The error was a '+sfancy('Permission Error')+', the input '\
748
+ 'to the method was: `'+simp(i)+'`.'
749
+ e 'Is the file that you are trying to download really '\
750
+ 'existing on the remote server?'
751
+ return false
752
+ end
753
+ end
754
+ end; alias download download_remote_file # === download
755
+ alias download_this_remote_file download_remote_file # === download_this_remote_file
756
+ alias download_this_file download_remote_file # === download_this_file
757
+
758
+ # ========================================================================= #
759
+ # === create_remote_file (touch tag)
760
+ #
761
+ # This "touches" a remote file.
762
+ # ========================================================================= #
763
+ def create_remote_file(
764
+ i,
765
+ be_verbose = be_verbose?
766
+ )
767
+ if i.is_a? Array
768
+ i.each {|entry| create_remote_file(entry, be_verbose) }
769
+ else
770
+ FileUtils.touch(i)
771
+ if be_verbose
772
+ notify_the_user_about(i, __method__)
773
+ end
774
+ upload_this_text_file(i, :be_quiet)
775
+ File.delete(i) if File.zero? i # And get rid of that file too.
776
+ end
777
+ end; alias touch create_remote_file # === touch
778
+
779
+ # ========================================================================= #
780
+ # === fancy_remote_listing
781
+ #
782
+ # This method will obtain the (remote) directory listing and then
783
+ # display it.
784
+ # ========================================================================= #
785
+ def fancy_remote_listing(
786
+ be_verbose = be_verbose?
787
+ )
788
+ update_file_listing
789
+ case be_verbose
790
+ when :be_silent,
791
+ :be_quiet
792
+ be_verbose = false
793
+ when :also_show_filesize
794
+ be_verbose = true
795
+ end
796
+ if be_verbose
797
+ e ('=' * 55)+' '+
798
+ FtpParadise.yellow('REMOTE FILES')+' '+('=' * 12)
799
+ if remote_directory_is_empty?
800
+ e "Remote `#{sdir(remote_path?)}` is empty."
801
+ e 'No files or directories can be found therein.'
802
+ else
803
+ e 'Remote content of `'+sdir(remote_path?)+'` is:'+N+N
804
+ e 'Index Filename '\
805
+ ' Filesize'
806
+ show_remote_file_listing
807
+ end
808
+ cliner
809
+ end
810
+ return remote_directory_content
811
+ end
812
+
813
+ # ========================================================================= #
814
+ # === rename
815
+ #
816
+ # This method will attempt to rename a file on the remote server.
817
+ #
818
+ # Note that this is equivalent to moving a file, which is why the alias
819
+ # move_file can also be used. Any move-file actioni s simply a rename()
820
+ # action.
821
+ #
822
+ # The first argument passed to this method should be the name of an
823
+ # existing (remote) file. The second second argument should be the
824
+ # new name of that file, or its full (remote) path.
825
+ #
826
+ # Also note that it seems as if the FTP protocol requires the full
827
+ # target location, otherwise errors such as the following might
828
+ # happen:
829
+ #
830
+ # ftp.rb in `getresp': 451 Rename/move failure: Is a directory (Net::FTPTempError)
831
+ #
832
+ # The command used by .rename() command should be equivalent to this code:
833
+ #
834
+ # SITE mv oldpath newpath
835
+ #
836
+ # Documentation for the functionality can be found here:
837
+ #
838
+ # http://ruby-doc.org/stdlib/libdoc/net/ftp/rdoc/Net/FTP.html#method-i-rename
839
+ #
840
+ # ========================================================================= #
841
+ def rename(
842
+ from,
843
+ to,
844
+ be_verbose = be_verbose?
845
+ )
846
+ to = to.first if to.is_a? Array
847
+ if from.is_a? Array # Support batch-transfer.
848
+ from.each {|entry| rename(entry, to) }
849
+ else
850
+ from = rds(from)
851
+ to = rds(to)
852
+ begin
853
+ ftp_object?.rename(from, to)
854
+ if be_verbose
855
+ opnn; e "Renamed the remote entry `#{sfancy(from)}"\
856
+ "` to `#{sfancy(to)}`."
857
+ end
858
+ rescue Net::FTPTempError => error
859
+ e "An error (#{simp('Net::FTPTempError')}) occurred "\
860
+ "in the method #{simp('rename()')}:"
861
+ pp error
862
+ end
863
+ end
864
+ end; alias rename_file rename # === rename_file
865
+ alias move_file rename # === move_file
866
+ alias rename_remote_file rename # === rename_remote_file
867
+
868
+ # ========================================================================= #
869
+ # === update_remote_file_listing
870
+ # ========================================================================= #
871
+ def update_remote_file_listing(
872
+ be_verbose = be_verbose?
873
+ )
874
+ case be_verbose
875
+ when :be_quiet
876
+ be_verbose = false
877
+ end
878
+ if is_connected?
879
+ begin
880
+ # =================================================================== #
881
+ # Make use of a method that will skip a few entries, such as
882
+ # "." or "..".
883
+ # =================================================================== #
884
+ @internal_hash[:raw_entries] = return_slightly_sanitized_entries_ignoring_a_few
885
+ rescue Exception => error
886
+ opnn; e swarn('An error happened in the method '\
887
+ 'update_remote_file_listing(), at '\
888
+ 'line: '+__LINE__.to_s+'.')
889
+ pp error.class
890
+ pp error
891
+ end
892
+ else
893
+ if be_verbose
894
+ opnn; e 'Can not update the remote file listing '\
895
+ 'because we are not connected.'
896
+ end
897
+ end
898
+ end; alias update_file_listing update_remote_file_listing # === update_file_listing
899
+ alias update_raw_listing update_remote_file_listing # === update_raw_listing
900
+ alias get_listing update_remote_file_listing # === get_listing
901
+ alias get_remote_listing update_remote_file_listing # === get_remote_listing
902
+ alias update update_remote_file_listing # === update
903
+
904
+ # ========================================================================= #
905
+ # === does_this_remote_file_exist?
906
+ # ========================================================================= #
907
+ def does_this_remote_file_exist?(i)
908
+ i = File.basename(i).strip
909
+ array = return_all_remote_files
910
+ if array.is_a?(Array) and
911
+ array.first.is_a?(String)
912
+ array.map! {|entry|
913
+ entry = FtpParadise::Entry.new(entry)
914
+ }
915
+ array.select! {|entry| entry.is_a_file? }
916
+ array.map! {|entry| entry.filename? }
917
+ end
918
+ return array.include?(i)
919
+ end
920
+
921
+ # ========================================================================= #
922
+ # === show_remote_directory_listing
923
+ #
924
+ # This will simply show the content of a remote directory.
925
+ #
926
+ # Invocation examples:
927
+ #
928
+ # show_remote_directory_listing
929
+ # show_remote_directory_listing :default, :show_only_directories
930
+ #
931
+ # ========================================================================= #
932
+ def show_remote_directory_listing(
933
+ i = list,
934
+ array_options = []
935
+ )
936
+ unless array_options.is_a? Array
937
+ array_options = [array_options]
938
+ end
939
+ case i
940
+ when :default
941
+ i = list
942
+ end
943
+ if i.is_a? Array
944
+ # ===================================================================== #
945
+ # Get rid of '.' and '..'.
946
+ # ===================================================================== #
947
+ i.reject! {|entry| entry.end_with?('..') or entry.end_with?('.') }
948
+ # ===================================================================== #
949
+ # First, turn them into entries.
950
+ # ===================================================================== #
951
+ i.map! {|entry| FtpParadise::Entry.new(entry) }
952
+ # ===================================================================== #
953
+ # Next, we can use different behaviours.
954
+ # ===================================================================== #
955
+ if array_options.include? :show_only_directories
956
+ i.select! {|entry| entry.is_a_directory? }
957
+ end
958
+ i.each {|entry| entry.show_the_line }
959
+ end
960
+ end; alias show_remote_files show_remote_directory_listing # === show_remote_files
961
+
962
+ # ========================================================================= #
963
+ # === upload (upload tag)
964
+ #
965
+ # This method can upload binary files, text files and whole directories.
966
+ # Based on that check, the method body will behave differently, and
967
+ # delegate to other methods such as upload_directory() or upload_file().
968
+ #
969
+ # A single file (as String) can be uploaded, or an Array of files. The
970
+ # upload activity will transfer the file or the files onto the remote host.
971
+ #
972
+ # The second argument specifies whether the method will be verbose and
973
+ # report back to the user, or whether the method will be quiet,
974
+ # defaulting to the return value of the method `be_verbose?`.
975
+ # ========================================================================= #
976
+ def upload(
977
+ i,
978
+ be_verbose = be_verbose?
979
+ )
980
+ be_verbose = false if be_verbose == :be_silent
981
+ if i.is_a? Array
982
+ i.each {|entry| upload(entry, be_verbose) }
983
+ else
984
+ if i == '*' # Here we want to upload all files.
985
+ i = get_all_local_files
986
+ upload(i, be_verbose)
987
+ else
988
+ # =================================================================== #
989
+ # === Handle upload of directories first
990
+ # =================================================================== #
991
+ if File.directory? i
992
+ upload_directory(i, be_verbose)
993
+ # =================================================================== #
994
+ # === Handle uploading of files next
995
+ # =================================================================== #
996
+ else
997
+ upload_file(i, be_verbose)
998
+ end
999
+ end
1000
+ end
1001
+ end
1002
+
1003
+ # ========================================================================= #
1004
+ # === uploaded_these_files?
1005
+ # ========================================================================= #
1006
+ def uploaded_these_files?
1007
+ @internal_hash[:uploaded_these_files]
1008
+ end
1009
+
1010
+ # ========================================================================= #
1011
+ # === list? (list tag)
1012
+ #
1013
+ # Returns an array of file information in the directory (the output
1014
+ # is like `ls -l`). If a block is given, it iterates through the
1015
+ # listing.
1016
+ # ========================================================================= #
1017
+ def list?(i = '*')
1018
+ # ======================================================================= #
1019
+ # We will also sanitize this a bit.
1020
+ # ======================================================================= #
1021
+ @internal_hash[:raw_entries] = return_slightly_sanitized_entries_ignoring_a_few
1022
+ return @internal_hash[:raw_entries] # And return the result here.
1023
+ end; alias ls list? # === ls
1024
+ alias populate_raw_entries list? # === populate_raw_entries
1025
+
1026
+ # ========================================================================= #
1027
+ # === list_content (list tag, ls tag)
1028
+ #
1029
+ # List available data.
1030
+ # ========================================================================= #
1031
+ def list_content
1032
+ report_current_remote_dir
1033
+ result = list?
1034
+ cliner { pp result }
1035
+ _ = result.first[0, 1]
1036
+ case _
1037
+ when 'd'
1038
+ e "Directory #{result.first}"
1039
+ # @array_directories
1040
+ when 'l'
1041
+ e "Link #{result.first}"
1042
+ else
1043
+ e "File #{result.first}"
1044
+ end
1045
+ end; alias do_list_content list_content # === list
1046
+ alias listing? list_content # === listing?
1047
+
1048
+ # ========================================================================= #
1049
+ # === file_listing_as_entries?
1050
+ # ========================================================================= #
1051
+ def file_listing_as_entries?
1052
+ _ = remote_file_listing?
1053
+ if _
1054
+ return _.map {|entry| FtpParadise::Entry.new(entry) }
1055
+ end
1056
+ return nil
1057
+ end
1058
+
1059
+ # ========================================================================= #
1060
+ # === closed?
1061
+ #
1062
+ # Returns true if the connection to our remote host is closed.
1063
+ # ========================================================================= #
1064
+ def closed?
1065
+ begin
1066
+ ftp_object?.closed? if ftp_object?
1067
+ rescue Net::FTPConnectionError
1068
+ true
1069
+ end
1070
+ end
1071
+
1072
+ # ========================================================================= #
1073
+ # === dataset?
1074
+ # ========================================================================= #
1075
+ def dataset?
1076
+ FtpParadise.data?
1077
+ end
1078
+
1079
+ # ========================================================================= #
1080
+ # === return_slightly_sanitized_entries_ignoring_a_few
1081
+ # ========================================================================= #
1082
+ def return_slightly_sanitized_entries_ignoring_a_few(
1083
+ i = '*'
1084
+ )
1085
+ ftp_object?.list(i).reject {|entry|
1086
+ entry.to_s.strip.empty? or entry.end_with?(' .') or entry.end_with?(' ..')
1087
+ }.map {|line|
1088
+ if line.end_with? ':' # <- Some remote FTP-hosts use ':' for a directory.
1089
+ line[-1,1] = '/'
1090
+ end
1091
+ line
1092
+ }
1093
+ end; alias list return_slightly_sanitized_entries_ignoring_a_few # === list
1094
+
1095
+ # ========================================================================= #
1096
+ # === populate_internal_hash_with_default_values
1097
+ # ========================================================================= #
1098
+ def populate_internal_hash_with_default_values
1099
+ # ======================================================================= #
1100
+ # === @internal_hash
1101
+ # ======================================================================= #
1102
+ @internal_hash = {}
1103
+ # ======================================================================= #
1104
+ # === :transfer_mode
1105
+ # ======================================================================= #
1106
+ @internal_hash[:transfer_mode] = :binary
1107
+ # ======================================================================= #
1108
+ # === :port
1109
+ #
1110
+ # The internal Hash keeps track of some configure-settings and slots
1111
+ # to be used that are of relevance to this class.
1112
+ # ======================================================================= #
1113
+ @internal_hash[:port] = nil # Has to be nil initially.
1114
+ # ======================================================================= #
1115
+ # === :be_verbose
1116
+ # ======================================================================= #
1117
+ @internal_hash[:be_verbose] = nil
1118
+ # ======================================================================= #
1119
+ # === :raw_entries
1120
+ # ======================================================================= #
1121
+ @internal_hash[:raw_entries] = nil
1122
+ @internal_hash[:file] = nil
1123
+ @internal_hash[:show_full_names] = false # Is false on startup.
1124
+ @internal_hash[:debug] = false
1125
+ # ======================================================================= #
1126
+ # === :array_available_hosts
1127
+ # ======================================================================= #
1128
+ @internal_hash[:array_available_hosts] = []
1129
+ # ======================================================================= #
1130
+ # === :padding
1131
+ # ======================================================================= #
1132
+ @internal_hash[:padding] = ' ' # This padding value is used for remote directory listing.
1133
+ # ======================================================================= #
1134
+ # The following Array keeps track over the files that were uploaded
1135
+ # successfully. This gives us the possibility to query this from other
1136
+ # classes.
1137
+ # ======================================================================= #
1138
+ @internal_hash[:uploaded_these_files] = []
1139
+ end
1140
+
1141
+ # ========================================================================= #
1142
+ # === is_a_directory?
1143
+ #
1144
+ # This method queries whether the given input is a (remote) directory.
1145
+ # For this to work, the given input must obviously exist as file or
1146
+ # directory.
1147
+ # ========================================================================= #
1148
+ def is_a_directory?(i)
1149
+ update_file_listing
1150
+ candidates = file_listing_as_entries?.select {|entry|
1151
+ entry.is_a_directory?
1152
+ }.map(&:last)
1153
+ candidates.include? i
1154
+ end; alias is_directory? is_a_directory? # === is_directory?
1155
+ alias is_a_directory? is_a_directory? # === is_a_directory?
1156
+ alias this_remote_directory_exists? is_a_directory? # === this_remote_directory_exists?
1157
+ alias is_dir? is_a_directory? # === is_dir?
1158
+
1159
+ # ========================================================================= #
1160
+ # === remote_directory_is_empty?
1161
+ #
1162
+ # This method will return a Boolean - true if the remote directory
1163
+ # is empty, and false otherwise.
1164
+ # ========================================================================= #
1165
+ def remote_directory_is_empty?
1166
+ _ = return_remote_directory_content
1167
+ _.reject! {|entry|
1168
+ (entry == '.') or (entry == '..')
1169
+ }
1170
+ _.empty?
1171
+ end
1172
+
1173
+ # ========================================================================= #
1174
+ # === create_this_remote_directory (mkdir tag)
1175
+ #
1176
+ # This method will attempt to create a remote directory.
1177
+ #
1178
+ # A Net::FTPPermError may result if the permission does not allow for
1179
+ # that action.
1180
+ # ========================================================================= #
1181
+ def create_this_remote_directory(
1182
+ i, be_verbose = be_verbose?
1183
+ )
1184
+ if i.is_a? Array
1185
+ i.each {|entry| create_this_remote_directory(entry, be_verbose) }
1186
+ else
1187
+ i = rds(i+'/')
1188
+ if be_verbose
1189
+ notify_the_user_about(i, __method__)
1190
+ if is_directory?(i)
1191
+ opnn; e swarn('Warning - the remote directory ')+
1192
+ sdir(i)+swarn(' already exists.')
1193
+ opnn; e swarn('We thus can not create a new directory.')
1194
+ end
1195
+ end
1196
+ begin
1197
+ ftp_object?.mkdir(i)
1198
+ rescue Net::FTPConnectionError
1199
+ opnn; e 'Not connected - is the network down/available?'
1200
+ rescue Net::FTPPermError
1201
+ opnn; e "Net::FTPPermError: Can not create the remote "\
1202
+ "directory `#{remote_path?}#{sdir(i)}`"
1203
+ opnn; e 'as it - or a file with the same name - already exists.'
1204
+ end
1205
+ end
1206
+ end; alias mkdir create_this_remote_directory # === mkdir
1207
+ alias rmkdir create_this_remote_directory # === rmkdir
1208
+ alias remote_mkdir create_this_remote_directory # === remote_mkdir
1209
+ alias create_directory create_this_remote_directory # === create_directory
1210
+ alias create_these_remote_directories create_this_remote_directory # === create_these_remote_directories
1211
+ alias remote_create_directory create_this_remote_directory # === remote_create_directory
1212
+ alias create_remote_directory create_this_remote_directory # === create_remote_directory
1213
+
1214
+ # ========================================================================= #
1215
+ # === sanitize_remote_directory_content
1216
+ #
1217
+ # The purpose of this method is to clean up the remote dataset.
1218
+ #
1219
+ # Keep in mind that the output comes in something like:
1220
+ #
1221
+ # "-rw-rw-rw- 1 web netscape 6820 May 30 2011 AppendToCookbook.rb"
1222
+ # "drwxrwxrwx 2 web netscape 8192 Oct 29 2007 CSS"
1223
+ # "-rw-rw-rw- 1 web netscape 10548 May 30 2011 Chained.rb"
1224
+ # "-rw-r--r-- 1 330 330 237904 Jun 9 14:24 11.03.2003_UniWien_Biologie_EinfuehrungInDieMikrobiologie.jpg",
1225
+ #
1226
+ # This should contain all the information that is needed.
1227
+ # ========================================================================= #
1228
+ def sanitize_remote_directory_content
1229
+ _ = []
1230
+ raw_entries?.each { |e|
1231
+ next if e.empty?
1232
+ entry = FtpParadise::Entry.new(e)
1233
+ filesize = entry.filesize?
1234
+ timestamp = entry.parsed_timestamp?
1235
+ # ===================================================================== #
1236
+ # === Exclude 3 entries next
1237
+ # ===================================================================== #
1238
+ next if e.include? 'total' or
1239
+ entry.name? == '.' or
1240
+ entry.name? == '..' # Batch next.
1241
+ # ===================================================================== #
1242
+ # === Build up the final Array
1243
+ #
1244
+ # Our Array will have four entries:
1245
+ #
1246
+ # (1) Filename
1247
+ # (2) File or Directory (String)
1248
+ # (3) Filesize
1249
+ # (4) Timestamp
1250
+ #
1251
+ # ===================================================================== #
1252
+ _ << [ rds(entry.filename?), entry.file_or_directory, filesize, timestamp ]
1253
+ }
1254
+ @internal_hash[:sanitized_remote_directory_content] = _ #.compact
1255
+ end
1256
+
1257
+ # ========================================================================= #
1258
+ # === sanitized_remote_directory_content?
1259
+ # ========================================================================= #
1260
+ def sanitized_remote_directory_content?
1261
+ update_remote_file_listing
1262
+ sanitize_remote_directory_content
1263
+ @internal_hash[:sanitized_remote_directory_content]
1264
+ end
1265
+
1266
+ # ========================================================================= #
1267
+ # === download_binary_file
1268
+ #
1269
+ # Use this method to download a binary file, by calling the method
1270
+ # getbinaryfile(). You can download as many files as you want to
1271
+ # through this method, but we expect this method to be a binary
1272
+ # file.
1273
+ #
1274
+ # Specific usage example:
1275
+ #
1276
+ # ftp?.download_binary_file('photos_2009-03-29.zip', 'ftp_photos/photos.zip')
1277
+ #
1278
+ # ========================================================================= #
1279
+ def download_binary_file(
1280
+ i,
1281
+ be_verbose = be_verbose?
1282
+ )
1283
+ if i.is_a? Array
1284
+ i.each {|entry| download_binary_file(entry) }
1285
+ else
1286
+ ftp?.getbinaryfile(i) # Delegate towards .getbinaryfile()
1287
+ if be_verbose
1288
+ e "Downloaded file #{sfile(i)}."
1289
+ end
1290
+ end
1291
+ end
1292
+
1293
+ # ========================================================================= #
1294
+ # === empty?
1295
+ # ========================================================================= #
1296
+ def empty?
1297
+ array_remote_files.empty?
1298
+ end
1299
+
1300
+ # ========================================================================= #
1301
+ # === find_matches_for
1302
+ #
1303
+ # This method will return an array of files and directories that match
1304
+ # to the provided input (which we will assume to be a query).
1305
+ # ========================================================================= #
1306
+ def find_matches_for(i)
1307
+ i = i.delete '*'
1308
+ update_file_listing
1309
+ _ = return_remote_directory_content.map(&:first)
1310
+ _ = _.grep(/#{i}/)
1311
+ return _
1312
+ end
1313
+
1314
+ # ========================================================================= #
1315
+ # === output_sorted_by_time
1316
+ #
1317
+ # This method will output the remote content in a time-sorted manner.
1318
+ # ========================================================================= #
1319
+ def output_sorted_by_time
1320
+ _ = sanitized_remote_directory_content?
1321
+ sorted_result = _.sort_by {|array|
1322
+ array.last
1323
+ }.reverse
1324
+ sorted_result.each_with_index {|array, index| index += 1
1325
+ file_or_directory = array[1]
1326
+ name_of_the_file = array.first
1327
+ if file_or_directory == 'directory'
1328
+ name_of_the_file << '/' unless name_of_the_file.end_with? '/'
1329
+ end
1330
+ index = simp( (index.to_s+') ').rjust(6))
1331
+ e index+sfancy(name_of_the_file)
1332
+ }
1333
+ end
1334
+
1335
+ # ========================================================================= #
1336
+ # === last_response
1337
+ #
1338
+ # The server's last response is available through this method here.
1339
+ # ========================================================================= #
1340
+ def last_response
1341
+ ftp_object?.last_response
1342
+ end; alias last_response? last_response # === last_response?
1343
+ alias last_server_response? last_response # === last_server_response?
1344
+
1345
+ # ========================================================================= #
1346
+ # === raw_entries?
1347
+ # ========================================================================= #
1348
+ def raw_entries?
1349
+ @internal_hash[:raw_entries]
1350
+ end; alias remote_file_listing? raw_entries? # === remote_file_listing?
1351
+ alias file_listing? raw_entries? # === file_listing?
1352
+ alias raw_listing? raw_entries? # === raw_listing?
1353
+
1354
+ # ========================================================================= #
1355
+ # === return_local_directories
1356
+ #
1357
+ # Return all local directories.
1358
+ # ========================================================================= #
1359
+ def return_local_directories
1360
+ Dir['*'].select {|entry| File.directory?(entry) }
1361
+ end
1362
+
1363
+ # ========================================================================= #
1364
+ # === modification_time_of?
1365
+ #
1366
+ # This method will give us the last modification time of a remote
1367
+ # file, by issuing the mdtm() command.
1368
+ #
1369
+ # The format returned will be in YYYMMDDhhmmss.
1370
+ #
1371
+ # If you require a parsed Time instance, you can use mtime()
1372
+ # on the ftp object.
1373
+ #
1374
+ # Symbols could also be used, such as "pp modification_time_of? :a".
1375
+ # ========================================================================= #
1376
+ def modification_time_of?(i)
1377
+ if i.is_a? Array
1378
+ i.each {|entry| modification_time_of(entry) } # <- Recursive call.
1379
+ else
1380
+ ftp_object?.mdtm(i.to_s)
1381
+ end
1382
+ end; alias mdtm modification_time_of? # === mdtm
1383
+
1384
+ # ========================================================================= #
1385
+ # === set_file
1386
+ #
1387
+ # Use only this to modify the @file variable.
1388
+ # ========================================================================= #
1389
+ def set_file(i = nil)
1390
+ @internal_hash[:file] = i
1391
+ end
1392
+
1393
+ # ========================================================================= #
1394
+ # === is_file?
1395
+ #
1396
+ # This method will check whether the input is a file or not.
1397
+ # It will call the method .is_directory?()
1398
+ # ========================================================================= #
1399
+ def is_file?(i)
1400
+ !is_a_directory?(i)
1401
+ end
1402
+
1403
+ # ========================================================================= #
1404
+ # === logged_in?
1405
+ # ========================================================================= #
1406
+ def logged_in?
1407
+ ftp_object?.instance_variable_get('@logged_in') and
1408
+ (ftp_object?.instance_variable_get('@logged_in') == true)
1409
+ end
1410
+
1411
+ # ========================================================================= #
1412
+ # === available_hosts?
1413
+ # ========================================================================= #
1414
+ def available_hosts?
1415
+ @internal_hash[:array_available_hosts]
1416
+ end; alias array_available_hosts available_hosts? # === array_available_hosts
1417
+ alias array_available_hosts? available_hosts? # === array_available_hosts?
1418
+
1419
+ # ========================================================================= #
1420
+ # === open_timeout?
1421
+ # ========================================================================= #
1422
+ def open_timeout?
1423
+ ftp_object?.open_timeout.to_s if ftp_object?.respond_to? :open_timeout
1424
+ end
1425
+
1426
+ # ========================================================================= #
1427
+ # === feedback_login_hosts
1428
+ #
1429
+ # Feedback all available login hosts, based on the information stored
1430
+ # in the Array @array_available_hosts.
1431
+ # ========================================================================= #
1432
+ def feedback_login_hosts
1433
+ opnn; e 'The followings hosts are easily available:'
1434
+ e
1435
+ available_hosts?.each { |host| e " - #{sfancy(host)}" }
1436
+ e
1437
+ end
1438
+
1439
+ # ========================================================================= #
1440
+ # === help?
1441
+ # ========================================================================= #
1442
+ def help?
1443
+ ftp_object?.help
1444
+ end; alias help help? # === help
1445
+
1446
+ # ========================================================================= #
1447
+ # === close (close tag)
1448
+ #
1449
+ # Close the connection here.
1450
+ #
1451
+ # Further operations will be impossible until a new connection
1452
+ # is opened up again, via connect().
1453
+ # ========================================================================= #
1454
+ def close
1455
+ ftp_object?.close
1456
+ end
1457
+
1458
+ # ========================================================================= #
1459
+ # === mlsd
1460
+ # ========================================================================= #
1461
+ def mlsd(i)
1462
+ ftp_object?.mlsd(i)
1463
+ end
1464
+
1465
+ # ========================================================================= #
1466
+ # === site
1467
+ # ========================================================================= #
1468
+ def site(i = nil)
1469
+ ftp_object?.site(i)
1470
+ end
1471
+
1472
+ # ========================================================================= #
1473
+ # === file?
1474
+ # ========================================================================= #
1475
+ def file?
1476
+ @internal_hash[:file]
1477
+ end
1478
+
1479
+ # ========================================================================= #
1480
+ # === system_command
1481
+ #
1482
+ # This will return system information from the remote host.
1483
+ #
1484
+ # Stuff like:
1485
+ # UNIX Type: L8
1486
+ # ========================================================================= #
1487
+ def system_command
1488
+ ftp_object?.system
1489
+ end; alias system system_command # === system
1490
+
1491
+ # ========================================================================= #
1492
+ # === report_host_port_user_name_and_password
1493
+ # ========================================================================= #
1494
+ def report_host_port_user_name_and_password
1495
+ ljust = 15
1496
+ e '- Now trying to log in to '+simp(host?)+
1497
+ ' (Port: '+swarn(port?)+') using:'
1498
+ e ' '+('Login Name: ').ljust(ljust)+sfancy(user_name?)
1499
+ e ' '+('Password: ').ljust(ljust)+sfancy(password?)
1500
+ end
1501
+
1502
+ # ========================================================================= #
1503
+ # === opnn
1504
+ # ========================================================================= #
1505
+ def opnn
1506
+ super(NAMESPACE)
1507
+ end
1508
+
1509
+ # ========================================================================= #
1510
+ # === read_timeout=
1511
+ #
1512
+ # Setter-method for the #read_timeout attribute.
1513
+ # ========================================================================= #
1514
+ def read_timeout=(i)
1515
+ ftp_object?.read_timeout = i
1516
+ end
1517
+
1518
+ # ========================================================================= #
1519
+ # === size?
1520
+ #
1521
+ # This method will return the size of the given (remote) filename.
1522
+ # ========================================================================= #
1523
+ def size?(i)
1524
+ ftp_object?.size(i)
1525
+ end; alias size size? # === size
1526
+
1527
+ # ========================================================================= #
1528
+ # === padding?
1529
+ # ========================================================================= #
1530
+ def padding?
1531
+ @internal_hash[:padding]
1532
+ end
1533
+
1534
+ # ========================================================================= #
1535
+ # === be_verbose?
1536
+ # ========================================================================= #
1537
+ def be_verbose?
1538
+ @internal_hash[:be_verbose]
1539
+ end
1540
+
1541
+ # ========================================================================= #
1542
+ # === server_welcome_message?
1543
+ #
1544
+ # This method will return the remote server's welcome message.
1545
+ # ========================================================================= #
1546
+ def server_welcome_message?
1547
+ ftp_object?.welcome
1548
+ end; alias welcome? server_welcome_message? # === welcome?
1549
+ alias welcome server_welcome_message? # === welcome
1550
+
1551
+ # ========================================================================= #
1552
+ # === noop
1553
+ # ========================================================================= #
1554
+ def noop
1555
+ ftp_object?.noop
1556
+ end
1557
+
1558
+ # ========================================================================= #
1559
+ # === last_response_code?
1560
+ #
1561
+ # Return the server's last response code.
1562
+ # ========================================================================= #
1563
+ def last_response_code?
1564
+ ftp_object?.last_response_code
1565
+ end; alias last_response_code last_response_code? # === last_response_code
1566
+
1567
+ # ========================================================================= #
1568
+ # === []
1569
+ # ========================================================================= #
1570
+ def [](i)
1571
+ update_file_listing
1572
+ if i =~ /^\d+$/ # If is a number.
1573
+ i = remote_file_listing.size if i.to_i > remote_file_listing.size
1574
+ i = remote_file_listing[i.to_i - 1].first
1575
+ end
1576
+ return i
1577
+ end
1578
+
1579
+ # ========================================================================= #
1580
+ # === notify_the_user_about
1581
+ #
1582
+ # This method is a general "user notifier". It will notify the user
1583
+ # about doing certain actions within the FtpParadise project.
1584
+ # ========================================================================= #
1585
+ def notify_the_user_about(
1586
+ i, method
1587
+ )
1588
+ case method
1589
+ # ======================================================================= #
1590
+ # === :set_transfer_mode
1591
+ # ======================================================================= #
1592
+ when :set_transfer_mode
1593
+ opnn; e "Setting mode to #{orange(i.to_s)} now."
1594
+ # ======================================================================= #
1595
+ # === :remove_remote_files
1596
+ # ======================================================================= #
1597
+ when :remove_remote_files
1598
+ opnn; e "Deleting the remote file `#{sdir(i)}` now."
1599
+ # ======================================================================= #
1600
+ # === :upload_binary_file
1601
+ # ======================================================================= #
1602
+ when :upload_binary_file
1603
+ opnn; e 'Now trying to upload the binary file `'+sfile(i)+'`'
1604
+ opnn; e 'to the remote host `'+sfancy(remote_host?)+'`.'
1605
+ # ======================================================================= #
1606
+ # === :create_this_remote_directory
1607
+ # ======================================================================= #
1608
+ when :create_this_remote_directory
1609
+ opnn; e 'Creating the remote directory `'+sdir(i)+'` now.'
1610
+ # ======================================================================= #
1611
+ # === :remote_cd
1612
+ # ======================================================================= #
1613
+ when :remote_cd
1614
+ opnn; e 'Trying to remote-change directory into `'+sdir(i)+'`.'
1615
+ # ======================================================================= #
1616
+ # === :download_this_remote_file
1617
+ # ======================================================================= #
1618
+ when :download_this_remote_file
1619
+ opnn; e "Downloading the remote file `#{sdir(i)}` now."
1620
+ # ======================================================================= #
1621
+ # === :upload_this_text_file
1622
+ # ======================================================================= #
1623
+ when :upload_this_text_file
1624
+ opnn; e 'Uploading the local text file `'+sfile(i)+'` to '\
1625
+ 'the remote host at `'+sfancy(remote_pwd?)+'`.'
1626
+ # ======================================================================= #
1627
+ # === :create_remote_file
1628
+ # ======================================================================= #
1629
+ when :create_remote_file
1630
+ opnn; e 'Creating the remote file `'+sdir(i)+'` now.'
1631
+ # ======================================================================= #
1632
+ # === :remove_remote_directory
1633
+ # ======================================================================= #
1634
+ when :remove_remote_directory
1635
+ opnn; e 'Removing the remote directory `'+sdir(i)+'` now.'
1636
+ end
1637
+ end
1638
+
1639
+ # ========================================================================= #
1640
+ # === report_finished_uploading_of_this_file
1641
+ #
1642
+ # Report that we have finished uploading a file.
1643
+ #
1644
+ # We should also denote the leading http part.
1645
+ # ========================================================================= #
1646
+ def report_finished_uploading_of_this_file(i)
1647
+ if is_connected?
1648
+ remote_path = "http://#{rds(remote_path?+File.basename(i))}"
1649
+ opnn; e "Done uploading `#{sfile(i)}` to `"\
1650
+ "#{sdir(remote_path)}`!"
1651
+ end
1652
+ end
1653
+
1654
+ # ========================================================================= #
1655
+ # === password?
1656
+ # ========================================================================= #
1657
+ def password?
1658
+ ::FtpParadise.password?.to_s
1659
+ end; alias password password? # === password
1660
+
1661
+ # ========================================================================= #
1662
+ # === set_password
1663
+ #
1664
+ # Use only this method when attempting to modify the @password.
1665
+ #
1666
+ # This @ivar keeps track of the password we will use.
1667
+ # ========================================================================= #
1668
+ def set_password(
1669
+ i = :try_to_use_a_default_password
1670
+ )
1671
+ case i
1672
+ # === try_to_use_a_default_password
1673
+ when :try_to_use_a_default_password,
1674
+ :default
1675
+ _ = return_password_from_bplaced
1676
+ _.chop! if _.end_with? '_'
1677
+ i = _
1678
+ when :anonymous
1679
+ i = nil
1680
+ else
1681
+ i = i.to_s
1682
+ end
1683
+ ::FtpParadise.set_password(i)
1684
+ i # Return the password here as well, so that we can use it for assignments.
1685
+ end; alias password= set_password # === password=
1686
+
1687
+ # ========================================================================= #
1688
+ # === return_password_from_bplaced
1689
+ # ========================================================================= #
1690
+ def return_password_from_bplaced
1691
+ dataset = YAML.load_file(FILE_ROEBE_FTP)['bplaced']
1692
+ return dataset['password']
1693
+ end
1694
+
1695
+ # ========================================================================= #
1696
+ # === set_port
1697
+ #
1698
+ # Use this method to set the port. The port will be stored on the
1699
+ # toplevel-"namespace".
1700
+ # ========================================================================= #
1701
+ def set_port(
1702
+ i = DEFAULT_PORT
1703
+ )
1704
+ FtpParadise.set_port(i)
1705
+ end
1706
+
1707
+ # ========================================================================= #
1708
+ # === port?
1709
+ # ========================================================================= #
1710
+ def port?
1711
+ FtpParadise.port?.to_s
1712
+ end; alias port port? # === port
1713
+
1714
+ require 'ftp_paradise/toplevel_methods/remote_url.rb'
1715
+ # ========================================================================= #
1716
+ # === remote_url?
1717
+ #
1718
+ # This method is guaranteed to return a String - except when an
1719
+ # error happens.
1720
+ # ========================================================================= #
1721
+ def remote_url?
1722
+ begin
1723
+ return FtpParadise.remote_url?.to_s
1724
+ rescue Interrupt
1725
+ exit # User interrupted, so we exit as requested.
1726
+ rescue Exception => error
1727
+ opnn; e 'We did encounter an error in the method '+
1728
+ simp(__method__.to_s)
1729
+ opnn; pp error
1730
+ return error.to_s # Return that exception.
1731
+ end
1732
+ end; alias remote_host? remote_url? # === remote_host?
1733
+ alias remote_url remote_url? # === remote_url
1734
+ alias url? remote_url? # === url?
1735
+ alias host? remote_url? # === host?
1736
+ alias host remote_url? # === host
1737
+
1738
+ # ========================================================================= #
1739
+ # === remove (remove tag)
1740
+ # ========================================================================= #
1741
+ def remove(i)
1742
+ if i.is_a? Array
1743
+ i.each {|entry| remove(entry) }
1744
+ else
1745
+ if is_a_directory?(i)
1746
+ remove_remote_directory(i)
1747
+ elsif is_a_file?(i)
1748
+ remove_remote_file(i, be_verbose?)
1749
+ end
1750
+ end
1751
+ end
1752
+
1753
+ # ========================================================================= #
1754
+ # === original_delete
1755
+ #
1756
+ # This method will remove the file, without doing any additional
1757
+ # checks.
1758
+ # ========================================================================= #
1759
+ def original_delete(i)
1760
+ ftp_object?.delete(i)
1761
+ end
1762
+
1763
+ # ========================================================================= #
1764
+ # === remove_remote_directory
1765
+ #
1766
+ # This method will remove a remote directory. For this to work, as
1767
+ # operation, the remote directory has to exist.
1768
+ #
1769
+ # This operation may fail e. g. when the remote directory is not empty.
1770
+ # This explains why we attempt to rescue some errors.
1771
+ # ========================================================================= #
1772
+ def remove_remote_directory(
1773
+ i,
1774
+ be_verbose = be_verbose?,
1775
+ force_remove = false
1776
+ )
1777
+ case force_remove
1778
+ when :force_remove
1779
+ force_remove = true
1780
+ when :do_not_force_remove
1781
+ force_remove = false
1782
+ end
1783
+ if i.is_a? Array
1784
+ i.each {|entry| remove_remote_directory(entry, be_verbose) }
1785
+ else
1786
+ if be_verbose
1787
+ notify_the_user_about(i, __method__)
1788
+ end
1789
+ if is_a_directory? i
1790
+ begin
1791
+ ftp_object?.rmdir(i)
1792
+ rescue Net::FTPPermError => error
1793
+ opnn; e swarn('We could not remove the remote directory at ')+
1794
+ sdir(i)+swarn(' as it is not empty.')
1795
+ pp error
1796
+ if force_remove
1797
+ opnn; e 'We will now try to enter into this directory'
1798
+ opnn; e 'and then remove all files of that directory.'
1799
+ rcd(this_dir)
1800
+ update_file_listing
1801
+ all_remote_files?.each {|file| remove(file) } # Now it should be removed.
1802
+ rcd('..') # Go back again.
1803
+ rmdir(i, be_verbose, :do_not_force_remove) # But we won't force again, to avoid recursive loops.
1804
+ opnn; e "The remote directory at #{sdir(i)} has been removed."
1805
+ end
1806
+ end
1807
+ else
1808
+ if be_verbose
1809
+ opnn; e "The given input #{sfancy(i)} is not a directory."
1810
+ end
1811
+ end
1812
+ end
1813
+ end; alias rmdir remove_remote_directory # === rmdir
1814
+ alias remove_these_remote_directories remove_remote_directory # === remove_these_remote_directories
1815
+ alias remove_directory remove_remote_directory # === remove_directory
1816
+
1817
+ # ========================================================================= #
1818
+ # === puttextfile
1819
+ #
1820
+ # This method will transfer a localfile to the remote server in
1821
+ # ASCII (text) mode. The result will be stored in "remotefile".
1822
+ #
1823
+ # If a callback or an associated block is supplied, calls it, passing
1824
+ # in the transmitted data one line at a time.
1825
+ # ========================================================================= #
1826
+ def puttextfile(
1827
+ local_file, remotefile = File.basename(local_file)
1828
+ )
1829
+ begin
1830
+ ftp_object?.puttextfile(local_file)
1831
+ @internal_hash[:uploaded_these_files] << local_file
1832
+ rescue Net::FTPPermError => error
1833
+ opnn; e swarn('Can not upload `')+sfile(local_file)+swarn('`.')
1834
+ opnn; e swarn('Reason provided to this method was:')
1835
+ opnn; e " → #{sfancy(error.to_s)}"
1836
+ rescue Exception => error
1837
+ opnn; e "An error happened in the method #{__method__}"
1838
+ pp error
1839
+ end
1840
+ end
1841
+
1842
+ # ========================================================================= #
1843
+ # === upload_this_text_file
1844
+ #
1845
+ # This method can be used to upload one or several text files.
1846
+ #
1847
+ # The first argument should be an Array or a String, denoting the
1848
+ # name/path of the local text file that you wish to upload.
1849
+ # ========================================================================= #
1850
+ def upload_this_text_file(
1851
+ i,
1852
+ be_verbose = be_verbose?
1853
+ )
1854
+ be_verbose = false if be_verbose == :be_silent
1855
+ if i.is_a? Array
1856
+ i.each {|entry| upload_this_text_file(entry, be_verbose) }
1857
+ else
1858
+ i = i.strip.delete(N) # Added in February 2014.
1859
+ case i
1860
+ when :default
1861
+ ENV['MISC'].to_s+'/SITEMAP.cgi' # <- Makes only sense for text-files anyway.
1862
+ end
1863
+ case be_verbose
1864
+ when :be_quiet
1865
+ be_verbose = false
1866
+ end
1867
+ if be_verbose
1868
+ notify_the_user_about(i, __method__)
1869
+ end
1870
+ puttextfile(i) # <- Delegate towards the method puttextfile().
1871
+ report_finished_uploading_of_this_file(i) if be_verbose
1872
+ end
1873
+ end
1874
+
1875
+ # ========================================================================= #
1876
+ # === upload_this_directory
1877
+ #
1878
+ # This method can be used to upload a local directory to a remote host.
1879
+ #
1880
+ # If the first input argument is an Array, then the method will call
1881
+ # itself recursively. This allows us to transfer several directories
1882
+ # in one go.
1883
+ #
1884
+ # If the input is a (local and existing) directory, then this method
1885
+ # will also have to create a remote directory, then chdir into it,
1886
+ # and then upload the content of that local directory to the remote
1887
+ # host.
1888
+ # ========================================================================= #
1889
+ def upload_this_directory(
1890
+ i,
1891
+ be_verbose = be_verbose?
1892
+ )
1893
+ if i.is_a? Array
1894
+ i.each {|entry| upload_this_directory(i, be_verbose) }
1895
+ else
1896
+ if File.directory? i
1897
+ unless this_remote_directory_exists?(i)
1898
+ remote_create_directory(i, be_verbose)
1899
+ end
1900
+ change_local_directory(i)
1901
+ change_remote_directory(i)
1902
+ report_remote_directory
1903
+ content = return_directory_content(i) # Last but not least, copy all files to that dir.
1904
+ content.each {|this_file| upload(this_file) }
1905
+ else
1906
+ opnn; e "The given input `#{sfancy(i)}` is not a directory."
1907
+ opnn; e 'This method can only upload directories.'
1908
+ end
1909
+ end
1910
+ end; alias upload_directory upload_this_directory # === upload_directory
1911
+ alias upload_these_directories upload_this_directory # === upload_these_directories
1912
+
1913
+ # ========================================================================= #
1914
+ # === set_transfer_mode
1915
+ #
1916
+ # This method will set to either one of two different possibles modes:
1917
+ #
1918
+ # (1) :ascii
1919
+ # (2) :binary
1920
+ # (3) :passive
1921
+ #
1922
+ # Note that :passive "mode" is ascii, with an additional invocation to
1923
+ # change the transfer mode to .passive.
1924
+ #
1925
+ # It will also change passive mode. The argument :default will default
1926
+ # to the more commonly used ASCII mode.
1927
+ #
1928
+ # When would you want to use ASCII mode?
1929
+ #
1930
+ # Use ascii mode for:
1931
+ #
1932
+ # txt, rtf, html, php
1933
+ #
1934
+ # Use binary mode for:
1935
+ #
1936
+ # images, videos and similar.
1937
+ #
1938
+ # ========================================================================= #
1939
+ def set_transfer_mode(
1940
+ i = DEFAULT_TRANSFER_MODE, # Will usually default to :ascii
1941
+ be_verbose = be_verbose?
1942
+ )
1943
+ case be_verbose
1944
+ when :be_verbose
1945
+ be_verbose = true
1946
+ when :be_quiet
1947
+ be_verbose = false
1948
+ end
1949
+ i = :ascii if i == :default
1950
+ case i
1951
+ # ======================================================================= #
1952
+ # === :ascii
1953
+ # ======================================================================= #
1954
+ when :ascii
1955
+ notify_the_user_about(i, __method__) if be_verbose
1956
+ @internal_hash[:transfer_mode] = :ascii
1957
+ ftp_object?.binary = false if ftp_object?
1958
+ # ======================================================================= #
1959
+ # === :binary
1960
+ # ======================================================================= #
1961
+ when :binary
1962
+ notify_the_user_about(i, __method__) if be_verbose
1963
+ @internal_hash[:transfer_mode] = :binary
1964
+ # ======================================================================= #
1965
+ # === :passive
1966
+ # ======================================================================= #
1967
+ when :passive,
1968
+ :pass
1969
+ notify_the_user_about(i, __method__) if be_verbose
1970
+ @internal_hash[:transfer_mode] = :ascii
1971
+ ftp_object?.passive = true if ftp_object?
1972
+ else
1973
+ opnn; e swarn('Not found the following mode: ')+
1974
+ sfancy(i.to_s)
1975
+ end
1976
+ end; alias mode_to_use= set_transfer_mode # === mode_to_use=
1977
+ alias set_mode set_transfer_mode # === set_mode
1978
+
1979
+ # ========================================================================= #
1980
+ # === report_transfer_mode_in_use
1981
+ # ========================================================================= #
1982
+ def report_transfer_mode_in_use
1983
+ e "Transfer mode: #{sfancy(transfer_mode?.to_s)}"
1984
+ end
1985
+
1986
+ # ========================================================================= #
1987
+ # === set_active
1988
+ # ========================================================================= #
1989
+ def set_active
1990
+ ftp_object?.passive = false
1991
+ end
1992
+
1993
+ # ========================================================================= #
1994
+ # === passive_transfer?
1995
+ # ========================================================================= #
1996
+ def passive_transfer?
1997
+ ftp_object?.passive
1998
+ end; alias passive? passive_transfer? # === passive?
1999
+
2000
+ # ========================================================================= #
2001
+ # === transfer_mode?
2002
+ #
2003
+ # This method will return the currently used transfer_mode. This mode
2004
+ # can be either :binary, or :ascii. By default it will be :binary.
2005
+ #
2006
+ # The transfer mode can be :binary or :text. :ascii is an alias to
2007
+ # :text.
2008
+ # ========================================================================= #
2009
+ def transfer_mode?
2010
+ @internal_hash[:transfer_mode]
2011
+ end; alias transfer_mode transfer_mode? # === transfer_mode
2012
+ alias mode? transfer_mode? # === mode?
2013
+ alias type transfer_mode? # === type
2014
+ alias type? transfer_mode? # === type?
2015
+
2016
+ # ========================================================================= #
2017
+ # === set_ascii
2018
+ #
2019
+ # Easier wrapper method.
2020
+ # ========================================================================= #
2021
+ def set_ascii
2022
+ set_transfer_mode :ascii
2023
+ end; alias set_ascii_mode set_ascii # === set_ascii_mode
2024
+
2025
+ # ========================================================================= #
2026
+ # === binary?
2027
+ #
2028
+ # When this is true, then then all FTP-transfers will be performed in
2029
+ # binary mode.
2030
+ #
2031
+ # Deaults to true.
2032
+ # ========================================================================= #
2033
+ def binary?
2034
+ ftp_object?.binary
2035
+ end; alias binary binary? # === binary
2036
+
2037
+ # ========================================================================= #
2038
+ # === set_binary_mode
2039
+ # ========================================================================= #
2040
+ def set_binary_mode
2041
+ set_transfer_mode :binary
2042
+ ftp_object?.binary = true
2043
+ end; alias set_binary set_binary_mode # === set_binary
2044
+ alias set_to_binary_mode set_binary_mode # === set_to_binary_mode
2045
+
2046
+ # ========================================================================= #
2047
+ # === set_passive_mode
2048
+ #
2049
+ # Use this when modifying the passive setting.
2050
+ # ========================================================================= #
2051
+ def set_passive_mode
2052
+ set_transfer_mode :ascii
2053
+ ftp_object?.passive = true if ftp_object?
2054
+ end; alias set_passive set_passive_mode # === set_passive
2055
+
2056
+ # ========================================================================= #
2057
+ # === set_default_transfer_mode
2058
+ # ========================================================================= #
2059
+ def set_default_transfer_mode(
2060
+ be_verbose = :be_quiet
2061
+ )
2062
+ set_transfer_mode(DEFAULT_TRANSFER_MODE, be_verbose)
2063
+ end
2064
+
2065
+ # ========================================================================= #
2066
+ # === set_debug
2067
+ # ========================================================================= #
2068
+ def set_debug(i = SHALL_WE_DEBUG)
2069
+ @internal_hash[:debug] = i
2070
+ end
2071
+
2072
+ # ========================================================================= #
2073
+ # === enable_debug_mode
2074
+ #
2075
+ # When the debug mode is set to true, then all traffic to and from
2076
+ # the server is written to $stdout. By default, this will NOT
2077
+ # be the case.
2078
+ # ========================================================================= #
2079
+ def enable_debug_mode
2080
+ ftp_object?.debug_mode = true
2081
+ end
2082
+
2083
+ # ========================================================================= #
2084
+ # === enable_debug
2085
+ #
2086
+ # Set the @debug variable to true, and also invoke enable_debug_mode().
2087
+ # ========================================================================= #
2088
+ def enable_debug
2089
+ enable_debug_mode
2090
+ set_debug(true)
2091
+ end
2092
+
2093
+ # ========================================================================= #
2094
+ # === debug?
2095
+ # ========================================================================= #
2096
+ def debug?
2097
+ @internal_hash[:debug]
2098
+ end
2099
+
2100
+ # ========================================================================= #
2101
+ # === disable_debug
2102
+ # ========================================================================= #
2103
+ def disable_debug
2104
+ ftp_object?.debug_mode = false
2105
+ @internal_hash[:debug] = false
2106
+ end
2107
+
2108
+ # ========================================================================= #
2109
+ # === debug (debug tag)
2110
+ #
2111
+ # This method can be used for some debugging output.
2112
+ # ========================================================================= #
2113
+ def debug(
2114
+ shall_we_debug = debug?
2115
+ )
2116
+ cliner {
2117
+ pp ftp?
2118
+ show_host_user_name_port_and_password
2119
+ update_file_listing
2120
+ if shall_we_debug
2121
+ opnn; e 'File Listing:'
2122
+ show_file_listing
2123
+ end
2124
+ if remote_file_listing?.empty?
2125
+ opnn; e 'No file could be found. The remote directory '\
2126
+ 'is most likely empty.'
2127
+ end
2128
+ } if shall_we_debug
2129
+ end; alias feedback debug # === feedback
2130
+ alias report debug # === report
2131
+
2132
+ # ========================================================================= #
2133
+ # === remote_pwd
2134
+ # ========================================================================= #
2135
+ def remote_pwd
2136
+ ftp_object?.pwd
2137
+ end; alias rpwd remote_pwd # === rpwd
2138
+ alias getdir remote_pwd # === getdir
2139
+
2140
+ # ========================================================================= #
2141
+ # === return_remote_pwd
2142
+ #
2143
+ # This method will return the (remote) pwd, including the remote working
2144
+ # directory - including the subpath..
2145
+ #
2146
+ # This method will ensure that a trailing '/' will be returned here.
2147
+ #
2148
+ # The official documentation can be seen here:
2149
+ # https://ruby-doc.org/stdlib/libdoc/net/ftp/rdoc/Net/FTP.html#method-i-pwd
2150
+ # ========================================================================= #
2151
+ def return_remote_pwd
2152
+ begin
2153
+ if is_connected?
2154
+ remote_pwd = remote_url?.dup
2155
+ # ===================================================================== #
2156
+ # Need to safeguard, in the event that we are not connected to a
2157
+ # remote FTP server.
2158
+ # ===================================================================== #
2159
+ if ftp_object? and is_connected? and logged_in?
2160
+ remote_pwd << ftp_object?.pwd.to_s
2161
+ end
2162
+ remote_pwd << '/'
2163
+ return rds(remote_pwd)
2164
+ else
2165
+ opnn; e 'No FTP connection is open.'
2166
+ ''
2167
+ end
2168
+ rescue Net::FTPReplyError
2169
+ opnn; e 'Error Net::FTPReplyError received. May be due to user interrupting.'
2170
+ opnn; e 'Exiting now at once either way.'
2171
+ exit
2172
+ rescue SystemExit, Interrupt
2173
+ opnn; e 'User requested to exit, thus exiting now.'
2174
+ exit
2175
+ end
2176
+ end; alias pwd? return_remote_pwd # === pwd?
2177
+ alias pwd return_remote_pwd # === pwd (pwd tag)
2178
+ alias getdir return_remote_pwd # === get_dir
2179
+ alias remote_pwd return_remote_pwd # === remote_pwd
2180
+ alias remote_pwd? return_remote_pwd # === remote_pwd?
2181
+ alias connected_to? return_remote_pwd # === connected_to?
2182
+ alias remote? return_remote_pwd # === remote?
2183
+ alias base_dir? return_remote_pwd # === base_dir?
2184
+ alias remote_directory? return_remote_pwd # === remote_directory?
2185
+ alias remote_dir? return_remote_pwd # === remote_dir?
2186
+ alias remote_path? return_remote_pwd # === remote_path?
2187
+ alias return_subdirectory return_remote_pwd # === return_subdirectory
2188
+ alias current_directory return_remote_pwd # === current_directory
2189
+ alias return_remote_dir return_remote_pwd # === return_remote_dir
2190
+ alias get_remote_dir return_remote_pwd # === get_remote_dir
2191
+ alias remote_host? return_remote_pwd # === remote_host?
2192
+
2193
+ # ========================================================================= #
2194
+ # === report_current_remote_dir
2195
+ #
2196
+ # Gives you the current dir.
2197
+ # ========================================================================= #
2198
+ def report_current_remote_dir(
2199
+ be_verbose = be_verbose?
2200
+ )
2201
+ begin
2202
+ if be_verbose
2203
+ opnn; e 'The remote directory is:'
2204
+ e " #{sdir(return_remote_pwd)}"
2205
+ end
2206
+ rescue Exception => error
2207
+ opnn; e error.class
2208
+ opnn; e error
2209
+ end
2210
+ end; alias report_remote_directory report_current_remote_dir # === report_remote_directory
2211
+ alias dir? report_current_remote_dir # === dir?
2212
+ alias report_remote_pwd report_current_remote_dir # === report_remote_pwd
2213
+
2214
+ # ========================================================================= #
2215
+ # === remote_chdir (cd tag, chdir tag)
2216
+ #
2217
+ # This method allows us to cd to another remote directory, on the
2218
+ # remote FTP server (our main connection).
2219
+ #
2220
+ # The method must be able to check whether we are connected to the
2221
+ # remote host.
2222
+ # ========================================================================= #
2223
+ def remote_chdir(
2224
+ i,
2225
+ be_verbose = be_verbose?,
2226
+ &block
2227
+ )
2228
+ if block_given?
2229
+ case yield
2230
+ # ===================================================================== #
2231
+ # === :be_verbose
2232
+ # ===================================================================== #
2233
+ when :be_verbose
2234
+ be_verbose = true
2235
+ end
2236
+ end
2237
+ i = i.dup if i.frozen?
2238
+ # ======================================================================= #
2239
+ # Sanitize odd entries ending with ':'
2240
+ # ======================================================================= #
2241
+ i[-1,1] = '/' if i.end_with? ':'
2242
+ i = rds("#{i}/") # <- Always ensure that a '/' is the last character.
2243
+ if be_verbose
2244
+ notify_the_user_about(i, __method__)
2245
+ end
2246
+ if is_connected?
2247
+ # ===================================================================== #
2248
+ # If we cd to a non-existing target, the exception Net::FTPPermError
2249
+ # will be raised.
2250
+ # ===================================================================== #
2251
+ begin
2252
+ ftp_object?.chdir(i)
2253
+ update_remote_file_listing
2254
+ # ===================================================================== #
2255
+ # The user may have insufficient permissions:
2256
+ # ===================================================================== #
2257
+ rescue Net::FTPPermError => error
2258
+ pp error
2259
+ rescue Net::ReadTimeout => error
2260
+ opnn; e 'An error was encountered in the method '\
2261
+ 'remote_chdir().'
2262
+ opnn; e 'The error-class was Net::ReadTimeout.'
2263
+ e
2264
+ opnn; e 'The specific error will be displayed next.'
2265
+ e
2266
+ pp error
2267
+ end
2268
+ else
2269
+ opnn; e 'We are not connected to a remote host right now.'
2270
+ opnn; e 'Thus we can not change the directory.'
2271
+ end
2272
+ report_current_remote_dir if be_verbose # right now mandatory
2273
+ end; alias rcd remote_chdir # === rcd
2274
+ alias remote_cd remote_chdir # === remote_cd
2275
+ alias chdir remote_chdir # === chdir
2276
+ alias cd remote_chdir # === cd
2277
+ alias chdir remote_chdir # === chdir
2278
+ alias rcd remote_chdir # === rcd
2279
+ alias change_directory remote_chdir # === change_directory
2280
+ alias change_remote_directory remote_chdir # === change_remote_directory
2281
+ alias cd_into_this_remote_directory remote_chdir # === cd_into_this_remote_directory
2282
+ alias remote_change_directory remote_chdir # === remote_change_directory
2283
+
2284
+ # ========================================================================= #
2285
+ # === return_remote_directories
2286
+ #
2287
+ # Give us a list of (remote) directories - only directories, not
2288
+ # files.
2289
+ #
2290
+ # An Array will be returned as a result.
2291
+ # ========================================================================= #
2292
+ def return_remote_directories
2293
+ _ = []
2294
+ update_file_listing # Populate the file listing anew, so we will always get proper results back.
2295
+ raw_listing?.each {|entry|
2296
+ entry = FtpParadise::Entry.new(entry)
2297
+ _ << rds(entry.return_name) if entry.is_a_directory?
2298
+ }
2299
+ # ======================================================================= #
2300
+ # Directories must end with '/'. Ensure this to be the case next.
2301
+ # ======================================================================= #
2302
+ _.map! {|entry|
2303
+ entry << '/' unless entry.end_with? '/'
2304
+ entry
2305
+ }
2306
+ return _
2307
+ end; alias directories? return_remote_directories # === directories?
2308
+ alias return_directories return_remote_directories # === return_directories
2309
+
2310
+ # ========================================================================= #
2311
+ # === return_remote_directory_content
2312
+ #
2313
+ # This method will return ALL remote entries, no matter if file or
2314
+ # directory.
2315
+ # ========================================================================= #
2316
+ def return_remote_directory_content
2317
+ raw_entries = raw_entries?
2318
+ if raw_entries.nil?
2319
+ populate_raw_entries
2320
+ raw_entries = raw_entries?
2321
+ end
2322
+ if raw_entries
2323
+ _ = raw_entries.reject {|line|
2324
+ line.empty?
2325
+ }.map {|entry|
2326
+ FtpParadise::Entry.new(entry).name?
2327
+ }
2328
+ end
2329
+ return _
2330
+ end; alias array_file_listing? return_remote_directory_content # === array_file_listing?
2331
+ alias array_file_listing return_remote_directory_content # === array_file_listing
2332
+ alias remote_directory_content return_remote_directory_content # === remote_directory_content
2333
+ alias list? return_remote_directory_content # === list?
2334
+
2335
+ # ========================================================================= #
2336
+ # === quit (quit tag)
2337
+ #
2338
+ # Use this method to quit (and disconnect) from the FTP Connection
2339
+ # again.
2340
+ # ========================================================================= #
2341
+ def quit
2342
+ begin
2343
+ if is_connected?
2344
+ if ftp_object?
2345
+ FtpParadise.clear_user_dataset
2346
+ ftp_object?.quit
2347
+ end
2348
+ end
2349
+ rescue Exception => error
2350
+ opnn; e "An error happened in the method #{sfancy(__method__)}()"
2351
+ pp error
2352
+ end
2353
+ end
2354
+
2355
+ # ========================================================================= #
2356
+ # === FtpParadise::Connection[]
2357
+ # ========================================================================= #
2358
+ def self.[](i = '')
2359
+ new(i)
2360
+ end
2361
+
2362
+ # ========================================================================= #
2363
+ # === chdir (cd tag, chdir tag)
2364
+ # ========================================================================= #
2365
+ def chdir(i)
2366
+ @ftp_object.chdir(i)
2367
+ end; alias cd chdir # === cd
2368
+ alias remote_cd chdir # === remote_cd
2369
+
2370
+ # ========================================================================= #
2371
+ # === pwd
2372
+ #
2373
+ # Returns the current remote directory.
2374
+ # ========================================================================= #
2375
+ def pwd
2376
+ "#{@ftp_object.pwd}/".squeeze('/')
2377
+ end; alias getdir pwd # === getdir
2378
+ alias remote_directory? pwd # === remote_directory?
2379
+
2380
+ # ========================================================================= #
2381
+ # === ftp_connection?
2382
+ # ========================================================================= #
2383
+ def ftp_connection?
2384
+ @ftp_object
2385
+ end; alias ftp_object? ftp_connection? # === ftp_object?
2386
+ alias net_ftp? ftp_connection? # === net_ftp?
2387
+ alias ftp? ftp_connection? # === ftp?
2388
+ alias ftp ftp_connection? # === ftp?
2389
+ alias ftp_object ftp_connection? # === ftp_object
2390
+
2391
+ # ========================================================================= #
2392
+ # === do_login
2393
+ #
2394
+ # This method is responsible for the login-action.
2395
+ #
2396
+ # The method signature for the net-ftp class' .login() is:
2397
+ #
2398
+ # login(user = "anonymous", passwd = nil, acct = nil)
2399
+ #
2400
+ # This method here accepts a Hash as first argument.
2401
+ #
2402
+ # For official information about .login(), see here:
2403
+ #
2404
+ # https://ruby-doc.org/stdlib/libdoc/net/ftp/rdoc/Net/FTP.html#method-i-login
2405
+ #
2406
+ # ========================================================================= #
2407
+ def do_login(
2408
+ to_this_url = nil, # The remote URL.
2409
+ use_this_as_username = username?, # The login-name.
2410
+ use_this_as_password = password?, # The password for that user.
2411
+ be_verbose = be_verbose?
2412
+ )
2413
+ if to_this_url.nil?
2414
+ to_this_url = FtpParadise.remote_url?
2415
+ elsif to_this_url.is_a? Hash
2416
+ end
2417
+ # ======================================================================= #
2418
+ # Rescue nil-passwords here.
2419
+ # ======================================================================= #
2420
+ if use_this_as_password.to_s.empty?
2421
+ use_this_as_password = set_password(:try_to_use_a_default_password)
2422
+ end
2423
+ if be_verbose
2424
+ # ===================================================================== #
2425
+ # Display some info to the user here.
2426
+ # ===================================================================== #
2427
+ e; cliner
2428
+ opnn; e "Using the URL #{royalblue(to_this_url)} (remote FTP host)."
2429
+ e
2430
+ e " Username: #{slateblue(use_this_as_username)}"
2431
+ e " Password: #{slateblue(use_this_as_password)}"
2432
+ e
2433
+ report_transfer_mode_in_use
2434
+ e
2435
+ cliner
2436
+ end
2437
+ if ftp_object?.nil? and !to_this_url.nil?
2438
+ initialize_a_new_net_ftp_object_with_this_url(to_this_url)
2439
+ end
2440
+ use_this_as_username = use_this_as_username.to_s
2441
+ # ======================================================================= #
2442
+ # The following code must be rescued because the login() method
2443
+ # may fail in various ways.
2444
+ # ======================================================================= #
2445
+ begin
2446
+ ftp_object?.login(
2447
+ use_this_as_username,
2448
+ use_this_as_password
2449
+ )
2450
+ # =================================================================== #
2451
+ # Next, assign towards the toplevel reference to the ftp-connection.
2452
+ # =================================================================== #
2453
+ sync_ftp_object_onto_the_main_namespace if ftp_object?
2454
+ if be_verbose and is_connected?
2455
+ e
2456
+ cliner {
2457
+ e "- #{sfancy('Successfully')} logged into "\
2458
+ "the remote FTP host at `#{simp(to_this_url)}`"
2459
+ }
2460
+ end
2461
+ rescue Net::FTPPermError => error
2462
+ opnn; e "We could not connect and login to `#{sfancy(to_this_url)}`."
2463
+ opnn; e 'It may be that you lack the proper permissions.'
2464
+ opnn; e 'This may happen because the user/password combination was'
2465
+ opnn; e 'incorrect. User and password combination will be shown next:'
2466
+ show_user_and_password
2467
+ opnn; e "Feedbacking that error next, of class #{error.class.to_s}:"
2468
+ opnn; e orange(error.to_s)
2469
+ rescue Net::FTPConnectionError => error
2470
+ opnn; e 'We do not seem to be connected. An error happened.'
2471
+ pp error
2472
+ pp error.class
2473
+ end
2474
+ end; alias do_connect do_login # === do_connect
2475
+ alias connect_to do_login # === connect_to
2476
+ alias connect do_login # === connect
2477
+ alias login do_login # === login
2478
+ alias login_to do_login # === login_to
2479
+ alias reconnect do_login # === reconnect
2480
+
2481
+ # ========================================================================= #
2482
+ # === remove_remote_file
2483
+ #
2484
+ # Remove a (remote) file, via the delete() method of the FTP protocol.
2485
+ #
2486
+ # Note that this method will only delete files.
2487
+ #
2488
+ # The official documentation for the Ruby-FTP delete() method can be
2489
+ # found here:
2490
+ #
2491
+ # https://www.ruby-doc.org/stdlib/libdoc/net/ftp/rdoc/Net/FTP.html#method-i-delete
2492
+ #
2493
+ # ========================================================================= #
2494
+ def remove_remote_file(
2495
+ i,
2496
+ be_verbose = be_verbose?
2497
+ )
2498
+ case be_verbose
2499
+ when :be_verbose
2500
+ be_verbose = true
2501
+ end
2502
+ if i.is_a? Array
2503
+ i.each {|entry| remove_remote_file(entry, be_verbose) }
2504
+ else
2505
+ if does_this_remote_file_exist?(File.basename(i))
2506
+ i = File.basename(i)
2507
+ if i =~ /^\d+$/ # if is a number
2508
+ update_file_listing
2509
+ _ = return_remote_file_listing[i.to_i - 1].first
2510
+ _ = File.basename(_)
2511
+ e "Performing a substitution of #{sfancy(i)}"\
2512
+ " to #{simp(_)}."
2513
+ i = _
2514
+ end
2515
+ if be_verbose
2516
+ notify_the_user_about(i, __method__)
2517
+ end
2518
+ ftp_object?.delete(i)
2519
+ update_file_listing
2520
+ return i # Also return the file that was deleted.
2521
+ else
2522
+ opnn; e "No remote file called `#{sfile(i)}` was "\
2523
+ "found at `#{sfancy(remote_pwd)}`."
2524
+ end
2525
+ end
2526
+ end; alias remote_remove remove_remote_file # === remote_remove
2527
+ alias remote_remove_files remove_remote_file # === remote_remove_files
2528
+ alias remote_remove_file remove_remote_file # === remote_remove_files
2529
+ alias delete remove_remote_file # === delete
2530
+ alias remove_file remove_remote_file # === remove_file
2531
+ alias rm_file remove_remote_file # === rm_file
2532
+ alias rmfile remove_remote_file # === rmfile
2533
+ alias delete_this_remote_file remove_remote_file # === delete_this_remote_file
2534
+
2535
+ # ========================================================================= #
2536
+ # === return_all_remote_files
2537
+ #
2538
+ # This method will return an Array with all remote files.
2539
+ # ========================================================================= #
2540
+ def return_all_remote_files
2541
+ results = []
2542
+ if file_listing?
2543
+ results = file_listing?.select {|entry|
2544
+ if entry.is_a?(String) and !entry.empty?
2545
+ entry = FtpParadise::Entry.new(entry)
2546
+ end
2547
+ entry.is_a_file?
2548
+ }
2549
+ end
2550
+ return results
2551
+ end; alias remote_file_listing? return_all_remote_files # === remote_file_listing?
2552
+ alias all_remote_files? return_all_remote_files # === all_remote_files?
2553
+ alias array_remote_files return_all_remote_files # === array_remote_files
2554
+ alias return_remote_files return_all_remote_files # === return_remote_files
2555
+ alias return_remote_file_listing return_all_remote_files # === return_remote_file_listing
2556
+ alias remote_files? return_all_remote_files # === remote_files
2557
+ alias files? return_all_remote_files # === files?
2558
+
2559
+ # ========================================================================= #
2560
+ # === open?
2561
+ #
2562
+ # This method can also be used to determine whether we are still
2563
+ # connected to the remote site.
2564
+ #
2565
+ # This method will return true if the connection is open.
2566
+ #
2567
+ # If you want to determine whether you are still connected to the
2568
+ # remote host, you can alias use the alias are_we_connected? - it
2569
+ # may read nicer.
2570
+ # ========================================================================= #
2571
+ def open?
2572
+ !closed?
2573
+ end; alias are_we_connected? open? # === are_we_connected?
2574
+ alias is_connected? open? # === is_connected?
2575
+ alias is_connected open? # === is_connected
2576
+ alias connected? open? # === connected?
2577
+ alias did_we_connect? open? # === did_we_connect?
2578
+
2579
+ # ========================================================================= #
2580
+ # === status?
2581
+ #
2582
+ # Report the status here. This is equivalent to the STAT command.
2583
+ # ========================================================================= #
2584
+ def status?
2585
+ ftp_object?.status.to_s
2586
+ end; alias status status? # === status
2587
+ alias remote_status? status? # === remote_status?
2588
+
2589
+ # ========================================================================= #
2590
+ # === initialize_a_new_net_ftp_object_with_this_remote_url
2591
+ #
2592
+ # This method is the only one allowed to create a new Net::FTP instance.
2593
+ # ========================================================================= #
2594
+ def initialize_a_new_net_ftp_object_with_this_remote_url(i)
2595
+ @ftp_object = Net::FTP.new(i) # ftp = Net::FTP.new(YAML.load_file(ENV['FTP_YAML_FILE'])['freehosting']['url'])
2596
+ end; alias initialize_a_new_net_ftp_object initialize_a_new_net_ftp_object_with_this_remote_url # === initialize_a_new_net_ftp_object
2597
+ alias initialize_a_new_net_ftp_object_with_this_url initialize_a_new_net_ftp_object_with_this_remote_url # === initialize_a_new_net_ftp_object_with_this_url
2598
+
2599
+ # ========================================================================= #
2600
+ # === connect_via_this_dataset
2601
+ # ========================================================================= #
2602
+ def connect_via_this_dataset(hash)
2603
+ set_data(hash)
2604
+ if ::FtpParadise.remote_host?.nil? and hash.has_key?(:remote_url)
2605
+ ::FtpParadise.set_remote_host(hash[:remote_url])
2606
+ end
2607
+ do_login(FtpParadise.remote_url?)
2608
+ end
2609
+
2610
+ # ========================================================================= #
2611
+ # === set_data (all in one, set_data tag)
2612
+ #
2613
+ # This method sets:
2614
+ #
2615
+ # - host
2616
+ # - user name
2617
+ # - port and
2618
+ # - password
2619
+ #
2620
+ # This method is thus a nifty little convenience method. You can pass
2621
+ # a hash to it too, which is the recommended way to use this method.
2622
+ #
2623
+ # You can also use an Array (with 4 elements), in which case we will
2624
+ # process it one after the other. The reason for this procedure is
2625
+ # because we can also use yaml files that way, that also use the
2626
+ # exact order of elements.
2627
+ #
2628
+ # If you add a new entry to the case menu below, also add this to
2629
+ # ARRAY_AVAILABLE_HOSTS, please. That Array can be found in the
2630
+ # file 'constants/roebe_ftp_constants.rb'.
2631
+ # ========================================================================= #
2632
+ def set_data(
2633
+ i = 'default'
2634
+ ) # set the default here.
2635
+ if debug?
2636
+ opnn; e 'We will debug next, as the @debug variable was set to true.'
2637
+ pp i
2638
+ end
2639
+ # ======================================================================= #
2640
+ # === Handle Hash as input first
2641
+ # ======================================================================= #
2642
+ if i.is_a? Hash # Hash is treated differently.
2643
+
2644
+ # ===================================================================== #
2645
+ # === :host
2646
+ # ===================================================================== #
2647
+ if i.has_key? :host
2648
+ set_host i.fetch(:host)
2649
+ # ===================================================================== #
2650
+ # === :remote_host
2651
+ # ===================================================================== #
2652
+ elsif i.has_key? :remote_host
2653
+ set_host i.fetch(:remote_host)
2654
+ elsif i.has_key? :to # :to is an alias to :host.
2655
+ set_host i.fetch(:to)
2656
+ elsif i.has_key? :remote_url
2657
+ set_host i.fetch(:remote_url)
2658
+ end
2659
+
2660
+ # ===================================================================== #
2661
+ # === :user_name
2662
+ # ===================================================================== #
2663
+ if i.has_key? :user_name
2664
+ set_user_name i.fetch(:user_name)
2665
+ elsif i.has_key? :login_name
2666
+ set_user_name i.fetch(:login_name)
2667
+ end
2668
+
2669
+ # ===================================================================== #
2670
+ # === :password
2671
+ # ===================================================================== #
2672
+ if i.has_key? :password
2673
+ set_password i.fetch(:password)
2674
+ # ===================================================================== #
2675
+ # === :login_password
2676
+ # ===================================================================== #
2677
+ elsif i.has_key? :login_password
2678
+ set_password i.fetch(:login_password)
2679
+ end
2680
+
2681
+ # ===================================================================== #
2682
+ # === :port
2683
+ # ===================================================================== #
2684
+ if i.has_key? :port
2685
+ set_port i.fetch(:port)
2686
+ end
2687
+ # ======================================================================= #
2688
+ # === Handle Array as input next
2689
+ # ======================================================================= #
2690
+ elsif i.is_a? Array # Example-Array: ["ftp.byethost33.com", "b33_14144659", "1aaaaaa", 21]
2691
+ set_host i.first
2692
+ set_user_name i[1]
2693
+ set_password i[2]
2694
+ set_port i[3]
2695
+ # ======================================================================= #
2696
+ # === Else, use simple toggle commands, such as 1,2,3,4,5 and so forth.
2697
+ # ======================================================================= #
2698
+ else # In the following case menu you can toggle your FTP.
2699
+ case i.to_s # Work on strings only. Assumes shortcuts as well.
2700
+ # ===================================================================== #
2701
+ # === bplaced
2702
+ # ===================================================================== #
2703
+ when '1',
2704
+ 'bplaced',
2705
+ /shevy/i,
2706
+ 'default',
2707
+ 'top' # Current default.
2708
+ dataset = YAML.load_file(FILE_ROEBE_FTP)['bplaced']
2709
+ set_host dataset['host']
2710
+ set_user_name dataset['user_name']
2711
+ set_password dataset['password']
2712
+ set_port dataset['port']
2713
+ # ===================================================================== #
2714
+ # === shevy
2715
+ #
2716
+ # This defaults to my home system.
2717
+ # ===================================================================== #
2718
+ when '2',
2719
+ 'square',
2720
+ 'square7',
2721
+ 'podserver'
2722
+ _ = FILE_ROEBE_FTP
2723
+ if File.exist? _
2724
+ data = YAML.load_file(_)['bplaced']
2725
+ set_host data['url']
2726
+ set_user_name data['user_name']
2727
+ this_password = data['password']
2728
+ this_password.chop! if this_password.end_with? '_'
2729
+ set_password this_password
2730
+ set_port data['port']
2731
+ end
2732
+ # ===================================================================== #
2733
+ # === a1
2734
+ # ===================================================================== #
2735
+ when '3',
2736
+ 'a1',
2737
+ 'a1_ftp' # A1 FTP host. No longer in use but still kept.
2738
+ set_host A1.first
2739
+ set_user_name A1[1]
2740
+ set_password A1[2]
2741
+ set_port A1[3]
2742
+ # ===================================================================== #
2743
+ # === zymix
2744
+ # ===================================================================== #
2745
+ when '4',
2746
+ 'zymix',
2747
+ 'standard'
2748
+ set_host ZYMIX.first
2749
+ set_user_name ZYMIX[1]
2750
+ set_password ZYMIX[2]
2751
+ set_port ZYMIX[3]
2752
+ # ===================================================================== #
2753
+ # === uniwien
2754
+ # ===================================================================== #
2755
+ when '5',
2756
+ 'univie',
2757
+ 'uniwien' # Uni Wien FTP Account.
2758
+ set_host UNIVIE.first
2759
+ set_user_name UNIVIE[1]
2760
+ set_password UNIVIE[2]
2761
+ set_port UNIVIE[3]
2762
+ # ===================================================================== #
2763
+ # === byte
2764
+ # ===================================================================== #
2765
+ when '6',
2766
+ 'byte',
2767
+ 'bytehost'
2768
+ dataset = YAML.load_file(FILE_ROEBE_FTP)['bytehost']
2769
+ set_host dataset['host']
2770
+ set_user_name dataset['user_name']
2771
+ set_password dataset['password']
2772
+ set_port dataset['port']
2773
+ else
2774
+ set_data(:default) # Go back to default again if not found.
2775
+ end
2776
+ end
2777
+ end
2778
+
2779
+ # ========================================================================= #
2780
+ # === upload_this_local_file
2781
+ # ========================================================================= #
2782
+ def upload_this_local_file(i)
2783
+ i = i.join if i.is_a? Array
2784
+ ftp_connection?.putbinaryfile(i)
2785
+ end; alias putbinaryfile upload_this_local_file # === putbinaryfile
2786
+
2787
+ # ========================================================================= #
2788
+ # === run (run tag)
2789
+ # ========================================================================= #
2790
+ def run
2791
+ do_connect
2792
+ end
2793
+
2794
+ end; end
2795
+
2796
+ if __FILE__ == $PROGRAM_NAME
2797
+ if FtpParadise.is_on_roebe?
2798
+ FtpParadise::Connection.new(ARGV) { :use_default_dataset }
2799
+ else
2800
+ FtpParadise::Connection.new(ARGV)
2801
+ end
2802
+ end # connection.rb