flnews_post_proc 1.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +374 -0
- data/bin/flnews_post_proc +84 -0
- data/doc/html/flnews_post_proc.html +654 -0
- data/doc/html/flnews_post_proc_fr.html +701 -0
- data/doc/license.txt +13 -0
- data/doc/man/flnews_post_proc.1.gz +0 -0
- data/doc/man/flnews_post_proc_fr.1.gz +0 -0
- data/doc/pdf/flnews_post_proc.pdf +0 -0
- data/doc/pdf/flnews_post_proc_fr.pdf +0 -0
- data/doc/rst/flnews_post_proc.rst +334 -0
- data/doc/rst/flnews_post_proc_fr.rst +377 -0
- data/lib/basic_logging.rb +170 -0
- data/lib/body.rb +270 -0
- data/lib/color_output.rb +65 -0
- data/lib/configuration.rb +136 -0
- data/lib/flnews_post_proc.conf +172 -0
- data/lib/flnews_post_proc.rb +71 -0
- data/lib/headers.rb +148 -0
- data/lib/newsgroups.rb +134 -0
- data/lib/override.rb +199 -0
- data/lib/ruby_dlg +136 -0
- data/lib/version.rb +21 -0
- data/lib/whiptail_dlg +79 -0
- data/lib/yad_dlg +52 -0
- data/lib/zenity_dlg +59 -0
- metadata +88 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#encoding: UTF-8
|
|
2
|
+
=begin
|
|
3
|
+
/***************************************************************************
|
|
4
|
+
* 2023-2024, Michael Uplawski <michael.uplawski@uplawski.eu> *
|
|
5
|
+
* This program is free software; you can redistribute it and/or modify *
|
|
6
|
+
* it under the terms of the WTFPL 2.0 or later, see *
|
|
7
|
+
* http://www.wtfpl.net/about/ *
|
|
8
|
+
* *
|
|
9
|
+
* This program is distributed in the hope that it will be useful, *
|
|
10
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
11
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
|
12
|
+
* *
|
|
13
|
+
***************************************************************************/
|
|
14
|
+
=end
|
|
15
|
+
|
|
16
|
+
require 'yaml'
|
|
17
|
+
require 'ostruct'
|
|
18
|
+
# --needs the Diffy gem
|
|
19
|
+
require 'diffy'
|
|
20
|
+
|
|
21
|
+
require_relative 'configuration'
|
|
22
|
+
require_relative 'basic_logging'
|
|
23
|
+
require_relative 'headers'
|
|
24
|
+
require_relative 'body'
|
|
25
|
+
|
|
26
|
+
# line-break in the final article
|
|
27
|
+
$LN = "\r\n"
|
|
28
|
+
|
|
29
|
+
# The main application class.
|
|
30
|
+
# Does it.
|
|
31
|
+
class PostProcessor
|
|
32
|
+
# class-level configuration object
|
|
33
|
+
@@config = Configuration.instance
|
|
34
|
+
include BasicLogging
|
|
35
|
+
|
|
36
|
+
def initialize(article_text)
|
|
37
|
+
# for simplicity.
|
|
38
|
+
# separate the headers and the body.
|
|
39
|
+
debug ' initializing headers'
|
|
40
|
+
headers = Headers.new(article_text)
|
|
41
|
+
debug('headers is ' << headers.inspect)
|
|
42
|
+
body = Body.new(article_text)
|
|
43
|
+
|
|
44
|
+
debug('calling headers.update')
|
|
45
|
+
headers.update()
|
|
46
|
+
|
|
47
|
+
newsgroups = headers.newsgroups
|
|
48
|
+
|
|
49
|
+
# Order matters. These actions work on a
|
|
50
|
+
# preliminary version of the article, each
|
|
51
|
+
# one on the result of the previous !
|
|
52
|
+
body.set_intro(newsgroups.intro)
|
|
53
|
+
|
|
54
|
+
# if need be, extract references and footnotes.
|
|
55
|
+
body.handle_references
|
|
56
|
+
body.set_signature(newsgroups.signature)
|
|
57
|
+
|
|
58
|
+
# verify and eventually correct URLs
|
|
59
|
+
body.handle_urls
|
|
60
|
+
|
|
61
|
+
# get the headers and the body as a string.
|
|
62
|
+
# Assemble.
|
|
63
|
+
@article = headers.join << $LN << body.join
|
|
64
|
+
|
|
65
|
+
diff = Diffy::Diff.new(article_text, @article, :context => 2).to_s
|
|
66
|
+
info("\n" << "–" * 20 << "\nDiffs\n" << "–" * 20 << "\n" << diff)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
attr_reader :article
|
|
70
|
+
end
|
|
71
|
+
# EOF
|
data/lib/headers.rb
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
#encoding: UTF-8
|
|
2
|
+
=begin
|
|
3
|
+
/***************************************************************************
|
|
4
|
+
* 2023-2024, Michael Uplawski <michael.uplawski@uplawski.eu> *
|
|
5
|
+
* This program is free software; you can redistribute it and/or modify *
|
|
6
|
+
* it under the terms of the WTFPL 2.0 or later, see *
|
|
7
|
+
* http://www.wtfpl.net/about/ *
|
|
8
|
+
* *
|
|
9
|
+
* This program is distributed in the hope that it will be useful, *
|
|
10
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
11
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
|
12
|
+
* *
|
|
13
|
+
***************************************************************************/
|
|
14
|
+
=end
|
|
15
|
+
|
|
16
|
+
require_relative 'basic_logging'
|
|
17
|
+
require_relative 'configuration'
|
|
18
|
+
require_relative 'newsgroups'
|
|
19
|
+
|
|
20
|
+
# an object of this class represents the headers of a news-article
|
|
21
|
+
|
|
22
|
+
class Headers
|
|
23
|
+
# class-level configuration object
|
|
24
|
+
@@config = Configuration.instance
|
|
25
|
+
include BasicLogging
|
|
26
|
+
|
|
27
|
+
# read the headers from the article
|
|
28
|
+
def initialize(article_text)
|
|
29
|
+
|
|
30
|
+
line = nil
|
|
31
|
+
# transform the article to an array.
|
|
32
|
+
debug('before split, article_text is : ' << article_text)
|
|
33
|
+
line_array = article_text.split($LN)
|
|
34
|
+
debug('after split, line_array is : ' << line_array.inspect)
|
|
35
|
+
# find the first empty line
|
|
36
|
+
end_index = line_array.index {|ele| ele.strip == ''}
|
|
37
|
+
# keep the preceding lines.
|
|
38
|
+
@lines = line_array.slice!(0, end_index)
|
|
39
|
+
debug('headers: ' << @lines.to_s)
|
|
40
|
+
|
|
41
|
+
# headername: headervalue
|
|
42
|
+
@headers = {}
|
|
43
|
+
|
|
44
|
+
# fill the headers Hash from the header-lines.
|
|
45
|
+
# headers may have been line-wrapped.
|
|
46
|
+
|
|
47
|
+
cur_header = nil
|
|
48
|
+
@lines.each do |l|
|
|
49
|
+
# has the header been wrapped?
|
|
50
|
+
if !l.start_with?(/\s+/)
|
|
51
|
+
# header is all before the first colon
|
|
52
|
+
begin
|
|
53
|
+
cur_header = l.match(/^(.*?):/)[1].to_sym
|
|
54
|
+
rescue Exception => ex
|
|
55
|
+
error ("Cannot match a header in line " << l << "(" << ex.message << ")")
|
|
56
|
+
exit false;
|
|
57
|
+
end
|
|
58
|
+
# value is all after the first colon
|
|
59
|
+
# BUGGY: val = l.match(/:(.*)/)[1].strip
|
|
60
|
+
# BUGFIX 3/2024
|
|
61
|
+
val = l.match(/:(.*)/)[1].lstrip
|
|
62
|
+
else # start_with?(' ')
|
|
63
|
+
# a wrapped value is not devided
|
|
64
|
+
# BUGGY: val = l.strip
|
|
65
|
+
# BUGFIX 3/2024
|
|
66
|
+
val = l
|
|
67
|
+
end
|
|
68
|
+
# add value to the existing
|
|
69
|
+
if cur_header && @headers[cur_header]
|
|
70
|
+
@headers[cur_header] += val
|
|
71
|
+
else
|
|
72
|
+
# or add a new value
|
|
73
|
+
@headers[cur_header] = val
|
|
74
|
+
end
|
|
75
|
+
#@headers[l.match(/^(.*?):/)[1].to_sym] = l.match(/:(.*)/)[1].strip
|
|
76
|
+
# h = l.split(':')
|
|
77
|
+
# @headers[h[0].strip.to_sym] = h[1...h.size].join(':').strip
|
|
78
|
+
end
|
|
79
|
+
debug('headers are ' << @headers.to_s)
|
|
80
|
+
@newsgroups = Newsgroups.new(header(:Newsgroups))
|
|
81
|
+
debug('Newsgroups is ' << @newsgroups.inspect)
|
|
82
|
+
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# returns the value of header 'name'
|
|
86
|
+
def header(name)
|
|
87
|
+
# name must be a symbol.
|
|
88
|
+
if name.respond_to?(:to_sym)
|
|
89
|
+
@headers[name]
|
|
90
|
+
else
|
|
91
|
+
error(name.to_s << ' is not a symbol!')
|
|
92
|
+
nil
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Modify headers, if need be.
|
|
97
|
+
def update()
|
|
98
|
+
xnay = @newsgroups.xnay
|
|
99
|
+
debug('xnay should be set now : ' << xnay.to_s)
|
|
100
|
+
if xnay
|
|
101
|
+
@headers["X-No-Archive".to_sym] = xnay
|
|
102
|
+
end
|
|
103
|
+
ch = @@config.CUSTOM_HEADERS
|
|
104
|
+
debug('setting custom headers : ' << ch.inspect)
|
|
105
|
+
if @@config.CUSTOM_HEADERS
|
|
106
|
+
@@config.CUSTOM_HEADERS.each do |pair|
|
|
107
|
+
ch = pair.split(':')
|
|
108
|
+
hn = ch[0].strip
|
|
109
|
+
hv = ch[1].strip
|
|
110
|
+
# Ensure header is ascii only
|
|
111
|
+
if hv.ascii_only? && hn.ascii_only?
|
|
112
|
+
# <---------- special treatment Post-Processor ---------->
|
|
113
|
+
hv << ' ' << PROGVERSION.to_s if hn == 'X-Post-Processor' && hv == 'flnews_post_proc'
|
|
114
|
+
# >----------<
|
|
115
|
+
@headers[hn.to_sym] = hv
|
|
116
|
+
else
|
|
117
|
+
warn "Custom header [#{hn}:#{hv}] should be ASCII only! Header is ignored!"
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
@headers.compact!
|
|
121
|
+
end
|
|
122
|
+
debug('updated headers are ' << @headers.inspect)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# remove a header
|
|
126
|
+
def remove(name)
|
|
127
|
+
@headers.delete(name) if @headers[name]
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# basically a replacement for header(name), above.
|
|
131
|
+
# But you can call self.Newsgroups or self.From etc.
|
|
132
|
+
def method_missing(method, args = nil)
|
|
133
|
+
return @headers[method] if @headers[method]
|
|
134
|
+
error("unknown symbol '#{method}'")
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# return the headers as a String.
|
|
138
|
+
def join
|
|
139
|
+
htext = ''
|
|
140
|
+
@headers.each_pair {|h, t| htext << h.to_s << ': ' << t << $LN }
|
|
141
|
+
debug('joined headers: ' << htext)
|
|
142
|
+
htext
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
attr_reader :lines, :newsgroups
|
|
146
|
+
|
|
147
|
+
end
|
|
148
|
+
# EOF
|
data/lib/newsgroups.rb
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
#encoding: UTF-8
|
|
2
|
+
=begin
|
|
3
|
+
/***************************************************************************
|
|
4
|
+
* 2023-2024, Michael Uplawski <michael.uplawski@uplawski.eu> *
|
|
5
|
+
* This program is free software; you can redistribute it and/or modify *
|
|
6
|
+
* it under the terms of the WTFPL 2.0 or later, see *
|
|
7
|
+
* http://www.wtfpl.net/about/ *
|
|
8
|
+
* *
|
|
9
|
+
* This program is distributed in the hope that it will be useful, *
|
|
10
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
11
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
|
12
|
+
* *
|
|
13
|
+
***************************************************************************/
|
|
14
|
+
=end
|
|
15
|
+
|
|
16
|
+
# An object of this class concentrates the specificities of chosen
|
|
17
|
+
# newsgroups, as defined in the configuration.
|
|
18
|
+
|
|
19
|
+
require_relative 'configuration'
|
|
20
|
+
require_relative 'basic_logging'
|
|
21
|
+
|
|
22
|
+
class Newsgroups
|
|
23
|
+
# class-level configuration object
|
|
24
|
+
@@config = Configuration.instance
|
|
25
|
+
include BasicLogging
|
|
26
|
+
|
|
27
|
+
def initialize(groups)
|
|
28
|
+
@groups = groups.split(',')
|
|
29
|
+
debug('set signature, intro, xnay')
|
|
30
|
+
# set details for this post
|
|
31
|
+
if @groups.size == 1
|
|
32
|
+
set_signature
|
|
33
|
+
set_intro
|
|
34
|
+
set_xnay
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def xnay
|
|
39
|
+
debug('returning ' <<( @xnay ? @xnay : ' nil ') )
|
|
40
|
+
return @xnay ? @xnay : nil
|
|
41
|
+
end
|
|
42
|
+
attr_reader :signature, :intro, :groups
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
# defines the intro-line as per group.
|
|
47
|
+
def set_intro
|
|
48
|
+
|
|
49
|
+
@intro = nil
|
|
50
|
+
# only one group.
|
|
51
|
+
group = @groups[0]
|
|
52
|
+
# all configured intro-lines.
|
|
53
|
+
gintros = @@config.GROUP_INTROS
|
|
54
|
+
|
|
55
|
+
if gintros && gintros.respond_to?(:to_hash)
|
|
56
|
+
# find the intro for the group.
|
|
57
|
+
# either by name
|
|
58
|
+
if gintros.keys.include?(group)
|
|
59
|
+
@intro = gintros[group]
|
|
60
|
+
else
|
|
61
|
+
# or by a regular expression.
|
|
62
|
+
gintros.each do |gr, intro|
|
|
63
|
+
unless @intro
|
|
64
|
+
@intro = intro if group.match(gr)
|
|
65
|
+
debug "matched group against " << gr if @intro
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
debug('group_intro is ' << @intro.to_s)
|
|
70
|
+
else
|
|
71
|
+
msg = 'Cannot set the introduction line from the configuration!'
|
|
72
|
+
msg << "\nPlease verify that GROUP_INTROS is set"
|
|
73
|
+
warn(msg)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# replace all \n by \r\n
|
|
78
|
+
def correct_linebreaks(text)
|
|
79
|
+
warned = false
|
|
80
|
+
# find all lonely \n
|
|
81
|
+
while text.match(/([^\r])\n/) do
|
|
82
|
+
warn("ATTN! Line-breaks should be \\r\\n! Verify signatures!" ) if !warned
|
|
83
|
+
warned ||= true
|
|
84
|
+
# ... and silently marry them to \r
|
|
85
|
+
text.gsub!($~[0],$~[1] + "\r\n")
|
|
86
|
+
# Luxury you can afford.
|
|
87
|
+
end # \n
|
|
88
|
+
text
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# define the signature
|
|
92
|
+
def set_signature
|
|
93
|
+
@signature = nil
|
|
94
|
+
# 1 group
|
|
95
|
+
group = @groups[0]
|
|
96
|
+
gsigs = @@config.GROUP_SIGS
|
|
97
|
+
|
|
98
|
+
if gsigs && gsigs.respond_to?(:to_hash)
|
|
99
|
+
# find the signature for the group
|
|
100
|
+
# either by name
|
|
101
|
+
if gsigs.keys.include?(group)
|
|
102
|
+
@signature = gsigs[group]
|
|
103
|
+
debug('signature is ' << @signature ) if @signature
|
|
104
|
+
# .., or by applying a regexp.
|
|
105
|
+
else
|
|
106
|
+
gsigs.each do |g, s|
|
|
107
|
+
unless @signature
|
|
108
|
+
rg = Regexp.new(g)
|
|
109
|
+
sm = group.match(rg)
|
|
110
|
+
debug('signature for group(s) ' << g << ': ' << s) if sm
|
|
111
|
+
if sm
|
|
112
|
+
@signature = correct_linebreaks(s)
|
|
113
|
+
end # if sm
|
|
114
|
+
end # if no signature
|
|
115
|
+
end # gsigs.each
|
|
116
|
+
end # gsigs for group?
|
|
117
|
+
else # gsigs and is hash?
|
|
118
|
+
msg = "Cannot read the signatures from the configuration."
|
|
119
|
+
msg << "\nPlease verify that GROUP_SIGS is set."
|
|
120
|
+
warn(msg)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# define the xnay header.
|
|
125
|
+
def set_xnay
|
|
126
|
+
@xnay = nil
|
|
127
|
+
xgs = @@config.XNAY_GROUPS
|
|
128
|
+
if xgs && !xgs.empty? && xgs.detect {|g| @groups[0].match(g) }
|
|
129
|
+
debug("setting XNAY")
|
|
130
|
+
@xnay = 'YES'
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
# EOF
|
data/lib/override.rb
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
#encoding: UTF-8
|
|
2
|
+
=begin
|
|
3
|
+
/***************************************************************************
|
|
4
|
+
* 2023-2024, Michael Uplawski <michael.uplawski@uplawski.eu> *
|
|
5
|
+
* This program is free software; you can redistribute it and/or modify *
|
|
6
|
+
* it under the terms of the WTFPL 2.0 or later, see *
|
|
7
|
+
* http://www.wtfpl.net/about/ *
|
|
8
|
+
* *
|
|
9
|
+
* This program is distributed in the hope that it will be useful, *
|
|
10
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
11
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
|
12
|
+
* *
|
|
13
|
+
***************************************************************************/
|
|
14
|
+
=end
|
|
15
|
+
|
|
16
|
+
# This class manages a dialog to alter the behavior of the
|
|
17
|
+
# post-processor on a “per article” basis. It can be displayed
|
|
18
|
+
# before posting, to do some “last minute” changes,
|
|
19
|
+
# notably to deactivate them.
|
|
20
|
+
#
|
|
21
|
+
# Post-processing CANNOT be deactivated completely in this dialog.
|
|
22
|
+
# I do not remember, why a previous comment stated the contrary.
|
|
23
|
+
|
|
24
|
+
require_relative 'basic_logging'
|
|
25
|
+
|
|
26
|
+
class OverrideDlg
|
|
27
|
+
|
|
28
|
+
include BasicLogging
|
|
29
|
+
|
|
30
|
+
XTERM = 'xterm'
|
|
31
|
+
# TERMINAL = 'x-terminal-emulator'
|
|
32
|
+
WHIPTAIL = 'whiptail'
|
|
33
|
+
YAD = 'yad'
|
|
34
|
+
ZENITY = 'zenity'
|
|
35
|
+
# The external programs which are supported for the time. They will be run in
|
|
36
|
+
# a new process (IO.popen() ). The first program from this array, which is
|
|
37
|
+
# found in the Path, will be used. Whiptail and a pure ruby dialog
|
|
38
|
+
# necessitate that xterm be found, too.
|
|
39
|
+
@@Executables = [YAD, ZENITY, WHIPTAIL, XTERM]
|
|
40
|
+
@@LIBDIR = File::dirname(__FILE__)
|
|
41
|
+
# The configuration variables that can be unset.
|
|
42
|
+
# This class instance variable is exposed via a getter.
|
|
43
|
+
@cvars = [:GROUP_SIGS, :CUSTOM_HEADERS, :XNAY_GROUPS, :VFY_URLS, :DEBUG_LOG]
|
|
44
|
+
|
|
45
|
+
# ... here
|
|
46
|
+
# For the record: this is rather cool.
|
|
47
|
+
# ... believe me! It is!
|
|
48
|
+
class << self
|
|
49
|
+
attr_reader :cvars
|
|
50
|
+
end
|
|
51
|
+
# Love it.
|
|
52
|
+
|
|
53
|
+
# Create the object
|
|
54
|
+
def initialize
|
|
55
|
+
@config = Configuration::instance
|
|
56
|
+
# find the supported programs
|
|
57
|
+
@executables = @@Executables.select do |ex_name|
|
|
58
|
+
program?(ex_name)
|
|
59
|
+
end
|
|
60
|
+
# As we are calling external programs anyway,
|
|
61
|
+
# why not continue with that ...
|
|
62
|
+
@xmsg = ENV['PATH'].split(':').any? {|d| Dir.children(d).include?('xmessage')}
|
|
63
|
+
# bof.
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# display a dialog and return the new options.
|
|
67
|
+
def show
|
|
68
|
+
if(@executables && !@executables.empty?)
|
|
69
|
+
debug('found executables ' << @executables.join(', ') )
|
|
70
|
+
opts = nil
|
|
71
|
+
begin
|
|
72
|
+
if has?(YAD)
|
|
73
|
+
return yad_dlg.split.collect {|o| o.to_s}.join(' ')
|
|
74
|
+
elsif has?(ZENITY)
|
|
75
|
+
return zenity_dlg.split.collect {|o| o.to_s}.join(' ')
|
|
76
|
+
elsif has? XTERM
|
|
77
|
+
if has?(WHIPTAIL)
|
|
78
|
+
return whiptail_dlg.split.collect {|o| o.to_s}.join(' ')
|
|
79
|
+
else
|
|
80
|
+
debug 'using naked xterm'
|
|
81
|
+
return ruby_dlg.split.collect {|o| o.to_s}.join(' ')
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
rescue SystemExit
|
|
85
|
+
msg = 'Process is cancelled (SystemExit)'
|
|
86
|
+
info msg
|
|
87
|
+
exit true
|
|
88
|
+
rescue Exception => ex
|
|
89
|
+
msg = 'Error upon showing dialog ' << ex.message
|
|
90
|
+
error(msg)
|
|
91
|
+
end
|
|
92
|
+
# no program to show the dialog
|
|
93
|
+
else
|
|
94
|
+
msg = "#{File.basename($0)}: No suitable executable found to display the dialog"
|
|
95
|
+
warn msg
|
|
96
|
+
# if xmessage is available, give the user a last chance.
|
|
97
|
+
if @xmsg
|
|
98
|
+
io = IO.popen('xmessage -buttons continue:0,abort:1 -default abort -print ' << msg)
|
|
99
|
+
Process.wait(io.pid)
|
|
100
|
+
# ATTN! read io only once!
|
|
101
|
+
exit if ('continue' != io.read.to_s.strip )
|
|
102
|
+
# ... but then again, we still have a log.
|
|
103
|
+
debug('continue with configured settings')
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
private
|
|
109
|
+
# I know what it does and that there is some
|
|
110
|
+
# redundancy with the following method, but I
|
|
111
|
+
# do not feel like sorting it out, now.
|
|
112
|
+
def program?(ex_name)
|
|
113
|
+
ENV['PATH'].split(':').each do |dir_name|
|
|
114
|
+
return true if Dir.entries(dir_name).include?(ex_name)
|
|
115
|
+
end
|
|
116
|
+
return false
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# returns true if the executable ex_name is to be
|
|
120
|
+
# called for the dialog
|
|
121
|
+
def has?(ex_name)
|
|
122
|
+
@executables.include? ex_name
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
###### The following methods call a script, each, in an external process.
|
|
126
|
+
# There appears to be some Exception handling missing, but it does not
|
|
127
|
+
# hurt for the time being. Anyway, I do not care.
|
|
128
|
+
|
|
129
|
+
# creates a whiptail dialog in xterm.
|
|
130
|
+
def whiptail_dlg
|
|
131
|
+
debug('whiptail dialog')
|
|
132
|
+
tf = Tempfile.new
|
|
133
|
+
# dlg = @config.BINDIR << File::Separator << 'whiptail_dlg'
|
|
134
|
+
dlg = @@LIBDIR << File::Separator << 'whiptail_dlg'
|
|
135
|
+
dialog = XTERM.dup << ' -e ' << dlg << ' ' << tf.path
|
|
136
|
+
io = IO::popen(dialog)
|
|
137
|
+
Process.wait(io.pid )
|
|
138
|
+
nopts = tf.read
|
|
139
|
+
exit true if('exit' == nopts.strip)
|
|
140
|
+
tf.unlink
|
|
141
|
+
return nopts
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# creates a textual dialog in xterm.
|
|
145
|
+
def ruby_dlg
|
|
146
|
+
debug('xterm dialog')
|
|
147
|
+
tf = Tempfile.new
|
|
148
|
+
# dlg = @config.BINDIR << File::Separator << 'ruby_dlg'
|
|
149
|
+
dlg = @@LIBDIR << File::Separator << 'ruby_dlg'
|
|
150
|
+
begin
|
|
151
|
+
dialog = XTERM.dup << ' -e ' << dlg << ' ' << tf.path
|
|
152
|
+
debug('dialog will be ' << dialog)
|
|
153
|
+
rescue Exception => ex
|
|
154
|
+
error ex.message
|
|
155
|
+
wait_for_user
|
|
156
|
+
exit false
|
|
157
|
+
end
|
|
158
|
+
io = IO::popen(dialog)
|
|
159
|
+
debug('wait for ' << io.pid.to_s)
|
|
160
|
+
Process.wait(io.pid )
|
|
161
|
+
nopts = tf.read
|
|
162
|
+
exit true if('exit' == nopts.strip)
|
|
163
|
+
tf.unlink
|
|
164
|
+
return nopts
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# creates a Zenity dialog.
|
|
168
|
+
def zenity_dlg
|
|
169
|
+
debug('Zenity dialog')
|
|
170
|
+
# dialog = @config.BINDIR << File::Separator << 'zenity_dlg'
|
|
171
|
+
dialog = @@LIBDIR << File::Separator << 'zenity_dlg'
|
|
172
|
+
io = IO.popen(dialog)
|
|
173
|
+
Process::wait(io.pid)
|
|
174
|
+
rc = $?.exitstatus
|
|
175
|
+
|
|
176
|
+
exit true if rc != 0
|
|
177
|
+
|
|
178
|
+
nopts = io.read
|
|
179
|
+
return nopts
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# creates a YAD dialog.
|
|
183
|
+
def yad_dlg
|
|
184
|
+
debug('yad dialog')
|
|
185
|
+
# dialog = @config.BINDIR << File::Separator << 'yad_dlg'
|
|
186
|
+
dialog = @@LIBDIR << File::Separator << 'yad_dlg'
|
|
187
|
+
debug('dialog will be ' << dialog)
|
|
188
|
+
io = IO::popen(dialog)
|
|
189
|
+
Process::wait(io.pid)
|
|
190
|
+
exit true if $?.exitstatus != 0
|
|
191
|
+
|
|
192
|
+
nopts = io.read
|
|
193
|
+
return nopts
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# EOF
|
|
199
|
+
|
data/lib/ruby_dlg
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
=begin
|
|
4
|
+
/***************************************************************************
|
|
5
|
+
* This program is free software; you can redistribute it and/or modify *
|
|
6
|
+
* it under the terms of the WTFPL 2.0 or later, see *
|
|
7
|
+
* http://www.wtfpl.net/about/ *
|
|
8
|
+
* *
|
|
9
|
+
* This program is distributed in the hope that it will be useful, *
|
|
10
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
11
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
|
12
|
+
* *
|
|
13
|
+
***************************************************************************/
|
|
14
|
+
=end
|
|
15
|
+
|
|
16
|
+
require 'readline'
|
|
17
|
+
require_relative '../lib/color_output'
|
|
18
|
+
require 'io/wait'
|
|
19
|
+
require 'io/console'
|
|
20
|
+
|
|
21
|
+
def wait_for_user()
|
|
22
|
+
char = nil
|
|
23
|
+
# There is a difference which makes me prefer the below code from STDIN.raw(args)
|
|
24
|
+
# You can try
|
|
25
|
+
# char = STDIN.raw(&:getc)
|
|
26
|
+
# .., which does *not* work the same way and it won't for me.
|
|
27
|
+
|
|
28
|
+
STDIN.raw do
|
|
29
|
+
STDIN.noecho do
|
|
30
|
+
until (STDIN.ready?)
|
|
31
|
+
sleep(0.1)
|
|
32
|
+
end
|
|
33
|
+
char = (STDIN.read_nonblock(1).ord rescue nil)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
return char
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
ofl = nil
|
|
41
|
+
begin
|
|
42
|
+
ofl = File.open(ARGV[0], 'w+') if ARGV.length > 0
|
|
43
|
+
puts 'writing to ' << ARGV[0]
|
|
44
|
+
rescue Exception => ex
|
|
45
|
+
puts red ('cannot open ' << ARGV[1])
|
|
46
|
+
puts 'hit any key to exit'
|
|
47
|
+
wait_for_user
|
|
48
|
+
exit false
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
opt_array = []
|
|
54
|
+
message = ''
|
|
55
|
+
menu ||= %=
|
|
56
|
+
1 Unset Signature GROUP_SIGS
|
|
57
|
+
2 Unset Custom headers CUSTOM_HEADERS
|
|
58
|
+
3 Unset X-No-Archive XNAY_GROUPS
|
|
59
|
+
4 Do not correct URLs VFY_URLS
|
|
60
|
+
5 Disable log DEBUG_LOG
|
|
61
|
+
––––––––––––––––––––––––––––––––––––––––––––––
|
|
62
|
+
6 Summary
|
|
63
|
+
––––––––––––––––––––––––––––––––––––––––––––––
|
|
64
|
+
0 Okay, use settings.
|
|
65
|
+
––––––––––––––––––––––––––––––––––––––––––––––––
|
|
66
|
+
#{bold("Esc, Ctrl+C and 'q'")} terminate the Post-processor
|
|
67
|
+
and no changes will be applied.
|
|
68
|
+
=
|
|
69
|
+
|
|
70
|
+
loop do
|
|
71
|
+
system 'clear'
|
|
72
|
+
puts yellow(menu)
|
|
73
|
+
puts cyan(message)
|
|
74
|
+
option = wait_for_user - 48
|
|
75
|
+
case option
|
|
76
|
+
# Esc, Ctrl+C, 'q'
|
|
77
|
+
when -21, -45, 65
|
|
78
|
+
puts red('Aborting. Bye.')
|
|
79
|
+
ofl.write 'exit'
|
|
80
|
+
ofl.close
|
|
81
|
+
exit true
|
|
82
|
+
when 0
|
|
83
|
+
puts green('Applying changes.') if !opt_array.empty?
|
|
84
|
+
# write the list of variables to unset (others remain)
|
|
85
|
+
ofl.write opt_array.join(' ')
|
|
86
|
+
ofl.close
|
|
87
|
+
exit true
|
|
88
|
+
|
|
89
|
+
# toggle options
|
|
90
|
+
# ADD option to the option array, if it should be *removed*
|
|
91
|
+
# from the configuration, else remove it from the array.
|
|
92
|
+
when 1
|
|
93
|
+
active = !opt_array.include?(:GROUP_SIGS)
|
|
94
|
+
opt_array << :GROUP_SIGS if active
|
|
95
|
+
opt_array.delete(:GROUP_SIGS) if !active
|
|
96
|
+
|
|
97
|
+
message = "Signature #{active ? 'unset' : 'as configured'}!"
|
|
98
|
+
menu.sub!("Unset Signature", "Set Signature ") if active
|
|
99
|
+
menu.sub!("Set Signature ", "Unset Signature") if !active
|
|
100
|
+
when 2
|
|
101
|
+
active = !opt_array.include?(:CUSTOM_HEADERS)
|
|
102
|
+
opt_array << :CUSTOM_HEADERS if active
|
|
103
|
+
opt_array.delete(:CUSTOM_HEADERS) if !active
|
|
104
|
+
|
|
105
|
+
message = "Custom headers #{active ? 'removed' : 'are added'}!"
|
|
106
|
+
menu.sub!("Unset Custom headers", "Add Custom headers ") if active
|
|
107
|
+
menu.sub!("Add Custom headers ", "Unset Custom headers") if !active
|
|
108
|
+
when 3
|
|
109
|
+
active = !opt_array.include?(:XNAY_GROUPS)
|
|
110
|
+
opt_array << :XNAY_GROUPS if active
|
|
111
|
+
opt_array.delete(:XNAY_GROUPS) if !active
|
|
112
|
+
|
|
113
|
+
message = "X-No-Archive #{active ? 'removed' : 'is added'}!"
|
|
114
|
+
menu.sub!("Unset X-No-Archive", "Add X-No-Archive ") if active
|
|
115
|
+
menu.sub!("Add X-No-Archive ", "Unset X-No-Archive") if !active
|
|
116
|
+
when 4
|
|
117
|
+
active = !opt_array.include?(:VFY_URLS)
|
|
118
|
+
opt_array << :VFY_URLS if active
|
|
119
|
+
opt_array.delete(:VFY_URLS) if !active
|
|
120
|
+
|
|
121
|
+
message = "URLS will #{active ? 'not ' : ''}" << "be verified!"
|
|
122
|
+
menu.sub!("Do not correct URLs", "Correct URLs ") if active
|
|
123
|
+
menu.sub!("Correct URLs ", "Do not correct URLs") if !active
|
|
124
|
+
when 5
|
|
125
|
+
active = !opt_array.include?(:DEBUG_LOG)
|
|
126
|
+
opt_array << :DEBUG_LOG if active
|
|
127
|
+
opt_array.delete(:DEBUG_LOG) if !active
|
|
128
|
+
|
|
129
|
+
message = "Log is #{ active ? 'not ' : ''} " << "written!"
|
|
130
|
+
menu.sub!("Disable log", "Enable log ") if active
|
|
131
|
+
menu.sub!("Enable log ", "Disable log") if !active
|
|
132
|
+
when 6
|
|
133
|
+
message = "Summary of " << bold('disabled') << " options: " << opt_array.join(' ')
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|