rbcurse 1.5.0 → 1.5.2

Sign up to get free protection for your applications and to get access to all the features.
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