class FtpParadise::InteractiveFtp
Constants
- ARRAY_FORBIDDEN_HISTORY_COMMANDS
#¶ ↑
ARRAY_FORBIDDEN_HISTORY_COMMANDS
¶ ↑#¶ ↑
- ARRAY_PROJECT_FILES
#¶ ↑
ARRAY_PROJECT_FILES
¶ ↑The following files have to be opened when you wish to open the project files.
#¶ ↑
- DEFAULT_LOCAL_DIRECTORY
#¶ ↑
DEFAULT_LOCAL_DIRECTORY
¶ ↑#¶ ↑
- DEFAULT_REMOTE_DIRECTORY
#¶ ↑
DEFAULT_REMOTE_DIRECTORY
¶ ↑The default remote directory.
#¶ ↑
- DEFAULT_REMOTE_FILE
#¶ ↑
DEFAULT_REMOTE_FILE
¶ ↑The default remote file comes next.
#¶ ↑
- NAMESPACE
#¶ ↑
NAMESPACE
¶ ↑#¶ ↑
- NAME_OF_THIS_FILE
#¶ ↑
NAME_OF_THIS_FILE
¶ ↑#¶ ↑
- OPEN_IN_DEFAULT_EDITOR
#¶ ↑
OPEN_IN_DEFAULT_EDITOR
¶ ↑#¶ ↑
- PROMPT_TO_USE
#¶ ↑
PROMPT_TO_USE
¶ ↑Which Prompt to use by default for the Interactive FTP component.
#¶ ↑
- SHALL_WE_DEBUG
#¶ ↑
SHALL_WE_DEBUG
¶ ↑#¶ ↑
- SHOW_REMOTE_FILES_UPON_SUCCESSFUL_LOGIN
#¶ ↑
SHOW_REMOTE_FILES_UPON_SUCCESSFUL_LOGIN
¶ ↑If this constant is true then we will show the remote file listing upon a successful (first) login action.
#¶ ↑
- TITLE
#¶ ↑
TITLE
¶ ↑#¶ ↑
- USE_THIS_EDITOR
#¶ ↑
USE_THIS_EDITOR
¶ ↑#¶ ↑
Public Class Methods
#¶ ↑
initialize¶ ↑
#¶ ↑
# File lib/ftp_paradise/interactive_ftp/initialize.rb, line 14 def initialize( optional_commandline_arguments = nil, run_already = true ) register_sigint reset set_commandline_arguments( optional_commandline_arguments ) set_run_mode(:standalone) # Purposely defined before run(). This way, we can change it. run if run_already end
Public Instance Methods
#¶ ↑
all_arguments?¶ ↑
The alias a? may be an easier wrapper over @all_arguments.
#¶ ↑
# File lib/ftp_paradise/interactive_ftp/misc.rb, line 187 def all_arguments? @all_arguments end
#¶ ↑
change¶ ↑
This method can be used to change the main transfer mode.
#¶ ↑
# File lib/ftp_paradise/interactive_ftp/mode.rb, line 61 def change(i) case i # ======================================================================= # # === mode # ======================================================================= # when 'mode' # Change the mode that we use. use_binary_mode end end
#¶ ↑
change_directory
(cd tag)¶ ↑
This only changes for local directories, not remote directories.
#¶ ↑
# File lib/ftp_paradise/interactive_ftp/directory_handling.rb, line 149 def change_directory( i = DEFAULT_LOCAL_DIRECTORY, be_verbose = true ) i = '..' if i.nil? be_verbose = false if be_verbose == :be_silent i = i.to_s i.gsub!(/; pwd/,'') if i.include? '; pwd' begin i = get_env_of(i) if i.include? '$' if File.exist?(i) # =================================================================== # # Next, do the actual "change directory" action. # =================================================================== # Dir.chdir(i) # This will cd for local directories. i = return_pwd if i == '..' i = rds(return_pwd) unless i.include? '/' set_local_directory(i) # Set the new pwd here. report_local_directory if be_verbose else # else, the directory does not exist. e swarn('But the directory '+sdir(i)+' does not exist '\ 'locally in '+sdir(return_pwd)+'.') end rescue Exception => error e 'An exception occurred in '+swarn('change_directory()') e "The directory `#{sdir(i)}` does not exist." pp error # Should remove this and error perhaps. end end
#¶ ↑
change_local_and_remote_directories
¶ ↑
We combine local cd and remote cd here.
#¶ ↑
# File lib/ftp_paradise/interactive_ftp/directory_handling.rb, line 128 def change_local_and_remote_directories( target = DEFAULT_LOCAL_DIRECTORY ) change_directory(target, :be_silent) # Mandatory since as of 01.05.2011 if are_we_connected? remote_change_directory(target) # Since as of August 2011. end end
#¶ ↑
determine_user_dataset_from_this_hash
¶ ↑
This method can set relevant entries from an input Hash.
#¶ ↑
# File lib/ftp_paradise/interactive_ftp/misc.rb, line 90 def determine_user_dataset_from_this_hash( i, optional_use_this_entry = :default ) if optional_use_this_entry case optional_use_this_entry # ===================================================================== # # === :default # ===================================================================== # when :default optional_use_this_entry = :bplaced end end FtpParadise.determine_user_dataset_from_this_hash(i) end
#¶ ↑
display_configuration_options
(show config tag)¶ ↑
This method will show the configuration settings.
You can invoke this in an interactive FTP session by doing this:
config?
#¶ ↑
# File lib/ftp_paradise/interactive_ftp/show.rb, line 144 def display_configuration_options # Config tag. cliner { if @file.to_s.empty? e '@file is: unassigned as of yet' else e '@file is: '+sfancy(@file.to_s) end e '@local_directory is: '+sfancy(@local_directory.to_s) e '@splitted is: '+sfancy(@splitted.to_s) e 'Will we use the Readline module? '+ sfancy(verbose_truth(use_readline?)) e 'Will we show full names (with full path)? '+ sfancy(verbose_truth(show_full_names?)) e 'What is the base directory? '+ sfancy(@config.base_directory.to_s) } end
#¶ ↑
enter_main_loop
¶ ↑
#¶ ↑
# File lib/ftp_paradise/interactive_ftp/main_loop.rb, line 14 def enter_main_loop # ======================================================================= # # Enter the remote directory htdocs if we are on ftpupload.net # or on a similar host.. # ======================================================================= # if remote_url?.include?('ftpupload.net') remote_cd 'htdocs', :be_verbose elsif remote_url?.include?('shevy.bplaced.net') remote_cd 'www', :be_verbose end check_commandline_arguments # <- This will also query the menu() method. show_welcome_message display_prompt loop { begin # =================================================================== # # Obtain the user input: # =================================================================== # obtain_user_input # =================================================================== # # Pass the user input into the menu interface: # =================================================================== # result = menu result = result.first if result.is_a? Array case result when *ARRAY_VALID_OPTIONS_FOR_EXITING_THE_SHELL, :break break when :exit exit end rescue Interrupt e 'In order to quit, please use "'+ steelblue('q')+'" instead.' end } end
#¶ ↑
ftp_remote_directory?¶ ↑
#¶ ↑
# File lib/ftp_paradise/interactive_ftp/directory_handling.rb, line 14 def ftp_remote_directory? ftp?.remote_directory? end
#¶ ↑
obtain_user_input
¶ ↑
This method will obtain user input, and assign it to the variable @user_input.
#¶ ↑
# File lib/ftp_paradise/interactive_ftp/user_input.rb, line 17 def obtain_user_input if @use_readline user_input = Readline.readline('', true) Readline::HISTORY.pop if user_input.strip.empty? else user_input = $stdin.gets.chomp end # ======================================================================= # # Get rid of potential '#' comments in the input. # ======================================================================= # if user_input.include? '#' user_input = user_input[0 .. user_input.index('#')-1] end user_input.strip! # Get rid of ' ' empty characters. _ = user_input unless _.empty? # append to history. try_to_append_this_to_the_history(_) end # ======================================================================= # # If the user did input a ';' character then we will assume that he # wants to send multiple commands. We will however NOT assume so # if the string also includes a 'http://' - in that case, we assume # a HTTP URL instead. # ======================================================================= # if user_input.include? ';' and !user_input.include?('http://') user_input = user_input.split(';') else user_input = [user_input] # In this case simply turn it into an Array. end # ======================================================================= # # The @user_input variable should always be an Array. # ======================================================================= # @user_input = user_input end
#¶ ↑
open_this_file_in_editor
(edit tag, editor tag, open tag)¶ ↑
If you pass as first argument to this method the string 'ALL', we will try to open the (local) project files in your editor.
To test this, do:
open ALL open YAML
#¶ ↑
# File lib/ftp_paradise/interactive_ftp/misc.rb, line 47 def open_this_file_in_editor( this_file = @file ) this_file = ARRAY_PROJECT_FILES if this_file.nil? if this_file.is_a? Array this_file.each {|entry| open_this_file_in_editor(entry) } else this_file = this_file.to_s if this_file == 'TODO' this_file = ARRAY_PROJECT_FILES.select {|entry| entry.include? 'TODO' }[0] end if this_file.to_s =~ /^\d+$/ # If only numbers were given. this_file = Dir['*'].sort[this_file.to_i - 1] end this_file = NAME_OF_THIS_FILE if this_file.empty? if this_file == 'ALL' and ! File.exist?('ALL') open_this_file_in_editor(ARRAY_PROJECT_FILES) elsif this_file == 'YAML' and ! File.exist?('YAML') open_this_file_in_editor(YAML_FILE) else _ = @use_this_editor+" #{this_file}" if File.exist?(this_file) && File.file?(this_file) unless has_unwanted_file_suffix?(this_file) e 'Loading '+sfile(this_file)+' in editor '+ 'now as '+simp('USE_THIS_EDITOR')+' was set '+ 'to true:' e ' '+_+' &' `#{_}` end set_file(this_file) # Since 24.12.2011 we also assign it. else e swarn('But the file `')+sfile(this_file)+ swarn('` does not exist.') end end end end
#¶ ↑
remote_change_directory
¶ ↑
This method can be used to change directory on the remote host.
An argument such as :show_remote_file_listing can be passed as second argument to this method, in which case we will list the content of the remote directory after the cd-action.
If readline is used, as determined by the instance variable @use_readline, then we will attempt to cd-<TAB>.
Invocation example:
rcd htdocs
#¶ ↑
# File lib/ftp_paradise/interactive_ftp/directory_handling.rb, line 79 def remote_change_directory( i = f?, optional_instruction = nil, be_verbose = false ) i = i.first if i.is_a? Array i = '..' if i.nil? # <- Tiny "safeguard". # ======================================================================= # # We must first check whether we input only numbers, # and whether such a directory does NOT exist. # ======================================================================= # if (i =~ /^\d+$/) and !is_dir?(i) ftp?.update_file_listing i = ftp?.array_file_listing[i.to_i - 1] end if be_verbose e "Trying to cd into the remote directory `#{sfancy(i)}`." end case i # case tag when '?' # intercept ? e 'You went into these remote directories so far:' @array_history_remote_directories.each { |entry| e "- #{entry}" } else # This is the default. if i i.squeeze!('/') if i.include? '//' # Get rid of multiple //. e "Changing remote directory to `#{sdir(i)}` now." end begin ftp?.chdir(i) set_remote_directory(i) if optional_instruction case optional_instruction when :show_remote_file_listing show_remote_files end end rescue Exception => error pp error end end end
#¶ ↑
remote_create_directory
¶ ↑
#¶ ↑
# File lib/ftp_paradise/interactive_ftp/directory_handling.rb, line 192 def remote_create_directory( i = a?, be_verbose = true ) if i.is_a? Array i.each {|entry| remote_create_directory(entry, be_verbose) } else # ===================================================================== # # Delegate towards the respective module-method next. # ===================================================================== # if be_verbose e "Creating the directory #{sdir(i)} next:" end FtpParadise.remote_create_directory(i, @ftp) end end
#¶ ↑
remote_remove
¶ ↑
Use this if you wish to remove a remote file or a remote directory.
#¶ ↑
# File lib/ftp_paradise/interactive_ftp/remove.rb, line 36 def remote_remove(i) if i.is_a? Array i.each {|entry| remote_remove(entry) } else i = i.to_s.strip # Added as of July 2014. i = File.basename(i) if i.include? '/' # ===================================================================== # # The user may input numbers. If the input is a number, we will try to # find the corresponding entry - but only if no remote directory or # remote file exists with that name. Some directories may be named, # e. g. "123456". # ===================================================================== # unless this_remote_entry_exists? i i = convert_number_to_file(i) if i =~ /^\d+$/ end # ===================================================================== # # Next check for user input. If the user did input a '*', then we # will expand that. # ===================================================================== # if i.include?('*') or i.include?('*.') i = ftp?.array_file_listing.select {|entry| entry[0].include? i.delete('*') } i.reject! {|line| line == '.' or line == '..' # Reject '.' and '..' entries. } i.map! {|entry| File.basename(entry) } # ^^^ This is a bit hackish. remote_remove(i) else # =================================================================== # # We try to find out whether we have a directory or a file next. # =================================================================== # if is_dir?(i) remove_remote_directory(i) else # Assume it is a file. remove_remote_file(i) end end end end
#¶ ↑
remote_remove_file
¶ ↑
#¶ ↑
# File lib/ftp_paradise/interactive_ftp/misc.rb, line 150 def remote_remove_file( i = @first_argument ) if i.is_a? Array i.each {|entry| remote_remove_file(entry) } else e "Trying to remove `#{sfile(i)}` next:" @ftp.delete(i) end end
#¶ ↑
remote_url?¶ ↑
#¶ ↑
# File lib/ftp_paradise/interactive_ftp/misc.rb, line 143 def remote_url? FtpParadise.remote_url? end
#¶ ↑
remove_remote_directory
¶ ↑
Use this method to remove a remote directory.
#¶ ↑
# File lib/ftp_paradise/interactive_ftp/remove.rb, line 23 def remove_remote_directory(i) e "Removing remote directory `#{sdir(i)}` next." # ======================================================================= # # Delegate to ftp?. :force_remove so we remove even non-empty directories. # ======================================================================= # ftp?.remove_directory(i, :force_remove) end
#¶ ↑
remove_remote_file
¶ ↑
Use this method to attempt remove a remote file.
#¶ ↑
# File lib/ftp_paradise/interactive_ftp/remove.rb, line 84 def remove_remote_file(i) i[0,1] = ''.dup if i.start_with? '/' # We don't like starting "/" characters here. e "Removing remote file `#{sfile(i)}` next." # We remove the remote file here. begin result = ftp?.remove_file(i) e "Successfully removed remote file `#{sfile(result)}`." rescue Net::FTPPermError => error e 'Can not remove file `'+sfile(i)+'` as you are not '\ 'the owner. ('+simp('Net::FTPPermError')+')' pp error end end
#¶ ↑
report_local_directory
¶ ↑
Use only this method when reporting the local directory.
#¶ ↑
# File lib/ftp_paradise/interactive_ftp/directory_handling.rb, line 184 def report_local_directory e 'The local directory is: '+N+ @pad+sdir(return_pwd) end
#¶ ↑
report_remote_directory
¶ ↑
This method will report the remote directory.
#¶ ↑
# File lib/ftp_paradise/interactive_ftp/directory_handling.rb, line 23 def report_remote_directory( make_newline = true ) if is_connected? remote_dir = sdir(ftp_remote_directory?) if make_newline e 'The remote directory is: ' e " #{sdir(remote_dir)}" else e 'The remote directory is: '+sdir(remote_dir) end else e 'No connection is available. You may have to re-connect again.' end end
#¶ ↑
reset (reset tag)¶ ↑
Initialize and/or reset the variables used in this class.
#¶ ↑
# File lib/ftp_paradise/interactive_ftp/reset.rb, line 19 def reset super() # ======================================================================= # # The following check is for my home system. # ======================================================================= # if File.exist? FILE_ROEBE_FTP dataset = YAML.load_file(FILE_ROEBE_FTP) determine_user_dataset_from_this_hash(dataset, :default) end # ======================================================================= # # === @user_input # # Must "initialize" @user_input. # ======================================================================= # @user_input = nil # ======================================================================= # # Which files we did download so far. # ======================================================================= # @array_downloaded_files = [] # ======================================================================= # # === @array_all_input # ======================================================================= # @array_all_input = [] # Stores which was the input. # ======================================================================= # # === @history # ======================================================================= # @history = [] # ======================================================================= # # === @array_history_remote_directories # # This array keeps a listing of all remote directories we rcd-ed into. # ======================================================================= # @array_history_remote_directories = [] # ======================================================================= # # === @debug # # Whether we will debug or not, by default. # ======================================================================= # @debug = SHALL_WE_DEBUG # ======================================================================= # # === @are_we_connected # ======================================================================= # @are_we_connected = false # ======================================================================= # # === @pad # ======================================================================= # @pad = ' ' # The default padding to use. # ======================================================================= # # === @use_readline # # Initially we will try to make use of the Readline module. # ======================================================================= # @use_readline = true # ======================================================================= # # === @use_this_editor # # Specify which editor we may use - this can be overruled in the # interactive menu by the user of the FtpParadise project. # ======================================================================= # @use_this_editor = USE_THIS_EDITOR # ======================================================================= # # Try to make use of the Readline module as well. # ======================================================================= # consider_using_the_readline_module reset_instance_variables_that_hold_all_arguments set_file set_local_directory load_config initialize_ftp_object # Initialize the @ftp variable. end
#¶ ↑
set_mode
¶ ↑
Set the mode here. We default to :ascii mode.
There are only two valid modes:
:ascii :binary
#¶ ↑
# File lib/ftp_paradise/interactive_ftp/mode.rb, line 40 def set_mode( i = :ascii ) @mode = i ftp?.set_transfer_mode( @mode, :be_quiet # Cascade the variable down into ftp_lib.rb. ) end
#¶ ↑
setup_readline_completion
¶ ↑
Call this method to invoke completion support.
#¶ ↑
# File lib/ftp_paradise/interactive_ftp/readline.rb, line 66 def setup_readline_completion Readline.completion_case_fold = true # Ignore case on tab-completion. Readline.completer_word_break_characters = "\n" Readline.completion_append_character = ' ' # ======================================================================= # # Act on Readline's completion functionality here. (readline tag) # # We will respond to these events specifically: # # - rcd # - cd # - upload # - download # # ======================================================================= # Readline.completion_proc = proc {|input| _ = [] case input # case tag # ===================================================================== # # To test it, do: # rcd AUS<TAB> # ===================================================================== # when /^rcd/, /^rcd /, /^rc/, 'rchange_dir', 'lcd', 'remote_change_directory' result = @_.return_directories # This will return the remote directories only. _ << result.map {|entry| input+' '+entry} # ===================================================================== # # === cd # ===================================================================== # when /^cd/,/^cd / # Fetch only directories. _ << @_.return_local_directories when /^upload/ # Act on upload. return_local_files.each { |array| _ << array } when /^download/ # Act on download. @_.array_file_listing.each { |array| _ << array.first } else # Default. # _ << return_local_files # Disabled in June 2014 because it gives completions to things I did not ask for. end _ = _.flatten _ # Return it here finally. } end
#¶ ↑
show_help
(help tag)¶ ↑
#¶ ↑
# File lib/ftp_paradise/interactive_ftp/help.rb, line 14 def show_help cliner e "Try one of these #{sfancy('help options')} for interactive-ftp:#{N}#{N}" e parens(:assign)+' '+pound_token+'Assign to the @file variable' e parens(:help)+' '+pound_token+'To see the help section' e parens(:history)+' '+pound_token+'To show the history' e parens(:cd)+' '+pound_token+'Change local directory' e parens(:config)+' '+pound_token+'Show the configuration' e parens(:dated)+' '+pound_token+'Display the remote directory '\ 'content in a time-sorted manner' e parens(:edit)+' '+pound_token+'Edit this file here in your main editor' e parens(:everything)+' '+pound_token+'Show everything (username, password, host and so on)' e parens(:login)+' '+pound_token+'Connect to the remote host (alias '\ 'to connect_to exists)' e parens(:list)+' '+pound_token+'List remote files' e parens(:last)+' '+pound_token+'Repeat the last action (or show the last action)' e parens(:rcd)+' '+pound_token+'Change remote directory' e parens(:remote?)+' '+pound_token+'List where we are connected' e parens(:stat)+' '+pound_token+'Show information about a file' e parens(:status?)+' '+pound_token+'See the current status of the connection' e parens(:file?)+' '+pound_token+'Shows whether we have a '+ 'default file set (which can be used to upload)' e parens(:info)+' '+pound_token+'Shows some information (debug)' e parens(:set_port)+' '+pound_token+'Set the port number' e parens(:q)+' '+pound_token+'To quit/exit' e parens(:quit)+' '+pound_token+'Quit the session' if on_roebe? # Display it only for me. e parens(:shevy)+' '+pound_token+'Connect to shevy' end e parens(:lpwd)+' '+pound_token+'Report the current remote directory' e parens(:pwd)+' '+pound_token+'Report the local directory'+N e parens(:welcome)+' '+pound_token+'Show the welcome-message of the remote FTP server'+N e cliner end
#¶ ↑
show_history
¶ ↑
This method can be used to display the input-history of the user.
#¶ ↑
# File lib/ftp_paradise/interactive_ftp/show.rb, line 84 def show_history # History tag. e "The history for #{sfancy(return_title)} is:" @history.each_with_index { |key, index| e '%3s' % (index+1).to_s+' '+key } end
#¶ ↑
show_remote_directories
¶ ↑
#¶ ↑
# File lib/ftp_paradise/interactive_ftp/show.rb, line 14 def show_remote_directories e "The remote directories at #{sdir(return_remote_pwd)} are:" e ftp?.return_remote_directories.each_with_index {|dir, index| index += 1 e index.to_s.rjust(3)+') '+sdir(dir) } e end
#¶ ↑
show_which_files_we_did_download_so_far
¶ ↑
#¶ ↑
# File lib/ftp_paradise/interactive_ftp/show.rb, line 94 def show_which_files_we_did_download_so_far if @array_downloaded_files.empty? e 'We did not yet download any file.' else e 'We downloaded these files so far:' pp @array_downloaded_files end end
#¶ ↑
try_to_use_readline
¶ ↑
This method ought to be called before we invoke the method menu().
#¶ ↑
# File lib/ftp_paradise/interactive_ftp/readline.rb, line 47 def try_to_use_readline if @use_readline begin require 'readline' # Using readline since August 2011. setup_readline_completion rescue LoadError # =================================================================== # # In this case the user can not use the readline-module. # =================================================================== # do_not_use_readline end end end
#¶ ↑
upload (upload tag)¶ ↑
Use this method to upload something locally to the remote site.
You can also upload several files in one go - to do this, try one of these ways:
upload 7,8 # This would upload file position 7 and 8. upload 1..293
#¶ ↑
# File lib/ftp_paradise/interactive_ftp/upload.rb, line 23 def upload( i = Dir['*'] ) # ======================================================================= # # We will always work with an Array past the following point. # ======================================================================= # i = [i].flatten.compact # Safeguard against nil. if i.empty? i << @file if @file end i.map! {|entry| if entry.include?('-') and !entry.include?('.') # Assume a range was given like 1-20. splitted = entry.split('-') entry = (splitted[0] .. splitted[1]).to_a elsif entry.include?('..') # Assume a range such as: upload 1..25 entry =~ /(\d+)\.\.(\d+)/ start_position = $1.to_s.dup.to_i end_position = $2.to_s.dup.to_i entry = return_local_files[start_position, end_position] elsif entry.include?(',') splitted = i.split(',') entry = (splitted[0] .. splitted[1]).to_a elsif (entry == 'ALL') or (entry == '*') entry = Dir['*'] elsif entry.include?('*.') or entry.include?('*') entry = Dir[entry] end entry } i.flatten! i.compact! if on_roebe? and !is_connected? connect_to :shevy end i.each {|this_file| if this_file =~ /^\d+$/ # upload only a specific number. sorted = Dir['*'].sort if i.is_a? Array i = i.first end this_file = sorted[i.to_i - 1] end _ = this_file # default to upload to 'all' if File.exist?(_) # =================================================================== # # Next, some files will always be in binary mode. These are # defined in the Array ARRAY_BINARY_FILES. # =================================================================== # if ARRAY_BINARY_FILES.include?(File.extname(_).delete('.')) and (@mode != :binary) use_binary_mode end case @mode when :ascii set_file(_) ftp?.upload(_) # And now, call the functionality in the FTP lib. else ftp?.upload_binary(_) end else opne swarn('But the file `')+ sfile(i)+ swarn('` does not exist.') end } end
#¶ ↑
use_binary_mode
¶ ↑
This enables use the binary mode.
#¶ ↑
# File lib/ftp_paradise/interactive_ftp/mode.rb, line 16 def use_binary_mode( be_verbose = false ) case be_verbose when :be_quiet be_verbose = false when :be_verbose be_verbose = true end e 'Using binary mode now.' if be_verbose set_mode :binary end