#encoding: UTF-8 =begin /*************************************************************************** * 2023-2024, Michael Uplawski * * This program is free software; you can redistribute it and/or modify * * it under the terms of the WTFPL 2.0 or later, see * * http://www.wtfpl.net/about/ * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * * ***************************************************************************/ =end # This class manages a dialog to alter the behavior of the # post-processor on a “per article” basis. It can be displayed # before posting, to do some “last minute” changes, # notably to deactivate them. # # Post-processing CANNOT be deactivated completely in this dialog. # I do not remember, why a previous comment stated the contrary. require_relative 'basic_logging' class OverrideDlg include BasicLogging XTERM = 'xterm' # TERMINAL = 'x-terminal-emulator' WHIPTAIL = 'whiptail' YAD = 'yad' ZENITY = 'zenity' # The external programs which are supported for the time. They will be run in # a new process (IO.popen() ). The first program from this array, which is # found in the Path, will be used. Whiptail and a pure ruby dialog # necessitate that xterm be found, too. @@Executables = [YAD, ZENITY, WHIPTAIL, XTERM] @@LIBDIR = File::dirname(__FILE__) # The configuration variables that can be unset. # This class instance variable is exposed via a getter. @cvars = [:GROUP_SIGS, :CUSTOM_HEADERS, :NO_ARCHIVE_GROUPS, :VFY_URLS, :DEBUG_LOG] # ... here # For the record: this is rather cool. # ... believe me! It is! class << self attr_reader :cvars end # Love it. # Create the object def initialize @config = Configuration::instance # find the supported programs @executables = @@Executables.select do |ex_name| program?(ex_name) end # As we are calling external programs anyway, # why not continue with that ... @xmsg = ENV['PATH'].split(':').any? {|d| Dir.children(d).include?('xmessage')} # bof. end # display a dialog and return the new options. def show if(@executables && !@executables.empty?) debug('found executables ' << @executables.join(', ')) opts = nil begin if has?(YAD) return yad_dlg.split.collect {|o| o.to_s}.join(' ') elsif has?(ZENITY) return zenity_dlg.split.collect {|o| o.to_s}.join(' ') elsif has? XTERM if has?(WHIPTAIL) return whiptail_dlg.split.collect {|o| o.to_s}.join(' ') else debug 'using naked xterm' return ruby_dlg.split.collect {|o| o.to_s}.join(' ') end end rescue SystemExit msg = 'Process is cancelled (SystemExit)' info msg exit true rescue Exception => ex msg = 'Error upon showing dialog ' << ex.message error(msg) end # no program to show the dialog else msg = "#{File.basename($0)}: No suitable executable found to display the dialog" warn msg # if xmessage is available, give the user a last chance. if @xmsg io = IO.popen('xmessage -buttons continue:0,abort:1 -default abort -print ' << msg) Process.wait(io.pid) # ATTN! read io only once! exit if ('continue' != io.read.to_s.strip ) # ... but then again, we still have a log. debug('continue with configured settings') end end end private # I know what it does and that there is some # redundancy with the following method, but I # do not feel like sorting it out, now. def program?(ex_name) ENV['PATH'].split(':').each do |dir_name| return true if Dir.entries(dir_name).include?(ex_name) end return false end # returns true if the executable ex_name is to be # called for the dialog def has?(ex_name) @executables.include? ex_name end ###### The following methods call a script, each, in an external process. # There appears to be some Exception handling missing, but it does not # hurt for the time being. Anyway, I do not care. # creates a whiptail dialog in xterm. def whiptail_dlg debug('whiptail dialog') tf = Tempfile.new # dlg = @config.BINDIR << File::Separator << 'whiptail_dlg' dlg = @@LIBDIR << File::Separator << 'whiptail_dlg' dialog = XTERM.dup << ' -e ' << dlg << ' ' << tf.path io = IO::popen(dialog) Process.wait(io.pid ) nopts = tf.read exit true if('exit' == nopts.strip) tf.unlink return nopts end # creates a textual dialog in xterm. def ruby_dlg debug('xterm dialog') tf = Tempfile.new # dlg = @config.BINDIR << File::Separator << 'ruby_dlg' dlg = @@LIBDIR << File::Separator << 'ruby_dlg' begin dialog = XTERM.dup << ' -e ' << dlg << ' ' << tf.path debug('dialog will be ' << dialog) rescue Exception => ex error ex.message wait_for_user exit false end io = IO::popen(dialog) debug('wait for ' << io.pid.to_s) Process.wait(io.pid ) nopts = tf.read exit true if('exit' == nopts.strip) tf.unlink return nopts end # creates a Zenity dialog. def zenity_dlg debug('Zenity dialog') # dialog = @config.BINDIR << File::Separator << 'zenity_dlg' dialog = @@LIBDIR << File::Separator << 'zenity_dlg' io = IO.popen(dialog) Process::wait(io.pid) rc = $?.exitstatus exit true if rc != 0 nopts = io.read return nopts end # creates a YAD dialog. def yad_dlg debug('yad dialog') # dialog = @config.BINDIR << File::Separator << 'yad_dlg' dialog = @@LIBDIR << File::Separator << 'yad_dlg' debug('dialog will be ' << dialog) io = IO::popen(dialog) Process::wait(io.pid) exit true if $?.exitstatus != 0 nopts = io.read return nopts end end # EOF