watobo 0.9.16 → 0.9.17

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md CHANGED
@@ -1,8 +1,35 @@
1
+ Version 0.9.17
2
+ ===
3
+ News
4
+ ---
5
+
6
+ **General**
7
+
8
+ * changed parameter parsing for better handling
9
+ * Boolean-SQL check now also takes xml parameters for testing
10
+ * new appearance of CA certificates
11
+
12
+ **Manual Request Editor**
13
+
14
+ * XML parser, xml-request parameters available in table
15
+
16
+ Fixes
17
+ ---
18
+ **General**
19
+
20
+ * request line removed on `remove_header` regex match
21
+ * double insert of Content-Length header
22
+ * bad markdown format of CHANGELOG
23
+ * wrong parameter parsing if value contains '=' sign
24
+ * new custom response viewer; now you can code your own handler, e.g. `lambda{ |response| return response.content_type }`
25
+ * added table view on request viewer
26
+
1
27
  Version 0.9.16
2
28
  ===
3
29
  Fixes
4
30
  ---
5
31
  **General**
32
+
6
33
  * double insert of Content-Length header
7
34
  * bad markdown format of CHANGELOG
8
35
 
@@ -11,6 +38,7 @@ Version 0.9.15
11
38
  Fixes
12
39
  ---
13
40
  **General**
41
+
14
42
  * improved socket handling
15
43
  * fixed some UTF-8 issues in passive modules
16
44
  * added application/octet-stream to pass-through content-types
@@ -18,12 +46,15 @@ Fixes
18
46
  * setting/replacing http-headers is now case-in-sensitive
19
47
 
20
48
  **Passive Modules**
49
+
21
50
  * fixed `Disclosure_ipaddr`; now all IPs inside body are reported
22
51
 
23
52
  **Active Modules**
53
+
24
54
  * Domino DB enumeration will now run on all requests
25
55
 
26
56
  **Crawler Plugin**
57
+
27
58
  * extended allowed/excluded URL checks on full url path /w query
28
59
 
29
60
  News
data/lib/watobo.rb CHANGED
@@ -47,16 +47,14 @@ require 'watobo/utils'
47
47
  require 'watobo/mixins'
48
48
  require 'watobo/config'
49
49
  require 'watobo/defaults'
50
+ require 'watobo/http'
50
51
  require 'watobo/core'
51
52
  require 'watobo/externals'
52
53
  require 'watobo/adapters'
53
54
  require 'watobo/framework'
54
- require 'watobo/http/data/data'
55
- require 'watobo/http/url/url'
56
- require 'watobo/http/cookies/cookies'
57
55
  require 'watobo/parser'
58
56
  require 'watobo/interceptor'
59
- require 'watobo/http_socket'
57
+ require 'watobo/sockets'
60
58
 
61
59
  # WORKAROUND FOR LINUX :(
62
60
  dont_know_why_REQUIRE_hangs = Mechanize.new
@@ -64,7 +62,7 @@ dont_know_why_REQUIRE_hangs = Mechanize.new
64
62
  # @private
65
63
  module Watobo#:nodoc: all #:nodoc: all
66
64
 
67
- VERSION = "0.9.16"
65
+ VERSION = "0.9.17"
68
66
 
69
67
  def self.base_directory
70
68
  @base_directory ||= ""
@@ -27,6 +27,20 @@ module Watobo#:nodoc: all
27
27
  @hostname = %x('hostname').strip
28
28
  @hostname = "watobo" if @hostname.empty?
29
29
  @domain = "#{@hostname}.watobo.local"
30
+
31
+ def self.dh_key
32
+ dh_filename = File.join(@ca_config[:CA_dir], "watobo_dh.key")
33
+ unless File.exist? dh_filename
34
+ #puts "* no dh key file found"
35
+ File.open(dh_filename,"w") do |fh|
36
+ print "* creating SSL key (DH 1024) ... "
37
+ fh.write OpenSSL::PKey::DH.new(1024).to_pem
38
+ print " DONE\r\n"
39
+ end
40
+ end
41
+ OpenSSL::PKey::DH.new(File.read(dh_filename))
42
+ end
43
+
30
44
  def self.ca_ready?
31
45
  return false unless File.exists? @ca_config[:CA_dir]
32
46
  return false unless File.exists? @ca_config[:private_dir]
@@ -63,8 +77,10 @@ module Watobo#:nodoc: all
63
77
  :crl_days => 14,
64
78
  :name => [
65
79
  ['C', 'DE', OpenSSL::ASN1::PRINTABLESTRING],
66
- ['O', @domain, OpenSSL::ASN1::UTF8STRING],
67
- ['OU', @hostname, OpenSSL::ASN1::UTF8STRING],
80
+ #['O', @domain, OpenSSL::ASN1::UTF8STRING],
81
+ ['O', "WATOBO", OpenSSL::ASN1::UTF8STRING],
82
+ # ['OU', @hostname, OpenSSL::ASN1::UTF8STRING],
83
+ ['OU', "WATOBO CA", OpenSSL::ASN1::UTF8STRING]
68
84
  ]
69
85
  }
70
86
 
@@ -85,10 +101,10 @@ module Watobo#:nodoc: all
85
101
  #print "Create Certificate ..."
86
102
  cert = OpenSSL::X509::Certificate.new
87
103
  #puts "done!"
88
- name = @ca_config[:name].dup << ['CN', 'CA']
104
+ name = @ca_config[:name].dup << ['CN', 'Watobo']
89
105
 
90
106
  cert.subject = cert.issuer = OpenSSL::X509::Name.new(name)
91
- cert.not_before = Time.now
107
+ cert.not_before = Time.now - 24 * 60 * 60
92
108
  cert.not_after = Time.now + @ca_config[:ca_cert_days] * 24 * 60 * 60
93
109
  cert.public_key = keypair.public_key
94
110
  cert.serial = 0x0
@@ -130,6 +146,8 @@ module Watobo#:nodoc: all
130
146
  end
131
147
 
132
148
  puts "Done generating certificate for #{cert.subject}"
149
+ puts ">> create DH key ..."
150
+ dh_key
133
151
  else
134
152
  #puts "Open Cert File ..."
135
153
  raw = File.read @ca_config[:cert_file] # DER- or PEM-encoded
@@ -326,7 +344,7 @@ module Watobo#:nodoc: all
326
344
  ex << ef.create_extension("authorityInfoAccess",
327
345
  "OCSP;" << @ca_config[:ocsp_location])
328
346
  end
329
- cert.extensions = ex
347
+ # cert.extensions = ex
330
348
  cert.sign ca_keypair, OpenSSL::Digest::SHA1.new
331
349
 
332
350
  # backup_cert_file = @ca_config[:backup_certs_dir] + "/cert_#{cert.serial}.pem"
@@ -360,8 +378,9 @@ module Watobo#:nodoc: all
360
378
  name = @ca_config[:name].dup
361
379
  case cert_config[:type]
362
380
  when 'server' then
363
- name << ['OU', 'CA']
364
- name << ['CN', cert_config[:hostname]]
381
+ # name << ['OU', 'Watobo CA']
382
+ name << ['CN', cert_config[:hostname]]
383
+ #name << ['CN', "WATOBO"]
365
384
  when 'client' then
366
385
  name << ['CN', cert_config[:user]]
367
386
  name << ['emailAddress', cert_config[:email]]
@@ -396,17 +415,6 @@ module Watobo#:nodoc: all
396
415
  return csr_file
397
416
  end
398
417
 
399
- def self.dh_key
400
- dh_filename = File.join(@ca_config[:CA_dir], "watobo_dh.key")
401
- unless File.exist? dh_filename
402
- #puts "* no dh key file found"
403
- File.open(dh_filename,"w") do |fh|
404
- puts "* creating SSL key (DH 1024) ... "
405
- fh.write OpenSSL::PKey::DH.new(1024).to_pem
406
- print " DONE\r\n"
407
- end
408
- end
409
- OpenSSL::PKey::DH.new(File.read(dh_filename))
410
- end
418
+
411
419
  end
412
420
  end
@@ -30,15 +30,16 @@ module Watobo#:nodoc: all
30
30
  attr :path
31
31
  attr :secure
32
32
  attr :http_only
33
- def name_value
33
+
34
+ def to_s
34
35
  "#{@name}=#{@value}"
35
- end
36
+ end
36
37
 
37
- def initialize(cookie_prefs)
38
+ def initialize(prefs)
38
39
  @secure = false
39
40
  @http_only = false
40
41
 
41
- if cookie_prefs.respond_to? :has_key?
42
+ if prefs.respond_to? :has_key?
42
43
  @secure = prefs.has_key?(:secure) ? prefs[:secure] : false
43
44
  @http_only = prefs.has_key?(:http_only) ? prefs[:http_only] : false
44
45
  @location = :cookie
@@ -46,11 +47,14 @@ module Watobo#:nodoc: all
46
47
  @name = prefs[:name]
47
48
  @value = prefs[:value]
48
49
  else
49
- chunks = cookie_prefs.split(";")
50
+ puts "= NEW COOKIE ="
51
+ puts prefs
52
+ puts prefs.class
53
+ chunks = prefs.split(";")
50
54
  # first chunk
51
55
  @name, @value = chunks.first.split(":").last.split("=")
52
56
 
53
- m = cookie_prefs.match(/path=([^;]*)/)
57
+ m = prefs.match(/path=([^;]*)/)
54
58
  @path = m.nil? ? "" : m[1].strip
55
59
  @secure = true if chunks.select{|c| c =~ /Secure/i }
56
60
  @http_only = true if chunks.select{|c| c =~ /HttpOnly/i }
@@ -38,7 +38,8 @@ module Watobo#:nodoc: all
38
38
  def initialize(prefs)
39
39
  @location = nil
40
40
  @name = prefs[:name]
41
- @value = prefs[:value]
41
+ @value = prefs[:value]
42
+ @prefs = prefs
42
43
  end
43
44
  end
44
45
 
@@ -63,4 +64,15 @@ module Watobo#:nodoc: all
63
64
  @location = :cookie
64
65
  end
65
66
  end
67
+
68
+ class XmlParameter < Parameter
69
+ attr :parent
70
+ attr :namespace
71
+ def initialize(prefs)
72
+ super prefs
73
+ @location = :xml
74
+ @parent = prefs.has_key?(:parent) ? prefs[:parent] : ""
75
+ @namespace = prefs.has_key?(:namespace) ? prefs[:namespace] : nil
76
+ end
77
+ end
66
78
  end
@@ -40,7 +40,10 @@ module Watobo#:nodoc: all
40
40
  attr :data
41
41
  attr :url
42
42
  attr :header
43
- attr :cookies
43
+ # attr :cookies
44
+
45
+ include Watobo::HTTP::Cookies::Mixin
46
+ include Watobo::HTTP::Xml::Mixin
44
47
 
45
48
  def self.create request
46
49
  request.extend Watobo::Mixin::Parser::Url
@@ -79,10 +82,23 @@ module Watobo#:nodoc: all
79
82
  end
80
83
  end
81
84
 
82
- def parameters(*locations)
85
+ def parameters(*locations, &block)
86
+ param_locations = [ :url, :data, :wwwform, :xml, :cookies ]
87
+ unless locations.empty?
88
+ param_locations.select!{ |loc| locations.include? loc }
89
+ end
90
+
83
91
  parms = []
84
- parms.concat @data.parameters
85
- parms.concat @url.parameters
92
+ parms.concat @url.parameters if param_locations.include?(:url)
93
+ parms.concat cookies.parameters if param_locations.include?(:cookies)
94
+ parms.concat @data.parameters if self.is_wwwform? and ( param_locations.include?(:data) or param_locations.include?(:wwwform) )
95
+
96
+ parms.concat xml.parameters if self.is_xml? and param_locations.include?(:xml)
97
+ if block_given?
98
+ parms.each do |p|
99
+ yield p
100
+ end
101
+ end
86
102
  parms
87
103
  end
88
104
 
@@ -94,6 +110,10 @@ module Watobo#:nodoc: all
94
110
  @data.set parm
95
111
  when :url
96
112
  @url.set parm
113
+ when :xml
114
+ xml.set parm
115
+ when :cookie
116
+ cookies.set parm
97
117
  end
98
118
  true
99
119
  end
@@ -358,6 +358,10 @@ module Watobo#:nodoc: all
358
358
  tab_frame = FXVerticalFrame.new(@tabBook, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_RAISED)
359
359
  @hexViewer = HexViewer.new(tab_frame)
360
360
  @viewers.push @hexViewer
361
+
362
+ FXTabItem.new(@tabBook, "Table", nil)
363
+ tab_frame = FXVerticalFrame.new(@tabBook, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_RAISED)
364
+ @viewers << Watobo::Gui::TableEditorFrame.new(tab_frame, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_SUNKEN|FRAME_THICK, :padding => 0)
361
365
  end
362
366
 
363
367
  end
@@ -442,10 +446,13 @@ module Watobo#:nodoc: all
442
446
  @hexViewer = HexViewer.new(tab_frame)
443
447
  @viewers << @hexViewer
444
448
 
445
- FXTabItem.new(@tabBook, "HTML", nil)
446
-
449
+ FXTabItem.new(@tabBook, "HTML", nil)
447
450
  @html_viewer = HTMLViewerFrame.new(@tabBook, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_RAISED)
448
451
  @viewers << @html_viewer
452
+
453
+ FXTabItem.new(@tabBook, "Custom", nil)
454
+ @viewers << CustomViewer.new(@tabBook, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_RAISED)
455
+
449
456
  end
450
457
 
451
458
  end
@@ -303,8 +303,23 @@ module Watobo#:nodoc: all
303
303
  update_text
304
304
  # l = FXLabel.new(@filter_info, "Test")
305
305
 
306
- @table_option_autoscroll = FXCheckButton.new(f, "autoscroll", nil, 0, ICON_BEFORE_TEXT|LAYOUT_SIDE_LEFT)
306
+ bframe = FXVerticalFrame.new(f, :opts => LAYOUT_FILL_Y, :padding => 0)
307
+ @table_option_autoscroll = FXCheckButton.new(bframe, "autoscroll", nil, 0, ICON_BEFORE_TEXT|LAYOUT_SIDE_LEFT)
307
308
  @table_option_autoscroll.setCheck(true)
309
+
310
+ iframe = FXHorizontalFrame.new(bframe, :opts => LAYOUT_FILL_X, :padding => 0 )
311
+
312
+ FXButton.new(iframe, "", ICON_BTN_DOWN, nil, 0, FRAME_RAISED|FRAME_THICK|LAYOUT_RIGHT).connect(SEL_COMMAND) {
313
+ @table.scrollDown() unless @table.nil?
314
+ }
315
+
316
+ FXButton.new(iframe, "", ICON_BTN_UP, nil, 0, FRAME_RAISED|FRAME_THICK|LAYOUT_RIGHT).connect(SEL_COMMAND) {
317
+ @table.scrollUp() unless @table.nil?
318
+ }
319
+
320
+
321
+
322
+
308
323
 
309
324
 
310
325
 
@@ -0,0 +1,368 @@
1
+ # .
2
+ # custom_viewer.rb
3
+ #
4
+ # Copyright 2013 by siberas, http://www.siberas.de
5
+ #
6
+ # This file is part of WATOBO (Web Application Tool Box)
7
+ # http://watobo.sourceforge.com
8
+ #
9
+ # WATOBO is free software; you can redistribute it and/or modify
10
+ # it under the terms of the GNU General Public License as published by
11
+ # the Free Software Foundation version 2 of the License.
12
+ #
13
+ # WATOBO is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # GNU General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU General Public License
19
+ # along with WATOBO; if not, write to the Free Software
20
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21
+ # .
22
+ # @private
23
+ module Watobo#:nodoc: all
24
+ module Gui
25
+
26
+
27
+ class CustomViewer < FXVerticalFrame
28
+ SEL_TYPE_GREP = 0
29
+ SEL_TYPE_HIGHLIGHT = 1
30
+ attr_accessor :max_len
31
+ def style=(new_style)
32
+ @simple_text_view.style = new_style
33
+ end
34
+
35
+ def editable=(value)
36
+ @simple_text_view.editable = value
37
+ end
38
+
39
+ def setText(text, prefs={})
40
+
41
+ normalized_text = text
42
+ if text.is_a? Watobo::Request or text.is_a? Watobo::Response
43
+ return false unless @handler.respond_to? :call
44
+ result = call_handler(text)
45
+ normalized_text = result
46
+ else
47
+ return false
48
+ end
49
+
50
+ @text = normalized_text
51
+ #@text = text
52
+ @simple_text_view.max_len = -1
53
+ @simple_text_view.setText(normalized_text, prefs)
54
+ @match_pos_label.text = "0/0"
55
+ @match_pos_label.textColor = 'grey'
56
+
57
+ applyFilter() if @auto_apply_cbtn.checked?
58
+ end
59
+
60
+ def highlight(pattern)
61
+ highlightPattern(pattern)
62
+ end
63
+
64
+ def setFont(font_type=nil, size=nil)
65
+ @simple_text_view.setFont(font_type, size)
66
+ end
67
+
68
+ def getText
69
+ @simple_text_view.textbox.to_s
70
+ end
71
+
72
+ def initialize(owner, opts)
73
+ super(owner, opts)
74
+
75
+ @text_matches = []
76
+
77
+ @style = 2 # default style
78
+ @text = ''
79
+ @max_len = 5000
80
+ @filter_mode = SEL_TYPE_HIGHLIGHT
81
+ @cur_match_pos = 0
82
+ @text_dt = FXDataTarget.new('')
83
+ @filter_dt = FXDataTarget.new('')
84
+
85
+ @handler = nil
86
+ @handler_file = nil
87
+ @handler_path = nil
88
+
89
+ handler_ctrl_frame = FXHorizontalFrame.new(self, :opts => LAYOUT_FILL_X, :padding => 0)
90
+ @handler_status_lbl = FXLabel.new(handler_ctrl_frame, "No handler!")
91
+ @handler_status_lbl.textColor = "red"
92
+ add_handler_btn = FXButton.new(handler_ctrl_frame, "add", nil, nil, 0, FRAME_RAISED|LAYOUT_FILL_Y|LAYOUT_RIGHT)
93
+ add_handler_btn.connect(SEL_COMMAND){ add_handler }
94
+ reload_handler_btn = FXButton.new(handler_ctrl_frame, "reload", nil, nil, 0, FRAME_RAISED|LAYOUT_FILL_Y|LAYOUT_RIGHT)
95
+ reload_handler_btn.connect(SEL_COMMAND){ load_handler(@handler_file) }
96
+ reset_handler_btn = FXButton.new(handler_ctrl_frame, "reset", nil, nil, 0, FRAME_RAISED|LAYOUT_FILL_Y|LAYOUT_RIGHT)
97
+ reset_handler_btn.connect(SEL_COMMAND){
98
+ @handler = nil
99
+ @handler_file = nil
100
+ @handler_status_lbl = FXLabel.new(handler_ctrl_frame, "No handler!")
101
+ @handler_status_lbl.textColor = "red"
102
+ }
103
+
104
+ text_view_header = FXHorizontalFrame.new(self, :opts => LAYOUT_FILL_X|LAYOUT_SIDE_BOTTOM|LAYOUT_FIX_HEIGHT,:height => 24, :padding => 0)
105
+
106
+ #@auto_apply_cbtn.connect(SEL_COMMAND, method(:onInterceptChanged))
107
+
108
+ pmatch_btn = FXButton.new(text_view_header, "<", nil, nil, 0, FRAME_RAISED|LAYOUT_FILL_Y)
109
+ @match_pos_label = FXLabel.new(text_view_header, "0/0", :opts => LAYOUT_FILL_Y)
110
+ @match_pos_label.textColor = 'grey'
111
+ pmatch_btn.connect(SEL_COMMAND) { gotoPrevMatch() }
112
+ nmatch_btn = FXButton.new(text_view_header, ">", nil, nil, 0, FRAME_RAISED|LAYOUT_FILL_Y)
113
+ nmatch_btn.connect(SEL_COMMAND) { gotoNextMatch() }
114
+
115
+ # @filter_text = FXTextField.new(text_view_header, 10,
116
+ # :target => @filter_dt, :selector => FXDataTarget::ID_VALUE,
117
+ # :opts => FRAME_SUNKEN|FRAME_THICK|LAYOUT_FILL_X|LAYOUT_FILL_Y)
118
+
119
+ @filter_text = FXComboBox.new(text_view_header, 20, @filter_dt, 0, FRAME_SUNKEN|FRAME_THICK|LAYOUT_SIDE_TOP|LAYOUT_FILL_X)
120
+ @filter_text.connect(SEL_COMMAND){
121
+ applyFilter()
122
+ addFilterHistory()
123
+ }
124
+
125
+ @filter_text.connect(SEL_CHANGED) {
126
+ applyFilter()
127
+ }
128
+
129
+ menu = FXMenuPane.new(self)
130
+ FXMenuCommand.new(menu, "&Highlight").connect(SEL_COMMAND){
131
+ @filter_mode = SEL_TYPE_HIGHLIGHT
132
+ applyFilter()
133
+ @mode_btn.text = "Highlight"
134
+ }#, method(:switchMethod))
135
+ FXMenuCommand.new(menu, "&Grep").connect(SEL_COMMAND){
136
+ @filter_mode = SEL_TYPE_GREP
137
+ applyFilter()
138
+ @mode_btn.text = "Grep"
139
+ }#, method(:switchMethod))
140
+
141
+ @auto_apply_cbtn = FXCheckButton.new(text_view_header, "auto-apply", nil, 0, ICON_BEFORE_TEXT|LAYOUT_SIDE_TOP|LAYOUT_RIGHT|LAYOUT_FILL_Y)
142
+ @mode_btn = FXMenuButton.new(text_view_header, "Highlight", nil, menu,
143
+ :opts=> MENUBUTTON_DOWN|FRAME_RAISED|FRAME_THICK|ICON_AFTER_TEXT|LAYOUT_RIGHT|LAYOUT_FILL_Y)
144
+
145
+ reset_button = FXButton.new(text_view_header, "&Reset", nil, nil, 0, FRAME_RAISED|FRAME_THICK|LAYOUT_FILL_Y)
146
+ reset_button.connect(SEL_COMMAND){ resetFilter() }
147
+
148
+ text_box_frame = FXVerticalFrame.new(self, LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_SUNKEN|FRAME_THICK, :padding => 0)
149
+
150
+ @simple_text_view = SimpleTextView.new(text_box_frame, :opts => LAYOUT_FILL_X|LAYOUT_FILL_Y,:padding => 0)
151
+ @simple_text_view.style = 1
152
+ @simple_text_view.editable = false
153
+ @simple_text_view.textStyle -= TEXT_WORDWRAP
154
+
155
+ addHotkeyHandler(@simple_text_view.textbox)
156
+ addHotkeyHandler(@filter_text)
157
+
158
+ @filter_dt.connect(SEL_COMMAND) { applyFilter() }
159
+
160
+ end
161
+
162
+ def applyFilter
163
+ pattern = @filter_text.text
164
+ @match_pos_label.text = "0/0"
165
+ @simple_text_view.resetMatches()
166
+ @simple_text_view.setText(@text)
167
+ @match_pos_label.textColor = 'grey'
168
+ return true if pattern == ''
169
+ case @filter_mode
170
+ when SEL_TYPE_GREP
171
+ grepPattern(pattern)
172
+ when SEL_TYPE_HIGHLIGHT
173
+ highlightPattern(pattern)
174
+ end
175
+ end
176
+
177
+ private
178
+
179
+ def add_handler
180
+
181
+ handler_filename = FXFileDialog.getOpenFilename(self, "Select handler file", @handler_path, "*.rb\n*")
182
+ if handler_filename != "" then
183
+ if File.exists?(handler_filename) then
184
+ @handler_file = handler_filename
185
+ @handler_path = File.dirname(handler_filename) + "/"
186
+ load_handler(handler_filename)
187
+ end
188
+ end
189
+
190
+ end
191
+
192
+ def load_handler(file)
193
+ @handler = nil
194
+ return false if file.nil?
195
+ return false unless File.exist? file
196
+ begin
197
+ source = File.read(file)
198
+ #puts source
199
+ result = eval(source)
200
+ if result.respond_to? :call
201
+ @handler = result
202
+ @handler_status_lbl.text = "Handler ready!"
203
+ @handler_status_lbl.textColor = "green"
204
+ end
205
+ return true
206
+
207
+ rescue SyntaxError, LocalJumpError, NameError => e
208
+ out = e.to_s
209
+ out << e.backtrace.join("\n")
210
+ rescue => bang
211
+ out = bang
212
+ out << bang.backtrace.join("\n")
213
+ end
214
+ puts out
215
+ return false
216
+ end
217
+
218
+ def call_handler(object)
219
+ begin
220
+ result = @handler.call(object)
221
+ return result
222
+ rescue => bang
223
+ result = bang.to_s
224
+ result << bang.backtrace.join("\n")
225
+ return result
226
+ end
227
+
228
+ end
229
+
230
+ def gotoNextMatch()
231
+ @cur_match_pos += 1 if @cur_match_pos < @simple_text_view.numMatches-1
232
+ @simple_text_view.makeMatchVisible(@cur_match_pos)
233
+ @match_pos_label.text = "#{@cur_match_pos+1}/#{@simple_text_view.numMatches}" if @simple_text_view.numMatches > 0
234
+ end
235
+
236
+ def gotoPrevMatch()
237
+ @cur_match_pos -= 1 if @cur_match_pos > 0
238
+ @simple_text_view.makeMatchVisible(@cur_match_pos)
239
+ @match_pos_label.text = "#{@cur_match_pos+1}/#{@simple_text_view.numMatches}" if @simple_text_view.numMatches > 0
240
+ end
241
+
242
+ def addFilterHistory()
243
+ text = @filter_text.text
244
+ return true if text == ''
245
+ has_item = false
246
+ @filter_text.each do |item, data|
247
+ has_item = true if data == text
248
+ end
249
+ @filter_text.appendItem(text, text) unless has_item == true
250
+ @filter_text.numVisible = @filter_text.numItems
251
+ end
252
+
253
+ def resetFilter
254
+ @simple_text_view.max_len = 0
255
+ @simple_text_view.setText(@text)
256
+ @match_pos_label.text = "0/0"
257
+ @match_pos_label.textColor = 'grey'
258
+ @filter_text.text = ''
259
+ end
260
+
261
+ def highlightPattern(pattern)
262
+ @cur_match_pos = 0
263
+ @simple_text_view.max_len = 0
264
+
265
+ @match_pos_label.textColor = 'black'
266
+
267
+ @simple_text_view.setText(@text)
268
+ @simple_text_view.highlight(pattern)
269
+ @match_pos_label.text = "0/#{@simple_text_view.numMatches()}"
270
+
271
+ @simple_text_view.makeMatchVisible(0)
272
+
273
+ @match_pos_label.text = "1/#{@simple_text_view.numMatches()}" if @simple_text_view.numMatches() > 0
274
+
275
+ end
276
+
277
+ def grepPattern(pattern)
278
+ @cur_match_pos = 0
279
+ @simple_text_view.max_len = 0
280
+
281
+ @match_pos_label.textColor = 'black'
282
+
283
+ @simple_text_view.setText(@text)
284
+
285
+ @simple_text_view.filter(pattern)
286
+ @match_pos_label.text = "0/#{@simple_text_view.numMatches()}"
287
+ @simple_text_view.highlight(pattern)
288
+ @simple_text_view.makeMatchVisible(0)
289
+
290
+ @filter_mode = SEL_TYPE_GREP
291
+
292
+ @match_pos_label.text = "1/#{@simple_text_view.numMatches()}" if @simple_text_view.numMatches() > 0
293
+
294
+ end
295
+
296
+ def addHotkeyHandler(widget)
297
+ @ctrl_pressed = false
298
+
299
+ widget.connect(SEL_KEYPRESS) { |sender, sel, event|
300
+ # puts event.code
301
+ @ctrl_pressed = true if event.code == KEY_Control_L or event.code == KEY_Control_R
302
+ # @shift_pressed = true if @ctrl_pressed and ( event.code == KEY_Shift_L or event.code == KEY_Shift_R )
303
+ if event.code == KEY_Return
304
+ highlight(@filter_text.text)
305
+ true # special handling of KEY_Return, because we don't want a linebreak in textbox.
306
+ end
307
+
308
+ if event.code == KEY_F1
309
+
310
+ unless event.moved?
311
+ FXMenuPane.new(self) do |menu_pane|
312
+ FXMenuCaption.new(menu_pane, "Hotkeys:")
313
+ FXMenuSeparator.new(menu_pane)
314
+ [ "<ctrl-r> - Reset Filter",
315
+ "<ctrl-g> - Grep",
316
+ "<ctrl-h> - Highlight",
317
+ "<ctrl-n> - Goto Next",
318
+ "<ctrl-shift-n> - Goto Prev",
319
+ "<ctrl-w> - Switch Wordwrap"
320
+ ].each do |hk|
321
+ FXMenuCaption.new(menu_pane, hk).backColor = 'yellow'
322
+ end
323
+
324
+ menu_pane.create
325
+ menu_pane.popup(nil, event.root_x, event.root_y)
326
+ app.runModalWhileShown(menu_pane)
327
+ end
328
+
329
+ end
330
+ end
331
+
332
+ if @ctrl_pressed
333
+ case event.code
334
+ when KEY_n
335
+ gotoNextMatch()
336
+ addFilterHistory()
337
+ when KEY_N
338
+ gotoPrevMatch()
339
+ addFilterHistory()
340
+ when KEY_w
341
+ @simple_text_view.textbox.textStyle ^= TEXT_WORDWRAP
342
+ when KEY_h
343
+ @mode_btn.text = "Highlight"
344
+ @filter_mode = SEL_TYPE_HIGHLIGHT
345
+ addFilterHistory()
346
+ applyFilter()
347
+ when KEY_g
348
+ @mode_btn.text = "Grep"
349
+ @filter_mode = SEL_TYPE_GREP
350
+ addFilterHistory()
351
+ applyFilter()
352
+ when KEY_r
353
+ resetFilter()
354
+
355
+ end
356
+ end
357
+ false
358
+ }
359
+
360
+ widget.connect(SEL_KEYRELEASE) { |sender, sel, event|
361
+ @ctrl_pressed = false if event.code == KEY_Control_L or event.code == KEY_Control_R
362
+ false
363
+ }
364
+ end
365
+
366
+ end
367
+ end
368
+ end