rbcurse 1.5.0 → 1.5.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Makefile +21 -0
- data/Manifest.txt +6 -0
- data/README.markdown +6 -4
- data/TODO +372 -0
- data/TODO2.txt +121 -0
- data/VERSION +1 -1
- data/examples/README.txt +67 -0
- data/examples/abasiclist.rb +33 -0
- data/examples/alpmenu.rb +42 -0
- data/examples/app.rb +859 -0
- data/examples/app.sample +17 -0
- data/examples/appdirtree.rb +74 -0
- data/examples/appemail.rb +191 -0
- data/examples/appemaillb.rb +308 -0
- data/examples/appgcompose.rb +315 -0
- data/examples/atree.rb +64 -0
- data/examples/common/file.rb +40 -0
- data/examples/common/rmail.rb +257 -0
- data/examples/data.txt +683 -0
- data/examples/data/README.markdown +9 -0
- data/examples/data/brew.txt +38 -0
- data/examples/data/color.2 +37 -0
- data/examples/data/gemlist.txt +60 -0
- data/examples/data/lotr.txt +12 -0
- data/examples/data/ports.txt +136 -0
- data/examples/data/tasks.txt +27 -0
- data/examples/data/todocsv.csv +28 -0
- data/examples/data/unix1.txt +21 -0
- data/examples/data/unix2.txt +11 -0
- data/examples/dbdemo.rb +495 -0
- data/examples/deprecated/appgmail.rb +952 -0
- data/examples/deprecated/splitp.rb +56 -0
- data/examples/deprecated/testscrolllb.rb +86 -0
- data/examples/deprecated/testscrollp.rb +88 -0
- data/examples/deprecated/testscrollta.rb +80 -0
- data/examples/deprecated/testscrolltable.rb +165 -0
- data/examples/deprecated/testsplit.rb +87 -0
- data/examples/deprecated/testsplit2.rb +123 -0
- data/examples/deprecated/testsplit3.rb +215 -0
- data/examples/deprecated/testsplit3_1.rb +244 -0
- data/examples/deprecated/testsplit3a.rb +215 -0
- data/examples/deprecated/testsplit3b.rb +237 -0
- data/examples/deprecated/testsplitta.rb +148 -0
- data/examples/deprecated/testsplittv.rb +142 -0
- data/examples/deprecated/testsplittvv.rb +144 -0
- data/examples/deprecated/testtpane.rb +215 -0
- data/examples/deprecated/testtpane2.rb +145 -0
- data/examples/deprecated/testtpanetable.rb +203 -0
- data/examples/dirtree.rb +88 -0
- data/examples/experimental/resultsetdemo.rb +280 -0
- data/examples/experimental/testmform.rb +35 -0
- data/examples/experimental/testscroller.rb +117 -0
- data/examples/experimental/teststackflow.rb +111 -0
- data/examples/menu1.rb +112 -0
- data/examples/multispl.rb +86 -0
- data/examples/newmessagebox.rb +131 -0
- data/examples/newtabbedwindow.rb +100 -0
- data/examples/newtesttabp.rb +121 -0
- data/examples/qdfilechooser.rb +68 -0
- data/examples/rfe.rb +1239 -0
- data/examples/rfe_renderer.rb +121 -0
- data/examples/sqlc.rb +454 -0
- data/examples/sqlm.rb +437 -0
- data/examples/sqlt.rb +408 -0
- data/examples/status.txt +68 -0
- data/examples/table1.rb +24 -0
- data/examples/term2.rb +84 -0
- data/examples/test1.rb +239 -0
- data/examples/test2.rb +674 -0
- data/examples/testapp.rb +44 -0
- data/examples/testapp2.rb +58 -0
- data/examples/testchars.rb +137 -0
- data/examples/testcombo.rb +91 -0
- data/examples/testkeypress.rb +66 -0
- data/examples/testlistbox.rb +113 -0
- data/examples/testmenu.rb +101 -0
- data/examples/testmulticomp.rb +70 -0
- data/examples/testmulticontainer.rb +94 -0
- data/examples/testmultispl.rb +199 -0
- data/examples/testree.rb +106 -0
- data/examples/testtable.rb +264 -0
- data/examples/testtabp.rb +107 -0
- data/examples/testtodo.rb +584 -0
- data/examples/testvimsplit.rb +112 -0
- data/examples/testwsshortcuts.rb +64 -0
- data/examples/testwsshortcuts2.rb +126 -0
- data/examples/todo.db +0 -0
- data/examples/todo.yml +191 -0
- data/examples/viewtodo.rb +574 -0
- data/lib/rbcurse/deprecated/README.markdown +12 -0
- data/lib/rbcurse/deprecated/rpad.rb +375 -0
- data/lib/rbcurse/deprecated/rscrollpane.rb +512 -0
- data/lib/rbcurse/deprecated/rsplitpane.rb +894 -0
- data/lib/rbcurse/deprecated/rsplitpane2.rb +1009 -0
- data/lib/rbcurse/deprecated/rviewport.rb +204 -0
- data/lib/rbcurse/deprecated/widgets/mapper.rb +130 -0
- data/lib/rbcurse/deprecated/widgets/rmessagebox.rb +348 -0
- data/lib/rbcurse/deprecated/widgets/rtabbedpane.rb +1158 -0
- data/lib/rbcurse/deprecated/widgets/rtabbedwindow.rb +167 -0
- data/lib/rbcurse/deprecated/widgets/scrollable.rb +301 -0
- data/lib/rbcurse/deprecated/widgets/stdscrwindow.rb +309 -0
- data/lib/ver/keyboard2.rb +170 -0
- data/test/test_rbcurse.rb +0 -0
- 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
|