maillinks 0.1.5 → 1.0

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.
@@ -7,7 +7,9 @@
7
7
 
8
8
  Synopsis
9
9
  ========
10
- maillinks [mail-file]
10
+ maillinks [mail-file]
11
+
12
+ maillinks [mail-file] <log level>
11
13
 
12
14
  or
13
15
 
@@ -26,6 +28,11 @@ directives which are likely to be addressed to a remotely running application.
26
28
  below the email-text. You can scrutinize the URL and find information about the
27
29
  destination, before you engage your web-browser or other tool to follow a link.
28
30
 
31
+ *MailLinks* displays the result, together with the original HTML-mail in the
32
+ first Web-Browser that can be executed. At the time of this writing, the
33
+ possible Browsers are: *Dillo, W3M, Lynx, Brave-Browser, Firefox*. If none of
34
+ these is found, the program aborts with an error message.
35
+
29
36
  Integration in mail-clients
30
37
  ----------------------------
31
38
 
@@ -46,8 +53,14 @@ macros or similar options can be configured.
46
53
 
47
54
  Options
48
55
  =========
49
- *Maillinks* does currently not interpret any command line arguments other than
50
- the name of a mail-file to analyze.
56
+ When called with a mail file as first argument, *Maillinks* can interpret
57
+ as second argument a log level, to control the verboseness of the program
58
+ output. The default is *info*, but you can have more detailed console output
59
+ with *debug*.
60
+
61
+ When used as a filter, reading from *STDIN*, **no additional arguments are
62
+ accepted**.
63
+
51
64
 
52
65
  Other Information
53
66
  ==================
@@ -61,14 +74,26 @@ Source-code and Development
61
74
  the data-archive with *tar -xzf*.
62
75
 
63
76
  Version
64
- 0.1.2 (May 2017)
77
+ 0.2.1 (April 2026)
78
+
79
+ .. _WTFPL: https://www.wtfpl.net/about/
65
80
 
66
81
  License
67
- *Maillinks* is published under the conditions of the GNU General Public
68
- License, version 3.0 or later.
82
+ *Maillinks* is published under the conditions of the WTFPL_, version 2.0.
69
83
 
70
84
  Author
71
85
  Michael Uplawski <michael.uplawski@uplawski.eu>
72
86
 
73
- Ω
87
+ This document
88
+ -------------
89
+ .. _CC By-ND 4.0: https://creativecommons.org/licenses/by-nd/4.0/
90
+ .. |date| date::
91
+
92
+ ©Michael Uplawski <michael.uplawski@uplawski.eu>
93
+
94
+ License: `CC BY-ND 4.0`_
95
+
96
+ Date: |date|
97
+
98
+ **Ω**
74
99
 
@@ -0,0 +1,249 @@
1
+ #!/bin/env ruby
2
+ #encoding: UTF-8
3
+ =begin
4
+ /***************************************************************************
5
+ * 2023-2026, Michael Uplawski <michael.uplawski@uplawski.eu> *
6
+ * This program is free software; you can redistribute it and/or modify *
7
+ * it under the terms of the WTFPL 2.0 or later, see *
8
+ * http://www.wtfpl.net/about/ *
9
+ * *
10
+ * This program is distributed in the hope that it will be useful, *
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
13
+ * *
14
+ ***************************************************************************/
15
+ =end
16
+
17
+ #
18
+ # Simplified logging.
19
+ # See example code at the bottom of this file.
20
+ # Execute this file to see the output.
21
+ module BasicLogging
22
+
23
+ DEBUG = 0
24
+ INFO = 1
25
+ WARN = 2
26
+ ERROR = 3
27
+ FATAL = 4
28
+ UNKNOWN = nil
29
+
30
+ # this is mainly for the translation of method calls into log levels
31
+ Levels = {:debug => DEBUG, :info => INFO, :warn => WARN, :error => ERROR,
32
+ :fatal => FATAL, :unknown => UNKNOWN}
33
+
34
+ @@log_level = UNKNOWN
35
+ @@target = STDOUT
36
+ @@muted = []
37
+
38
+ # do not log, if caller is obj (class or instance)
39
+ def self.mute(obj)
40
+ name = obj.class == Class ? obj.name.dup : obj.class.name
41
+ @@muted << name
42
+ end
43
+
44
+ def self.is_muted?(obj)
45
+ name = obj.class == Class ? obj.name.dup : obj.class.name
46
+ @@muted.include?(name)
47
+ end
48
+
49
+ # set the log level
50
+ def set_level(lv)
51
+ if lv.respond_to?(:to_str) && Levels.keys.include?(lv.strip.to_sym)
52
+ lv = Levels[lv.to_sym]
53
+ elsif lv.respond_to?(:to_sym) && Levels.keys.include?(lv)
54
+ lv = Levels[lv]
55
+ end
56
+
57
+ if(!lv || (lv.respond_to?(:to_int) && lv >= DEBUG && lv <= FATAL) )
58
+ @@log_level = lv
59
+ else
60
+ msg = calling_method << ": ERROR : invalid log level \"" << lv.to_s << "\""
61
+ msg << "\n" << "Keepinng old log level " << Levels.keys.detect {| k| Levels[k] == @@log_level}.to_s
62
+ STDERR.puts msg
63
+ puts msg
64
+ end
65
+ end
66
+
67
+ # set the log target
68
+ def set_target(tg)
69
+ if tg.respond_to?(:to_io)
70
+ @@target = tg
71
+ elsif(!File::exist?(tg) || ( File.file?(tg) && File.writable?(tg) ) )
72
+ @@target = File.open(tg, 'w+')
73
+ elsif !tg || tg.respond_to?(:to_str) && tg.strip.empty?
74
+ @@target = nil
75
+ else
76
+ STDERR.puts calling_method << ': ERROR : target ' << tg.to_str << ' cannot be set'
77
+ STDERR.puts "Keeping old target " << @@target.inspect
78
+ return
79
+ end
80
+ end
81
+
82
+ # Output of log messages, depending on the set log level and the name of the
83
+ # alias method which is actually called.
84
+ def log(message)
85
+ if !BasicLogging.is_muted?(self)
86
+ # how has this method been called?
87
+ mlevel = __callee__
88
+ if Levels.has_key?(mlevel) && Levels[mlevel] <= FATAL
89
+ # output only for levels equal or above the value that corresponds to
90
+ # the calling alias.
91
+ format_log( message, mlevel) if @@log_level && Levels[mlevel] >= @@log_level
92
+ else
93
+ STDERR.puts calling_method << ": ERROR : invalid log level \"" << mlevel.to_s << "\""
94
+ end
95
+ end
96
+ end
97
+
98
+ def target
99
+ @@target.path if @@target
100
+ end
101
+
102
+ def level
103
+ @@level.to_s if @@level
104
+ end
105
+
106
+ # Clear the log (-file)
107
+ def clear_log
108
+ if @@target && @@target.respond_to?(:truncate)
109
+ lock_target{ @@target.truncate(0) }
110
+ end
111
+ end
112
+
113
+ # find the name of the calling object's class or the file name in case of the
114
+ # top level object... or any dumb instance of Object
115
+ def log_name()
116
+ if !@log_name
117
+ clname = self.class.name
118
+ # limit analysis of the call stack to 'Object'.
119
+ if clname == 'Object'
120
+ @log_name = File::basename(caller.last.split(':')[0])
121
+ else
122
+ @log_name = self.class == Class ? self.name.dup << ' [class]' : clname
123
+ end
124
+ end
125
+ @log_name
126
+ end
127
+
128
+ alias :debug :log
129
+ alias :info :log
130
+ alias :warn :log
131
+ alias :error :log
132
+ alias :fatal :log
133
+
134
+ private
135
+
136
+ # Find the method that called, or 'main' in case of a top level Object.
137
+ # This needs a bunch of memory and slows down the process.
138
+ # Use of this method should be limited.
139
+ def calling_method()
140
+ # find instances other than the current module.
141
+ stack_item = caller.detect do |item|
142
+ item.split(':')[0] != __FILE__
143
+ end
144
+ if stack_item
145
+ if stack_item.include?('#')
146
+ m = stack_item.split(':').last.split("#")[1]
147
+ m.gsub!("'", '') if m && m.include?("'")
148
+ # looks cooler with a class name in front.
149
+ return '#' << m << '()'
150
+ else
151
+ # top level Object
152
+ return stack_item.split(':').last
153
+ end
154
+ else
155
+ # This is dumb but won't hurt a lot.
156
+ return 'from main'
157
+ end
158
+ end
159
+
160
+ # could be useful
161
+ def lock_target(&block)
162
+ begin
163
+ if @@target.respond_to?(:flock)
164
+ @@target.flock(File::LOCK_EX)
165
+ block.call
166
+ @@target.flock(File::LOCK_UN)
167
+ elsif @@target.respond_to?(:to_io)
168
+ block.call
169
+ end
170
+ rescue => ex
171
+ STDERR.puts calling_method << ": ERROR : cannot lock target (" << ex.message << ")"
172
+ end
173
+ end
174
+
175
+ # 1 format_log for all loggers.
176
+ def format_log(message, mlevel)
177
+ if @@target
178
+ location = log_name().dup << ' '
179
+ # Limit the memory-hungry analysis of the call stack
180
+ # This also takes about 2.5 times as long.
181
+ if mlevel != :info
182
+ location = log_name().dup << ' ' << calling_method << ' '
183
+ end
184
+ # indicate if a registered class or the registered object of a class is calling.
185
+ lock_target{@@target.puts '' << location << mlevel.to_s << ' ' << Time.now.strftime("%H:%M:%S:%6N") << ': ' << message.gsub("\n", "\n |")}
186
+ end
187
+ end
188
+ end # Module end
189
+
190
+
191
+
192
+ #---------test: execute file----------
193
+ if $0 == __FILE__
194
+ Array.extend(BasicLogging)
195
+ Array.set_level(BasicLogging::INFO)
196
+ Array.info('TEST')
197
+ ar = Array.new
198
+ ar.extend(BasicLogging)
199
+ # --- no output :
200
+ l = __LINE__
201
+ ar.debug(l.next.to_s << ': debug-test 0')
202
+ # output
203
+ ar.set_level(BasicLogging::DEBUG)
204
+ l = __LINE__
205
+ ar.debug(l.next.to_s << ': debug-test 1')
206
+
207
+ obj = Object.new
208
+ obj.extend(BasicLogging)
209
+ obj.set_level(BasicLogging::DEBUG)
210
+ puts "--------debug-----------"
211
+ obj.debug('debug')
212
+ obj.info('info')
213
+ obj.warn('warn')
214
+ obj.error('error')
215
+ obj.fatal('fatal')
216
+ puts "--------info-----------"
217
+ obj.set_level("info")
218
+ obj.debug('debug')
219
+ obj.info('info')
220
+ obj.warn('warn')
221
+ obj.error('error')
222
+ obj.fatal('fatal')
223
+ puts "--------fatal-----------"
224
+ obj.set_level("fatal")
225
+ obj.debug('debug')
226
+ obj.info('info')
227
+ obj.warn('warn')
228
+ obj.error('error')
229
+ obj.fatal('fatal')
230
+ puts "--------UNKNOWN-----------"
231
+ obj.set_level(nil)
232
+ obj.debug('debug')
233
+ obj.info('info')
234
+ obj.warn('warn')
235
+ obj.error('error')
236
+ obj.fatal('fatal')
237
+ # ---- into file ---
238
+ obj.set_target "/tmp/test_log.log"
239
+ puts "------ INFO into #{obj.target}-----------"
240
+ obj.set_level BasicLogging::INFO
241
+ obj.info('info output')
242
+
243
+ obj.info('info output 2')
244
+ puts "---------- invalid (fails) -------"
245
+ obj.set_target "/dev/sr0"
246
+ obj.set_level "power"
247
+ end
248
+
249
+ # EOF
@@ -0,0 +1,102 @@
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
+ # Functions to apply colors to terminal output.
17
+ # This is stolen from the Internet and I have lost track of my own additions
18
+ # and modifications.
19
+
20
+ COLORS = {:default => 9, :black => 0, :red => 1, :green => 2, :yellow => 3, :blue => 4, :purple => 5, :cyan => 6, :white => 7 }
21
+
22
+ BG = 4
23
+ FG = 3
24
+ REGULAR = 0
25
+ BOLD = 1
26
+ UNDERLINE = 4
27
+ BLINK = 5
28
+ SWAP = 7
29
+ NEUTRAL = 0
30
+
31
+ STYLES = {:regular => REGULAR, :bold => BOLD, :underline => UNDERLINE, :blink => BLINK, :swap => SWAP, :neutral => NEUTRAL}
32
+
33
+ # Colorizes the given text. Color-code is either an escape-sequence or one of
34
+ # the symbols representing color-names in the COLORS hash.
35
+ def colorize(text, color_code)
36
+ # ensure that colors are supported
37
+ if $stdout.tty? && ENV['TERM'] != 'dumb'
38
+ if (COLORS.keys.include?(color_code) )
39
+ "\033[3#{COLORS[color_code]}m#{text}\033[0m"
40
+ else
41
+ "#{color_code}#{text}\033[0m"
42
+ end
43
+ # if Terminal does not support colors
44
+ else
45
+ text
46
+ end
47
+ end
48
+
49
+ # rgb foreground
50
+ def colorize_RGB(text, r, g, b)
51
+ code = "%s;%s;%s" %[r, g, b]
52
+ "\033[38;2;#{code}m#{text}\033[0m"
53
+ end
54
+
55
+ # rgb background
56
+ def background_RGB(text, r, g, b)
57
+ code = "%s;%s;%s" %[r, g, b]
58
+ "\033[48;2;#{code}m#{text}\033[0m"
59
+ end
60
+
61
+ # duplicate code without much intelligence
62
+ def style(text, style_code)
63
+ "#{style_code}#{text}\033[0m"
64
+ end
65
+
66
+ # a function which allows to manipulate every known aspect of the ansi-output.
67
+ def colored_output(output_text, fg_color = :default, bg_color = :default, style = :regular , mode = :neutral )
68
+ if $stdout.tty? && ENV['TERM'] != 'dumb'
69
+ "\033[%i;%i;%i%i;%i%im%s\033[0m" %[STYLES[mode.to_sym], STYLES[style.to_sym], FG, COLORS[fg_color.to_sym], BG, COLORS[bg_color.to_sym], output_text]
70
+ else
71
+ # fallback for terminals that do not support colors.
72
+ output_text
73
+ end
74
+ end
75
+
76
+ # convenience functions
77
+ def black(text); colorize(text, "\033[30m"); end
78
+ def red(text); colorize(text, "\033[31m"); end
79
+ def green(text); colorize(text, "\033[32m"); end
80
+ def yellow(text); colorize(text, "\033[33m"); end
81
+ def purple(text); colorize(text, "\033[35m"); end
82
+ def cyan(text); colorize(text, "\033[36m"); end
83
+ def blue(text); colorize(text, "\033[34m"); end
84
+ def white(text); colorize(text, "\033[37m"); end
85
+
86
+ # RGB
87
+ # TODO: Fallbacks from the 256 color palette
88
+ def orange(text); colorize(text, "\033[38;2;255;165;0m"); end
89
+ def pink(text); colorize(text, "\033[38;2;255;0;165m"); end
90
+ def lightred(text); colorize(text, "\033[38;2;255;100;100m"); end
91
+ def lightgreen(text); colorize(text, "\033[38;2;100;255;100m"); end
92
+ def brown(text); colorize(text, "\033[38;2;153;76;0m"); end
93
+ def crimson(text); colorize(text, "\033[38;2;220;20;60m"); end
94
+
95
+ # quick contrast
96
+ def black_on_white(text); colorize(colorize(text, "\033[30m"), "\033[47m");end
97
+ def white_on_black(text); colorize(colorize(text, "\033[37m"), "\033[40m");end
98
+
99
+ # styles
100
+ def bold(text); style(text, "\033[01m");end
101
+ def underline(text); style(text, "\033[04m");end
102
+
data/lib/constants.rb CHANGED
@@ -1,22 +1,15 @@
1
1
  #encoding: UTF-8
2
2
  =begin
3
3
  /***************************************************************************
4
- * ©2015-2015 Michael Uplawski <michael.uplawski@uplawski.eu> *
5
- * *
4
+ * 2023-2026, Michael Uplawski <michael.uplawski@uplawski.eu> *
6
5
  * This program is free software; you can redistribute it and/or modify *
7
- * it under the terms of the GNU General Public License as published by *
8
- * the Free Software Foundation; either version 3 of the License, or *
9
- * (at your option) any later version. *
6
+ * it under the terms of the WTFPL 2.0 or later, see *
7
+ * http://www.wtfpl.net/about/ *
10
8
  * *
11
9
  * This program is distributed in the hope that it will be useful, *
12
10
  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
- * GNU General Public License for more details. *
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
15
12
  * *
16
- * You should have received a copy of the GNU General Public License *
17
- * along with this program; if not, write to the *
18
- * Free Software Foundation, Inc., *
19
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
20
13
  ***************************************************************************/
21
14
  =end
22
15
 
@@ -26,5 +19,7 @@ require 'tmpdir'
26
19
  # ignore the rules for HTML. Now they write HTML-mail.
27
20
  Block_Tags = %w~body div p hr table img~
28
21
 
29
- BROWSER = "/usr/bin/w3m"
22
+ # use the first one available
23
+ BROWSERS = ['dillo', 'w3m', 'lynx', 'brave-browser', 'firefox']
24
+
30
25
  OUT_FILE = "%s/mail_message.html" %Dir.tmpdir
data/lib/maillinks.rb CHANGED
@@ -1,86 +1,125 @@
1
1
  #encoding: UTF-8
2
2
  =begin
3
3
  /***************************************************************************
4
- * ©2015-2015 Michael Uplawski <michael.uplawski@uplawski.eu> *
5
- * *
4
+ * 2023-2026, Michael Uplawski <michael.uplawski@uplawski.eu> *
6
5
  * This program is free software; you can redistribute it and/or modify *
7
- * it under the terms of the GNU General Public License as published by *
8
- * the Free Software Foundation; either version 3 of the License, or *
9
- * (at your option) any later version. *
6
+ * it under the terms of the WTFPL 2.0 or later, see *
7
+ * http://www.wtfpl.net/about/ *
10
8
  * *
11
9
  * This program is distributed in the hope that it will be useful, *
12
10
  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
- * GNU General Public License for more details. *
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
15
12
  * *
16
- * You should have received a copy of the GNU General Public License *
17
- * along with this program; if not, write to the *
18
- * Free Software Foundation, Inc., *
19
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
20
13
  ***************************************************************************/
21
14
  =end
22
15
 
23
- require_relative 'file_checking'
24
- require_relative 'logging'
16
+ require_relative 'basic_logging'
25
17
  require_relative 'constants'
18
+ require_relative 'color_output'
26
19
  require 'mail'
27
20
  require 'nokogiri'
28
21
  require 'escape'
29
22
 
30
23
  # show me the urls.
31
24
  class MailLinks
32
- include Logging
25
+ include BasicLogging
33
26
  def initialize(mail = nil)
34
-
35
- init_logger(STDOUT)
36
- # a file may be piped in from the command-line...
37
- @log.debug('parameter is ' << (mail ? mail : ' N I L' ))
27
+ # a file may be piped in from the command-line...
28
+ debug('parameter is ' << (mail ? mail : ' N I L' ))
38
29
  if(mail && '-' != mail.strip)
39
- msg = File_Checking.file_check(mail, :exist, :file, :readable)
40
- if(msg)
41
- @log.error(msg)
42
- usage
43
- exit false
44
- else
45
- @log.debug('will work on mail-file ' << mail)
46
- @mail = mail
47
-
48
- File::open(OUT_FILE, 'w+') {|of| of << File::read(@mail) }
30
+ [:exist?, :file?, :readable?].each do |cond|
31
+ if !File.send(cond, mail)
32
+ error(yellow("#{mail}: not #{cond.split('?')[0]}. Aborting!") )
33
+ usage
34
+ exit false
35
+ end
49
36
  end
37
+ debug('will work on mail-file ' << mail)
38
+ @mail = mail
39
+
40
+ File::open(OUT_FILE, 'w+') {|of| of << File::read(@mail) }
50
41
  elsif(!$<.eof?)
51
- @log.debug('Reading data from STDIN. Hit Ctrl+D to interrupt')
42
+ info('Reading data from STDIN. Hit Ctrl+D to interrupt')
52
43
  input = $<.read
53
- @log.debug('input length is ' << input.length.to_s)
44
+ debug('input length is ' << input.length.to_s)
54
45
  if(input.length < 10)
55
- @log.error('insufficient input data')
56
- @log.error('No mail text provided')
46
+ error(yellow('insufficient input data'))
47
+ error(yellow('No mail text provided'))
57
48
  usage()
58
49
  exit false
59
50
  end
60
51
  # ... provide a temporary file in that case,
61
- # @mail = OUT_FILE
62
52
  File.open(OUT_FILE, 'w+') {|of| of << input}
63
53
  @mail = OUT_FILE.dup
64
- @log.debug('Temporary eml-file is written.')
54
+ debug('Temporary eml-file is written.')
65
55
  end
66
56
 
67
57
  procede
68
58
  end
69
59
 
70
60
  private
61
+
62
+ def browser()
63
+ path_dirs = ENV['PATH'].split(':')
64
+ BROWSERS.detect do |b|
65
+ debug 'trying to find browser: ' << b.to_s
66
+ # array of the directories in $PATH
67
+
68
+ path_dirs.each do |dir_name|
69
+ debug('looking in ' << dir_name)
70
+ return [b] if Dir.entries(dir_name).include?(b)
71
+ end
72
+ end
73
+ # Look for yad, when everything else has failed.
74
+ path_dirs.each do |dir_name|
75
+ if Dir.entries(dir_name).include?('yad')
76
+ return ['yad', '--browser', '--html', '--width=1000', '--height=800', '--uri=']
77
+ end
78
+ end
79
+ error 'Cannot find any of the given browsers: ' << BROWSERS.join(', ') << ', yad'
80
+ return nil
81
+ end
82
+
71
83
  def procede
72
84
  handle_mail
73
85
  show_mail
74
86
  end
75
87
  def usage
76
- msg = 'Usage: ' << $0 << ' ' << '<mail-file>'
88
+ msg = "\nUsage: " << $0 << ' ' << '<mail-file>'
77
89
  msg << "\n or: " << 'cat <mail-file> |' << $0
90
+ msg << "\nYou can name a log level as second parameter:\n"
91
+ msg << " " << $0 << ' ' << '<mail-file>' << ' ' << 'debug'
92
+ msg << "\nThis will create more verbose program output.\n"
78
93
  puts msg
79
94
  end
80
95
 
81
96
  def show_mail
82
- cmd = Escape.shell_command([BROWSER, OUT_FILE])
83
- system(cmd)
97
+ # prog is an array of 1 or more elements.
98
+ prog = browser()
99
+ debug 'browser is ' << (prog ? prog.to_s : ' N I L ')
100
+ if prog
101
+ uri_arg = OUT_FILE
102
+ if prog.length > 1
103
+ # concatenate out_file to the uri-parameter
104
+ uri_arg = prog.pop + OUT_FILE
105
+ end
106
+ # attach the uri_parameter, escape.
107
+ cmd = Escape.shell_command(prog.dup.push uri_arg)
108
+ debug 'command is ' << cmd
109
+ info cyan('<----------- Output from ' << prog[0] << '---------->')
110
+ begin
111
+ pid = Process.spawn(cmd)
112
+ Process.wait
113
+ info cyan('-----------> ' << prog[0] << ' END <----------')
114
+ debug 'removing temporary file ' << OUT_FILE
115
+ File.unlink(OUT_FILE)
116
+ rescue Exception => ex
117
+ error __LINE__.dup << ' ' << ex.message
118
+ end
119
+ else
120
+ fatal yellow('Cannot open browser!' + bold(' ABORTING.') )
121
+ exit false
122
+ end
84
123
  end
85
124
 
86
125
  def handle_mail
@@ -89,8 +128,8 @@ class MailLinks
89
128
  mail_body = mail_content.split("</head>")[1].split("</html>")[0]
90
129
  mail_body = Mail::Encodings::QuotedPrintable.decode(mail_body)
91
130
  rescue Exception => ex
92
- @log.error('Cannot find the html-body in this mail. Maybe it is not a HTML-mail?')
93
- @log.debug(ex.message)
131
+ error('Cannot find the html-body in this mail. Maybe it is not a HTML-mail?')
132
+ debug(ex.message)
94
133
  end
95
134
  if !mail_body
96
135
  mail_body = mail_content
@@ -100,7 +139,7 @@ class MailLinks
100
139
 
101
140
  a_nodes = html_mail.xpath(".//a")
102
141
  if(! a_nodes || a_nodes.empty? )
103
- @log.info('no links in this mail')
142
+ info(green('no links in this mail') )
104
143
  exit true
105
144
  end
106
145
  begin
@@ -114,30 +153,30 @@ class MailLinks
114
153
  body.add_child("<hr/>")
115
154
  body.add_child("<h2>HTML-links in this mail</h2>")[0]
116
155
  if(!body)
117
- @log.error('cannot find a body-tag in this mail')
156
+ error('cannot find a body-tag in this mail')
118
157
  exit false
119
158
  end
120
159
  dl = body.add_child("<dl id='links'></dl>")[0]
121
160
  if(!dl)
122
- @log.error('cannot add a list-tag')
161
+ error('cannot add a list-tag')
123
162
  exit false
124
163
  end
125
164
  links_hash = Hash.new
126
165
  a_nodes.each_with_index do |a, i|
127
- @log.debug('a is ' << a.to_s.gsub("=\" ", ''))
166
+ debug('a is ' << a.to_s.gsub("=\" ", ''))
128
167
  caption = a.inner_text.to_s.strip
129
168
  href = a.attribute('href')
130
169
  if(href)
131
- @log.debug('href is: ' << href.to_s)
170
+ debug('href is: ' << href.to_s)
132
171
  link = href.content
133
- @log.debug('link is ex href.content: ' << link.to_s)
172
+ debug('link is ex href.content: ' << link.to_s)
134
173
  a.add_next_sibling("<span>[" << (i.next).to_s << "]</span>")
135
174
  dl.add_child("<dt>%i) %s</dt>"%[i.next, caption])
136
- dl.add_child("<dd style='white-space:nowrap;'><a href='%s'>%s</a></dd>"%[link,link])
175
+ dl.add_child("<dd style='white-space:nowrap;'><a style='white-space:nowrap;' href='%s'>%s</a></dd>"%[link,link])
137
176
  end
138
177
  end
139
178
  rescue Exception => ex
140
- @log.error("cannot handle the HTML in this mail: " << ex.message)
179
+ error(yellow("cannot handle the HTML in this mail: ") << bold(ex.message) )
141
180
  exit false
142
181
  end
143
182