rbcurse 1.5.0 → 1.5.2

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.
Files changed (104) hide show
  1. data/Makefile +21 -0
  2. data/Manifest.txt +6 -0
  3. data/README.markdown +6 -4
  4. data/TODO +372 -0
  5. data/TODO2.txt +121 -0
  6. data/VERSION +1 -1
  7. data/examples/README.txt +67 -0
  8. data/examples/abasiclist.rb +33 -0
  9. data/examples/alpmenu.rb +42 -0
  10. data/examples/app.rb +859 -0
  11. data/examples/app.sample +17 -0
  12. data/examples/appdirtree.rb +74 -0
  13. data/examples/appemail.rb +191 -0
  14. data/examples/appemaillb.rb +308 -0
  15. data/examples/appgcompose.rb +315 -0
  16. data/examples/atree.rb +64 -0
  17. data/examples/common/file.rb +40 -0
  18. data/examples/common/rmail.rb +257 -0
  19. data/examples/data.txt +683 -0
  20. data/examples/data/README.markdown +9 -0
  21. data/examples/data/brew.txt +38 -0
  22. data/examples/data/color.2 +37 -0
  23. data/examples/data/gemlist.txt +60 -0
  24. data/examples/data/lotr.txt +12 -0
  25. data/examples/data/ports.txt +136 -0
  26. data/examples/data/tasks.txt +27 -0
  27. data/examples/data/todocsv.csv +28 -0
  28. data/examples/data/unix1.txt +21 -0
  29. data/examples/data/unix2.txt +11 -0
  30. data/examples/dbdemo.rb +495 -0
  31. data/examples/deprecated/appgmail.rb +952 -0
  32. data/examples/deprecated/splitp.rb +56 -0
  33. data/examples/deprecated/testscrolllb.rb +86 -0
  34. data/examples/deprecated/testscrollp.rb +88 -0
  35. data/examples/deprecated/testscrollta.rb +80 -0
  36. data/examples/deprecated/testscrolltable.rb +165 -0
  37. data/examples/deprecated/testsplit.rb +87 -0
  38. data/examples/deprecated/testsplit2.rb +123 -0
  39. data/examples/deprecated/testsplit3.rb +215 -0
  40. data/examples/deprecated/testsplit3_1.rb +244 -0
  41. data/examples/deprecated/testsplit3a.rb +215 -0
  42. data/examples/deprecated/testsplit3b.rb +237 -0
  43. data/examples/deprecated/testsplitta.rb +148 -0
  44. data/examples/deprecated/testsplittv.rb +142 -0
  45. data/examples/deprecated/testsplittvv.rb +144 -0
  46. data/examples/deprecated/testtpane.rb +215 -0
  47. data/examples/deprecated/testtpane2.rb +145 -0
  48. data/examples/deprecated/testtpanetable.rb +203 -0
  49. data/examples/dirtree.rb +88 -0
  50. data/examples/experimental/resultsetdemo.rb +280 -0
  51. data/examples/experimental/testmform.rb +35 -0
  52. data/examples/experimental/testscroller.rb +117 -0
  53. data/examples/experimental/teststackflow.rb +111 -0
  54. data/examples/menu1.rb +112 -0
  55. data/examples/multispl.rb +86 -0
  56. data/examples/newmessagebox.rb +131 -0
  57. data/examples/newtabbedwindow.rb +100 -0
  58. data/examples/newtesttabp.rb +121 -0
  59. data/examples/qdfilechooser.rb +68 -0
  60. data/examples/rfe.rb +1239 -0
  61. data/examples/rfe_renderer.rb +121 -0
  62. data/examples/sqlc.rb +454 -0
  63. data/examples/sqlm.rb +437 -0
  64. data/examples/sqlt.rb +408 -0
  65. data/examples/status.txt +68 -0
  66. data/examples/table1.rb +24 -0
  67. data/examples/term2.rb +84 -0
  68. data/examples/test1.rb +239 -0
  69. data/examples/test2.rb +674 -0
  70. data/examples/testapp.rb +44 -0
  71. data/examples/testapp2.rb +58 -0
  72. data/examples/testchars.rb +137 -0
  73. data/examples/testcombo.rb +91 -0
  74. data/examples/testkeypress.rb +66 -0
  75. data/examples/testlistbox.rb +113 -0
  76. data/examples/testmenu.rb +101 -0
  77. data/examples/testmulticomp.rb +70 -0
  78. data/examples/testmulticontainer.rb +94 -0
  79. data/examples/testmultispl.rb +199 -0
  80. data/examples/testree.rb +106 -0
  81. data/examples/testtable.rb +264 -0
  82. data/examples/testtabp.rb +107 -0
  83. data/examples/testtodo.rb +584 -0
  84. data/examples/testvimsplit.rb +112 -0
  85. data/examples/testwsshortcuts.rb +64 -0
  86. data/examples/testwsshortcuts2.rb +126 -0
  87. data/examples/todo.db +0 -0
  88. data/examples/todo.yml +191 -0
  89. data/examples/viewtodo.rb +574 -0
  90. data/lib/rbcurse/deprecated/README.markdown +12 -0
  91. data/lib/rbcurse/deprecated/rpad.rb +375 -0
  92. data/lib/rbcurse/deprecated/rscrollpane.rb +512 -0
  93. data/lib/rbcurse/deprecated/rsplitpane.rb +894 -0
  94. data/lib/rbcurse/deprecated/rsplitpane2.rb +1009 -0
  95. data/lib/rbcurse/deprecated/rviewport.rb +204 -0
  96. data/lib/rbcurse/deprecated/widgets/mapper.rb +130 -0
  97. data/lib/rbcurse/deprecated/widgets/rmessagebox.rb +348 -0
  98. data/lib/rbcurse/deprecated/widgets/rtabbedpane.rb +1158 -0
  99. data/lib/rbcurse/deprecated/widgets/rtabbedwindow.rb +167 -0
  100. data/lib/rbcurse/deprecated/widgets/scrollable.rb +301 -0
  101. data/lib/rbcurse/deprecated/widgets/stdscrwindow.rb +309 -0
  102. data/lib/ver/keyboard2.rb +170 -0
  103. data/test/test_rbcurse.rb +0 -0
  104. metadata +131 -9
@@ -0,0 +1,315 @@
1
+ require 'rbcurse/core/util/app'
2
+ require 'gmail'
3
+
4
+ # requires gmail gem
5
+
6
+ def insert_file
7
+ str = ask("File? ", Pathname) do |q|
8
+ q.completion_proc = Proc.new {|str| Dir.glob(str +"*").collect { |f| File.directory?(f) ? f+"/" : f } }
9
+ q.helptext = "Enter start of filename and tab to get completion"
10
+ end
11
+ message "we got #{str} "
12
+ end
13
+ ################
14
+ # Allow a field to have gmail like completion
15
+ # As a user types, a window highlights matches. Up and down arrow key may be used to select with Enter.
16
+ # A user may type Multiple email ids in field (space or comma sep), and matches for last word will be
17
+ # displayed.
18
+ # If you wish to use this in other ways:
19
+ # - match entire field not last word, then set matching to false or single
20
+ # - match_from_start will match your array values from start. If you want
21
+ # the pattern to match anywhere in array, set to false.
22
+ # - set height, width, top and left in config hash
23
+ # - block is intended to allow caller to override matching TODO
24
+ class GmailField
25
+ def initialize field, list=nil, config={}, &block
26
+ @field = field
27
+ @list = list
28
+ @config = config
29
+ @matching = config.fetch(:matching, :multiple)
30
+ @match_from_start = config.fetch(:match_from_start, true)
31
+ setup
32
+ end
33
+ def setup # gmailfield
34
+ @field.bind(:CHANGE) do |eve|
35
+ c = eve.source
36
+ text = c.getvalue
37
+ if text[-1] == " "
38
+ clear_list
39
+ else
40
+ pos = text.rindex(/, /)
41
+ if pos
42
+ text = text[pos+1..-1].strip if @matching == :multiple
43
+ end
44
+ @textsize = text.size
45
+ # \W instead of ^, will match start of word, lastname, emailid
46
+ patt = @match_from_start ? %r{\W#{text}}i : %r{#{text}}i
47
+ matches = @list.grep patt
48
+ @matches = matches
49
+ if @matches.size == 1 && @matches.first == text
50
+ clear_list
51
+ else
52
+ #$log.debug "XXXX #{self.class} matches #{matches} " if $log.debug?
53
+ #@caller = app.config[:caller]
54
+ if !matches.empty?
55
+ say " matches: #{matches.size}: #{matches} "
56
+ @list_object = udisplay_list matches
57
+ else
58
+ clear_list
59
+ #@caller.clear_list
60
+ end
61
+ end
62
+ end
63
+ end
64
+ @field.bind(:LEAVE) do |eve|
65
+ clear_list
66
+ end
67
+ @field.bind_key(KEY_DOWN) do
68
+ if @list_object
69
+ @list_object.press(KEY_DOWN)
70
+ #current_index = @list_object.current_index
71
+ @list_object.display_content
72
+ else
73
+ :UNHANDLED
74
+ end
75
+ end
76
+ @field.bind_key(KEY_UP) do
77
+ if @list_object
78
+ @list_object.press(KEY_UP)
79
+ #current_index = @list_object.current_index
80
+ @list_object.display_content
81
+ else
82
+ :UNHANDLED
83
+ end
84
+ end
85
+ @field.bind_key(13) do
86
+ #if @caller
87
+ if @list_object
88
+ @list_object.press(KEY_ENTER)
89
+ current_index = @list_object.current_index
90
+ if current_index > @matches.size-1
91
+ current_index = 0
92
+ end
93
+ sel = @matches[current_index]
94
+ if sel
95
+ #$log.debug "XXXX sel #{sel}, #{@textsize} " if $log.debug?
96
+ if @textsize
97
+ t = @field.getvalue
98
+ $log.debug "XXXX t #{t}:: matches:: #{@matches} " if $log.debug?
99
+ t.slice!(-@textsize..-1)
100
+ t << sel
101
+
102
+ #t << sel[@textsize..-1]
103
+ @field.set_buffer(t)
104
+ else
105
+ @field.set_buffer(@matches[current_index])
106
+ end
107
+ @field.cursor_end
108
+ end # sel , otherwise matches was nil
109
+ # need to set cursor correctly.
110
+ clear_list
111
+ end
112
+ #end
113
+ end
114
+ end
115
+
116
+ def udisplay_list list1 # gmailfield
117
+ unless @commandwin
118
+ require 'rbcurse/core/util/rcommandwindow'
119
+ if @style == :old
120
+ h = @config.fetch(:height, 5)
121
+ w = @config.fetch(:width, Ncurses.COLS-1)
122
+ top = @config.fetch(:top, Ncurses.LINES-6)
123
+ left = @config.fetch(:left, 0)
124
+ else
125
+ hj = list1.size+2
126
+ hj = [hj, 10].min
127
+ h = @config.fetch(:height, hj)
128
+ w = @config.fetch(:width, list1[0].size+5)
129
+ top = @config.fetch(:top, @field.row+1 )
130
+ left = @config.fetch(:left, @field.col)
131
+ end
132
+ layout = { :height => h, :width => w, :top => top, :left => left }
133
+ rc = CommandWindow.new nil, :layout => layout, :box => :border #, :title => config[:title]
134
+ @commandwin = rc
135
+ end
136
+ begin
137
+ @commandwin.clear
138
+ @commandwin.udisplay_list list1
139
+ ensure
140
+ #rc.destroy
141
+ #rc = nil
142
+ end
143
+ end
144
+ def clear_list # gmailfield
145
+ if @commandwin
146
+ @commandwin.destroy
147
+ @commandwin = nil
148
+ end
149
+ @list_object = nil
150
+ end
151
+ end
152
+ module AppgCompose
153
+ class GmailCompose
154
+ def initialize gmail=nil, config={}
155
+ @gmail = gmail
156
+ @username = config[:username]
157
+ @password = config[:password]
158
+ @config = config
159
+ #@to = config[:to]
160
+ #@cc = config[:cc]
161
+ #@bcc = config[:bcc]
162
+ #@subject = config[:subject]
163
+ yield self if block_given?
164
+ end
165
+ def __udisplay_list list1 # gmailcompose
166
+ warn "is this used ?"
167
+ unless @commandwin
168
+ require 'rbcurse/core/util/rcommandwindow'
169
+ layout = { :height => 5, :width => Ncurses.COLS-1, :top => Ncurses.LINES-6, :left => 0 }
170
+ rc = CommandWindow.new nil, :layout => layout, :box => true #, :title => config[:title]
171
+ @commandwin = rc
172
+ end
173
+ begin
174
+ #w = rc.window
175
+ # may need to clear first
176
+ @commandwin.clear
177
+ @commandwin.udisplay_list list1
178
+ ensure
179
+ #rc.destroy
180
+ #rc = nil
181
+ end
182
+ end
183
+ def __clear_list # gmailcompose
184
+ warn "is this used"
185
+ if @commandwin
186
+ @commandwin.destroy
187
+ @commandwin = nil
188
+ end
189
+ @list_object = nil
190
+ end
191
+ def run
192
+ ss = self
193
+ #$log.debug "XXX self #{ss.class} " if $log.debug?
194
+ App.new(:caller => ss) do |app|
195
+ #@caller = app.config[:caller]
196
+ #$log.debug " inside XXX new app #{@caller} "
197
+ $log.debug " inside XXX new app config #{app.config} "
198
+ def get_commands
199
+ %w{ insert_file}
200
+ end
201
+ header = app.app_header "rbcurse #{Rbcurse::VERSION}", :text_center => "Compose Mail", :text_right =>"27% Stronger", :color => :black, :bgcolor => :white, :attr => :bold
202
+ app.message "Press F10 to exit from here"
203
+ app.stack :margin_top => 2, :margin => 5, :width => 15 do |xxx|
204
+ fg = :white
205
+ bg = :blue
206
+ app.label :text => "To", :color => fg, :bgcolor => bg, :display_length => 10
207
+ app.label :text => "Subject", :color => fg, :bgcolor => bg, :display_length => 10
208
+ app.label :text => "Cc", :color => fg, :bgcolor => bg, :display_length => 10
209
+ app.label :text => "Body", :color => fg, :bgcolor => bg, :display_length => 10
210
+ end
211
+
212
+
213
+ ww = 80
214
+ app.stack :margin_top => 2, :margin => 25, :width => ww do |xxx|
215
+ file="contacts.yml"
216
+ to_list = []
217
+ if File.exists? file
218
+ require 'yaml'
219
+ contacts = YAML::load( File.open(file))
220
+ contacts.each { |e| to_list << "\"#{e[0]}\" <#{e[1]}>" }
221
+ else
222
+ to_list = ['"Matz " <matz@ruby.com>', '"James E Gray" <james@gmail.com>', '"Steve Jobs" <jobs@apple.com>', '"Bram Moolenar", <bmool@vim.com>', '"Mental Guy", <mentalguy@me.com>' ]
223
+ end
224
+ @to = app.field "to", :maxlen => 100, :bgcolor => :white, :color => :black
225
+ GmailField.new @to, to_list
226
+ @to.text = @config[:to]
227
+ @subject = app.field "subject", :maxlen => 100, :display_length => nil , :bgcolor => :white, :color => :black
228
+ @subject.text = @config[:subject]
229
+ @cc = app.field "cc", :maxlen => 100, :display_length => nil , :bgcolor => :white, :color => :black
230
+ GmailField.new @cc, to_list #, {:top => @cc.row+1, :left => @cc.col, :width => 40 }
231
+ @cc.text = @config[:cc]
232
+ @body = app.textarea :height => 10 do |e|
233
+ #e.source.get_text
234
+ end
235
+ app.hline :width => ww
236
+ app.flow do |xxx|
237
+ app.button "&Post" do
238
+ alert "To field is nil in button itself" if @to.nil?
239
+ app.message "posting letter"
240
+ #@caller = app.config[:caller]
241
+ status = post_letter(self, :to => @to, :subject => @subject, :body => @body)
242
+ app.message "posted email: status #{status} "
243
+ end
244
+ app.button "&Save" do
245
+ app.message "saving to file"
246
+ end
247
+ end
248
+
249
+ end # stack
250
+ end # app
251
+
252
+ end # run
253
+ # now we can access to and subject and body directly
254
+ # post an email
255
+ def post_letter app, config={}
256
+ #alert "i can access to directly. #{@to.getvalue} " if @to
257
+ to = config[:to]
258
+ subject = config[:subject]
259
+ body = config[:body]
260
+ if to.nil?
261
+ alert "To is nil. Some programming error"
262
+ return false
263
+ end
264
+ unless @username
265
+ ww = ENV['GMAIL_USER']
266
+ #ww << "@gmail.com" if ww # suddnely giving frozen string error
267
+ ww = ww + "@gmail.com" if ww
268
+ @username = ask("Username: ") { |q| q.default = ww }
269
+ end
270
+ unless @password
271
+ ww = ENV['GMAIL_PASS']
272
+ @password = ask("Password: ") { |q| q.default = ww; q.echo ="*" }
273
+ end
274
+ if @username.nil? || @password.nil?
275
+ say_with_pause "Cannot proceeed without user and pass"
276
+ return false
277
+ end
278
+ unless @gmail
279
+ say "Connecting to gmail..."
280
+ begin
281
+ @gmail = Gmail.connect!(@username, @password)
282
+ rescue => ex
283
+ @password = @username = nil
284
+ $log.debug( ex) if ex
285
+ $log.debug(ex.backtrace.join("\n")) if ex
286
+ end
287
+ end
288
+ unless @gmail
289
+ say_with_pause "Cannot proceeed without connection" unless @gmail
290
+ return false
291
+ end
292
+
293
+ body = body.get_text
294
+ to = to.getvalue
295
+ subject = subject.getvalue
296
+ say "Posting #{subject} to #{to} "
297
+ if body
298
+ @gmail.deliver do
299
+ to to
300
+ subject subject
301
+ body body
302
+ end
303
+ else
304
+ alert "Got no body"
305
+ end # body
306
+ true
307
+ end # post_letter
308
+
309
+ end # class
310
+ end # module
311
+ if __FILE__ == $PROGRAM_NAME
312
+ a = AppgCompose::GmailCompose.new
313
+ a.run
314
+ end
315
+
data/examples/atree.rb ADDED
@@ -0,0 +1,64 @@
1
+ require 'rbcurse/core/util/app'
2
+
3
+ App.new do
4
+ header = app_header "rbcurse #{Rbcurse::VERSION}", :text_center => "Tree Demo", :text_right =>"New Improved!", :color => :black, :bgcolor => :white, :attr => :bold
5
+ message "Press Enter to expand/collapse"
6
+ @form.bind_key(FFI::NCurses::KEY_F3) {
7
+ require 'rbcurse/core/util/viewer'
8
+ RubyCurses::Viewer.view("rbc13.log", :close_key => KEY_RETURN, :title => "<Enter> to close")
9
+ }
10
+
11
+ stack :margin_top => 2, :margin => 5, :width => 30 do
12
+ tm = nil
13
+ atree = tree :height => 10, :title => "ruby way" do
14
+ root "root" do
15
+ branch "hello" do
16
+ leaf "ruby"
17
+ end
18
+ branch "goodbye" do
19
+ leaf "java"
20
+ leaf "verbosity"
21
+ end
22
+ end
23
+ end
24
+ found=atree.get_node_for_path "goodbye"
25
+ atree.set_expanded_state(atree.root, true)
26
+ atree.set_expanded_state(found,true)
27
+
28
+ # using a Hash
29
+ model = { :ruby => [ "jruby", {:mri => %W[ 1.8.6 1.8.7]}, {:yarv => %W[1.9.1 1.9.2]}, "rubinius", "macruby" ], :python => %W[ cpython jython laden-swallow ] }
30
+ tree :data => model, :title => "Hash"
31
+
32
+ end # stack
33
+ stack :margin_top => 2, :margin => 40, :width => 30 do
34
+
35
+ # using an Array
36
+ tree :data => %W[ ruby cobol jruby smalltalk fortran piethon purrl lithp ], :title=> "Array"
37
+
38
+ # long way ISO 9001 certifed, SEI CMM 5 compliant
39
+ #
40
+ root = TreeNode.new "ROOT"
41
+ subroot = TreeNode.new "subroot"
42
+ leaf1 = TreeNode.new "leaf 1"
43
+ leaf2 = TreeNode.new "leaf 2"
44
+ model = DefaultTreeModel.new root
45
+ #model.insert_node_into(subroot, root, 0) # BLEAH JAVA !!
46
+
47
+ # slightly better, since we return self in ruby
48
+ root << subroot
49
+ subroot << leaf1 << leaf2
50
+ leaf1 << "leaf11"
51
+ leaf1 << "leaf12"
52
+
53
+ # more rubyish way
54
+ root.add "blocky", true do
55
+ add "block2"
56
+ add "block3" do
57
+ add "block31"
58
+ end
59
+ end
60
+
61
+ tree :data => model, :title => "legacy way"
62
+
63
+ end
64
+ end # app
@@ -0,0 +1,40 @@
1
+ # ----------------------------------------------------------------------------- #
2
+ # File: file.rb
3
+ # Description: some common file related methods which can be used across
4
+ # file manager demos, since we seems to have a lot of them :)
5
+ # Author: rkumar http://github.com/rkumar/rbcurse/
6
+ # Date: 2011-11-15 - 19:54
7
+ # License: Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
8
+ # Last update: use ,,L
9
+ # ----------------------------------------------------------------------------- #
10
+ #
11
+
12
+ require 'rbcurse/core/include/appmethods'
13
+ module RubyCurses
14
+ def file_edit fp #=@current_list.filepath
15
+ #$log.debug " edit #{fp}"
16
+ editor = ENV['EDITOR'] || 'vi'
17
+ vimp = %x[which #{editor}].chomp
18
+ shell_out "#{vimp} #{fp}"
19
+ end
20
+
21
+ # TODO we need to move these to some common file so differnt programs and demos
22
+ # can use them on pressing space or enter.
23
+ def file_page fp #=@current_list.filepath
24
+ ft=%x[file #{fp}]
25
+ if ft.index("text")
26
+ pager = ENV['PAGER'] || 'less'
27
+ vimp = %x[which #{pager}].chomp
28
+ shell_out "#{vimp} #{fp}"
29
+ elsif ft.index(/zip/i)
30
+ shell_out "tar tvf #{fp} | less"
31
+ elsif ft.index(/directory/i)
32
+ shell_out "ls -lh #{fp} | less"
33
+ else
34
+ alert "#{fp} is not text, not paging "
35
+ #use_on_file "als", fp # only zip or archive
36
+ end
37
+ end
38
+
39
+ end # module
40
+ include RubyCurses
@@ -0,0 +1,257 @@
1
+ #!/usr/bin/env ruby -w
2
+ # WARNING. This file is required by appemail.rb.
3
+ #
4
+ # Supply the path of any mbox file such as ~/mbox or ~/mail/read-mail
5
+ # and see a listing of mails, then give a msg number and see body
6
+ # You may run this with -EASCII-8BIT if it crashes with a UTF8 error.
7
+ #require 'mailread' # i've copied it in here 2011-09-18
8
+ require 'date'
9
+
10
+ # a sample mail formatter class
11
+ # Does formatting just like alpine
12
+ # Each message is passed in the format method, thus this is reused
13
+ class MailFormatter
14
+ attr_reader :message
15
+ attr_reader :header
16
+ def initialize #message
17
+ #@message = message
18
+ #@header = message.header
19
+ end
20
+
21
+ def date
22
+ raise StandardError, "pass message first using format()" unless @header
23
+ m = @header
24
+ date = Date.parse(m['Date'])
25
+ date = date.strftime("%b %d")
26
+ end
27
+
28
+ def from
29
+ raise StandardError, "pass message first using format()" unless @header
30
+ m = @header
31
+ match = m['From'].to_s.match(/\((.*)\)/)
32
+ from = m['From']
33
+ if match
34
+ from = match[1]
35
+ else
36
+ match = m['From'].to_s.match(/(.*)</)
37
+ from = match[1] if match
38
+ end
39
+ from
40
+ end
41
+ def body
42
+ raise StandardError, "pass message first using format()" unless @message
43
+ @message.body
44
+ end
45
+
46
+ def subject
47
+ raise StandardError, "pass message first using format()" unless @header
48
+ m = @header
49
+ m['Subject']
50
+ end
51
+ def status
52
+ raise StandardError, "pass message first using format()" unless @header
53
+ m = @header
54
+ m['Status']
55
+ end
56
+
57
+ def format message, count
58
+ @header = message.header
59
+ #@message = message
60
+ m = message.header
61
+ "%2s %2d %s %-25s %-s\n" % [ status, count, date, from, subject ]
62
+ end
63
+
64
+ def create_array message, count
65
+ @header = message.header
66
+ #@message = message
67
+ m = message.header
68
+ #printf("#{attr}%2s %2d %s |%-25s| %-s#{attre}\n", m['Status'], count, date, from, msg.header['Subject'])
69
+ row = [ status, count, date, from, m['Subject'] ]
70
+ end
71
+ end # class
72
+ # opens and maintains an mbox mailbox
73
+ class Mbox
74
+ include Enumerable
75
+ attr_reader :folder
76
+ attr_reader :mails
77
+ attr_reader :unread_count
78
+ attr_reader :read_count
79
+
80
+ # takes a mailbox name, e,g., mbox
81
+ # Does not update, since this is just a demo
82
+ def initialize folder
83
+ raise ArgumentError, "#{folder} not a valid file. Pls supply correct path." if !File.exists? folder
84
+ @folder = folder
85
+ @unread_count = 0
86
+ @read_count = 0
87
+ @mboxh = {}
88
+ @mbox_counts = {}
89
+ @mails = nil
90
+ @formatter = nil
91
+ parse
92
+ end
93
+ def parse &block # :yields: Mail
94
+ mbox = File.open(@folder)
95
+ count = lines = 0
96
+ unread_count = 0
97
+ read_count = 0
98
+ # array of mails
99
+ mails = []
100
+
101
+ # read up the warning message, we don't want it in our array
102
+ msg = Mail.new(mbox)
103
+
104
+ while !mbox.eof?
105
+ msg = Mail.new(mbox)
106
+ count += 1
107
+ s = msg.header['Status']
108
+ if s == "O"
109
+ unread_count += 1
110
+ else
111
+ read_count += 1
112
+ end
113
+ mails << msg
114
+ yield msg if block_given?
115
+ end
116
+ @mails = mails
117
+ #@mbox_counts[@folder] = [unread_count, read_count]
118
+ @unread_count, @read_count = unread_count, read_count
119
+ mbox.close
120
+ end
121
+ def each # :yields: message
122
+ parse unless @mails
123
+ @mails.each { |e| yield e }
124
+ end
125
+ def formatted_each &block
126
+ fmt = @formatter || MailFormatter.new
127
+ each_with_index do |msg, index|
128
+ yield fmt.format msg, index + 1
129
+ end
130
+ end
131
+ # returns an array for each entry which can be used with tabularwidget
132
+ def array_each &block
133
+ fmt = @formatter || MailFormatter.new
134
+ each_with_index do |msg, index|
135
+ yield fmt.create_array msg, index + 1
136
+ end
137
+ end
138
+ # set a formatter object, if you wish to override default one
139
+ def formatter fmt
140
+ @formatter = fmt
141
+ end
142
+ end
143
+ # opens and maintains a hash of mboxes
144
+ # does not see to add any value other than being just a hash !
145
+ class MboxManager
146
+ def initialize
147
+ @boxes = {}
148
+ @current_name = nil
149
+ end
150
+ def use folder
151
+ if !@boxes.has_key? folder
152
+ @mails = Mbox.new folder
153
+ @boxes[folder] = @mails
154
+ else
155
+ @mails = @boxes[folder]
156
+ end
157
+ @current_name = folder
158
+ @mails
159
+ end
160
+ def mails folder=@current_name
161
+ use folder
162
+ @mails
163
+ end
164
+ end
165
+
166
+ # The Mail class represents an internet mail message (as per RFC822, RFC2822)
167
+ # with headers and a body.
168
+ class Mail
169
+
170
+ # Create a new Mail where +f+ is either a stream which responds to gets(),
171
+ # or a path to a file. If +f+ is a path it will be opened.
172
+ #
173
+ # The whole message is read so it can be made available through the #header,
174
+ # #[] and #body methods.
175
+ #
176
+ # The "From " line is ignored if the mail is in mbox format.
177
+ def initialize(f)
178
+ unless defined? f.gets
179
+ f = open(f, "r")
180
+ opened = true
181
+ end
182
+
183
+ @header = {}
184
+ @body = []
185
+ begin
186
+ while line = f.gets()
187
+ line.chop!
188
+ # Added encode by RK since crashing with UTF-8 error
189
+ line = line.encode("ASCII-8BIT", :invalid => :replace, :undef => :replace, :replace => "?")
190
+ next if /^From /=~line # skip From-line
191
+ break if /^$/=~line # end of header
192
+
193
+ if /^(\S+?):\s*(.*)/=~line
194
+ (attr = $1).capitalize!
195
+ @header[attr] = $2
196
+ elsif attr
197
+ line.sub!(/^\s*/, '')
198
+ @header[attr] += "\n" + line
199
+ end
200
+ end
201
+
202
+ return unless line
203
+
204
+ while line = f.gets()
205
+ # Added encode by RK since crashing with UTF-8 error
206
+ line = line.encode("ASCII-8BIT", :invalid => :replace, :undef => :replace, :replace => "?")
207
+ #line = line.encode('ASCII-8BIT') # added RK
208
+ break if /^From /=~line
209
+ @body.push(line)
210
+ end
211
+ ensure
212
+ f.close if opened
213
+ end
214
+ end
215
+
216
+ # Return the headers as a Hash.
217
+ def header
218
+ return @header
219
+ end
220
+
221
+ # Return the message body as an Array of lines
222
+ def body
223
+ return @body
224
+ end
225
+
226
+ # Return the header corresponding to +field+.
227
+ #
228
+ # Matching is case-insensitive.
229
+ def [](field)
230
+ @header[field.capitalize]
231
+ end
232
+ end
233
+ #puts mails.size
234
+ if __FILE__ == $PROGRAM_NAME
235
+ MAILBOX = ARGV[0] || "mbox"
236
+ mx = Mbox.new MAILBOX
237
+ mx.formatted_each do |str|
238
+ puts str
239
+ end
240
+ mails = mx.mails
241
+ BOLD = "\e[1m"
242
+ CLEAR = "\e[0m"
243
+
244
+ # ask user for a number and print body for that
245
+ while true
246
+ print "Enter a mail number [1 to #{mails.size}]:"
247
+ n = STDIN.gets.chomp
248
+ break if n.nil? || n.empty?
249
+ msg = mails[n.to_i-1]
250
+ body = msg.body
251
+ puts
252
+ string= "#{msg.header['Subject']}"
253
+ puts "#{BOLD}#{string}#{CLEAR}"
254
+ puts "-" * string.length
255
+ puts body
256
+ end
257
+ end