watobo 0.9.16 → 0.9.17

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.
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