vmail 2.8.7 → 2.8.9
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/vmail.rb +12 -10
- data/lib/vmail.vim +37 -1
- data/lib/vmail/address_quoter.rb +4 -4
- data/lib/vmail/contacts_extractor.rb +5 -5
- data/lib/vmail/database.rb +2 -2
- data/lib/vmail/flagging_and_moving.rb +6 -6
- data/lib/vmail/helpers.rb +1 -1
- data/lib/vmail/imap_client.rb +35 -22
- data/lib/vmail/inbox_poller.rb +84 -9
- data/lib/vmail/message_formatter.rb +11 -11
- data/lib/vmail/options.rb +6 -6
- data/lib/vmail/query.rb +1 -1
- data/lib/vmail/reply_templating.rb +8 -8
- data/lib/vmail/searching.rb +5 -5
- data/lib/vmail/send_options.rb +2 -2
- data/lib/vmail/showing_headers.rb +11 -11
- data/lib/vmail/showing_message.rb +9 -9
- data/lib/vmail/version.rb +1 -1
- data/test/address_quoter_test.rb +4 -4
- data/test/message_formatter_test.rb +6 -6
- data/test/notifier_test.rb +35 -0
- data/test/reply_template_test.rb +1 -1
- metadata +32 -34
- checksums.yaml +0 -7
data/lib/vmail.rb
CHANGED
@@ -17,7 +17,7 @@ module Vmail
|
|
17
17
|
end
|
18
18
|
|
19
19
|
vim = ENV['VMAIL_VIM'] || 'vim'
|
20
|
-
ENV['VMAIL_BROWSER'] ||= if RUBY_PLATFORM.downcase.include?('linux')
|
20
|
+
ENV['VMAIL_BROWSER'] ||= if RUBY_PLATFORM.downcase.include?('linux')
|
21
21
|
tools = ['gnome-open', 'kfmclient-exec', 'xdg-open', 'konqueror']
|
22
22
|
tool = tools.detect { |tool|
|
23
23
|
`which #{tool}`.size > 0
|
@@ -65,9 +65,9 @@ module Vmail
|
|
65
65
|
# require after the working dir is set
|
66
66
|
require 'vmail/imap_client'
|
67
67
|
|
68
|
-
drb_uri = begin
|
68
|
+
drb_uri = begin
|
69
69
|
Vmail::ImapClient.daemon config
|
70
|
-
rescue
|
70
|
+
rescue
|
71
71
|
puts "Failure:", $!
|
72
72
|
exit(1)
|
73
73
|
end
|
@@ -79,14 +79,16 @@ module Vmail
|
|
79
79
|
server.select_mailbox mailbox
|
80
80
|
|
81
81
|
STDERR.puts "Mailbox: #{mailbox}"
|
82
|
-
STDERR.puts "Query: #{query.inspect}"
|
82
|
+
STDERR.puts "Query: #{query.inspect}"
|
83
83
|
STDERR.puts "Query String: #{String.shellescape(query_string)}"
|
84
|
-
|
84
|
+
|
85
85
|
buffer_file = "vmailbuffer"
|
86
86
|
# invoke vim
|
87
87
|
vimscript = File.expand_path("../vmail.vim", __FILE__)
|
88
88
|
vimopts = config['vim_opts']
|
89
|
-
|
89
|
+
$drb_uri = drb_uri
|
90
|
+
server_name = "VMAIL:#{ config['username'] }"
|
91
|
+
vim_command = "DRB_URI=#{drb_uri} VMAIL_CONTACTS_FILE=#{contacts_file} VMAIL_MAILBOX=#{String.shellescape(mailbox)} VMAIL_QUERY=\"#{query_string}\" #{vim} --servername #{ server_name } -S #{vimscript} -c '#{vimopts}' #{buffer_file}"
|
90
92
|
STDERR.puts vim_command
|
91
93
|
STDERR.puts "Using buffer file: #{buffer_file}"
|
92
94
|
File.open(buffer_file, "w") do |file|
|
@@ -102,9 +104,9 @@ module Vmail
|
|
102
104
|
|
103
105
|
File.delete(buffer_file)
|
104
106
|
|
105
|
-
STDERR.puts "Closing imap connection"
|
107
|
+
STDERR.puts "Closing imap connection"
|
106
108
|
begin
|
107
|
-
Timeout::timeout(10) do
|
109
|
+
Timeout::timeout(10) do
|
108
110
|
$gmail.close
|
109
111
|
end
|
110
112
|
rescue Timeout::Error
|
@@ -129,10 +131,10 @@ module Vmail
|
|
129
131
|
end
|
130
132
|
|
131
133
|
def parse_query
|
132
|
-
if ARGV[0] =~ /^\d+/
|
134
|
+
if ARGV[0] =~ /^\d+/
|
133
135
|
ARGV.shift
|
134
136
|
end
|
135
|
-
mailbox = ARGV.shift || 'INBOX'
|
137
|
+
mailbox = ARGV.shift || 'INBOX'
|
136
138
|
query = Vmail::Query.parse(ARGV)
|
137
139
|
[mailbox, query]
|
138
140
|
end
|
data/lib/vmail.vim
CHANGED
@@ -282,7 +282,7 @@ function! s:mark_as_read_unread(read) range
|
|
282
282
|
setlocal nomodifiable
|
283
283
|
write
|
284
284
|
redraw
|
285
|
-
echom nummsgs ." conversation(s) have been marked as unread."
|
285
|
+
echom nummsgs ." conversation(s) have been marked as " . (a:read ? "read" : "unread") . "."
|
286
286
|
endfunction
|
287
287
|
|
288
288
|
function! s:toggle_star() range
|
@@ -684,6 +684,42 @@ function! s:send_message()
|
|
684
684
|
redraw
|
685
685
|
endfunction
|
686
686
|
|
687
|
+
" --------------------------------------------------------------------------------
|
688
|
+
" Update message list with new emails.
|
689
|
+
|
690
|
+
func! UPDATE_MESSAGE_LIST(filename)
|
691
|
+
if s:mailbox == 'INBOX'
|
692
|
+
if bufnr('%') == s:listbufnr
|
693
|
+
call s:update_and_redraw_message_list(a:filename)
|
694
|
+
|
695
|
+
" If current_message is open with message list in another split.
|
696
|
+
elseif bufname('%') == s:message_bufname && index(tabpagebuflist(), s:listbufnr) >= 0
|
697
|
+
let message_bufnr = bufnr('%')
|
698
|
+
|
699
|
+
" Switch to message list window and update it.
|
700
|
+
while bufnr('%') != s:listbufnr | wincmd w | endwhile
|
701
|
+
call s:update_and_redraw_message_list(a:filename)
|
702
|
+
|
703
|
+
while bufnr('%') != message_bufnr | wincmd w | endwhile
|
704
|
+
else
|
705
|
+
call s:update_message_list(a:filename)
|
706
|
+
endif
|
707
|
+
endif
|
708
|
+
endfunc
|
709
|
+
|
710
|
+
func! s:update_and_redraw_message_list(filename)
|
711
|
+
call s:update_message_list(a:filename)
|
712
|
+
edit!
|
713
|
+
redraw!
|
714
|
+
endfunc
|
715
|
+
|
716
|
+
func! s:update_message_list(filename)
|
717
|
+
let newer_contents = readfile(a:filename)
|
718
|
+
let older_contents = readfile(s:listbufname)
|
719
|
+
let updated_contents = extend(newer_contents, older_contents)
|
720
|
+
call writefile(updated_contents, s:listbufname)
|
721
|
+
endfunc
|
722
|
+
|
687
723
|
" --------------------------------------------------------------------------------
|
688
724
|
|
689
725
|
" call from inside message window with <Leader>h
|
data/lib/vmail/address_quoter.rb
CHANGED
@@ -16,17 +16,17 @@ module Vmail
|
|
16
16
|
savebin = part + ", "
|
17
17
|
end
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
#Quote the names
|
21
|
-
addrs.map { |addr|
|
21
|
+
addrs.map { |addr|
|
22
22
|
# a little hackish
|
23
23
|
if addr =~ /"/
|
24
24
|
addr
|
25
25
|
else
|
26
|
-
addr.gsub(/^(.*) (<.*)/, '"\1" \2')
|
26
|
+
addr.gsub(/^(.*) (<.*)/, '"\1" \2')
|
27
27
|
end
|
28
28
|
}.join(', ')
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
end
|
32
32
|
end
|
@@ -11,7 +11,7 @@ class ContactsExtractor
|
|
11
11
|
@imap = Net::IMAP.new('imap.gmail.com', 993, true, nil, false)
|
12
12
|
puts @imap.login(@username, @password)
|
13
13
|
yield @imap
|
14
|
-
@imap.close
|
14
|
+
@imap.close
|
15
15
|
@imap.disconnect
|
16
16
|
end
|
17
17
|
|
@@ -31,10 +31,10 @@ class ContactsExtractor
|
|
31
31
|
recipients = fetch_data.attr["ENVELOPE"].to
|
32
32
|
next unless recipients
|
33
33
|
recipients.each do |address_struct|
|
34
|
-
email = [address_struct.mailbox, address_struct.host].join('@')
|
34
|
+
email = [address_struct.mailbox, address_struct.host].join('@')
|
35
35
|
name = address_struct.name
|
36
|
-
if name
|
37
|
-
name = Mail::Encodings.unquote_and_convert_to(name, 'UTF-8')
|
36
|
+
if name
|
37
|
+
name = Mail::Encodings.unquote_and_convert_to(name, 'UTF-8')
|
38
38
|
yield %Q("#{name}" <#{email}>)
|
39
39
|
else
|
40
40
|
yield email
|
@@ -46,7 +46,7 @@ class ContactsExtractor
|
|
46
46
|
|
47
47
|
def set_mailbox_prefix
|
48
48
|
mailboxes = ((@imap.list("[#@prefix]/", "%") || []) + (@imap.list("", "*")) || []).map {|struct| struct.name}
|
49
|
-
@prefix = mailboxes.detect {|m| m =~ /^\[Google Mail\]/} ? "Google Mail" : "Gmail"
|
49
|
+
@prefix = mailboxes.detect {|m| m =~ /^\[Google Mail\]/} ? "Google Mail" : "Gmail"
|
50
50
|
end
|
51
51
|
end
|
52
52
|
end
|
data/lib/vmail/database.rb
CHANGED
@@ -5,8 +5,8 @@ require 'sequel'
|
|
5
5
|
CREATE_TABLE_SCRIPT = File.expand_path("../../../db/create.sql", __FILE__)
|
6
6
|
print "Checking vmail.db version... "
|
7
7
|
db = Sequel.connect 'sqlite://vmail.db'
|
8
|
-
if db.tables.include?(:version) &&
|
9
|
-
(r = db[:version].first) &&
|
8
|
+
if db.tables.include?(:version) &&
|
9
|
+
(r = db[:version].first) &&
|
10
10
|
r[:vmail_version] != Vmail::VERSION
|
11
11
|
|
12
12
|
print "Vmail database version is outdated. Recreating.\n"
|
@@ -17,7 +17,7 @@ module Vmail
|
|
17
17
|
log "Deleting uid_set: #{uid_set.inspect}"
|
18
18
|
decrement_max_seqno(uid_set.size)
|
19
19
|
# for delete, do in a separate thread because deletions are slow
|
20
|
-
spawn_thread_if_tty do
|
20
|
+
spawn_thread_if_tty do
|
21
21
|
unless @mailbox == mailbox_aliases['trash']
|
22
22
|
log "imap.uid_copy #{uid_set.inspect} to #{mailbox_aliases['trash']}"
|
23
23
|
log @imap.uid_copy(uid_set, mailbox_aliases['trash'])
|
@@ -27,12 +27,12 @@ module Vmail
|
|
27
27
|
reload_mailbox
|
28
28
|
clear_cached_message
|
29
29
|
end
|
30
|
-
elsif flg == 'spam' || flg == mailbox_aliases['spam']
|
30
|
+
elsif flg == 'spam' || flg == mailbox_aliases['spam']
|
31
31
|
log "Marking as spam uid_set: #{uid_set.inspect}"
|
32
32
|
decrement_max_seqno(uid_set.size)
|
33
|
-
spawn_thread_if_tty do
|
33
|
+
spawn_thread_if_tty do
|
34
34
|
log "imap.uid_copy #{uid_set.inspect} to #{mailbox_aliases['spam']}"
|
35
|
-
log @imap.uid_copy(uid_set, mailbox_aliases['spam'])
|
35
|
+
log @imap.uid_copy(uid_set, mailbox_aliases['spam'])
|
36
36
|
log "imap.uid_store #{uid_set.inspect} #{action} [:Deleted]"
|
37
37
|
log @imap.uid_store(uid_set, action, [:Deleted])
|
38
38
|
reload_mailbox
|
@@ -61,7 +61,7 @@ module Vmail
|
|
61
61
|
end
|
62
62
|
create_if_necessary mailbox
|
63
63
|
log "Moving uid_set: #{uid_set.inspect} to #{mailbox}"
|
64
|
-
spawn_thread_if_tty do
|
64
|
+
spawn_thread_if_tty do
|
65
65
|
log @imap.uid_copy(uid_set, mailbox)
|
66
66
|
log @imap.uid_store(uid_set, '+FLAGS', [:Deleted])
|
67
67
|
reload_mailbox
|
@@ -79,7 +79,7 @@ module Vmail
|
|
79
79
|
end
|
80
80
|
create_if_necessary mailbox
|
81
81
|
log "Copying #{uid_set.inspect} to #{mailbox}"
|
82
|
-
spawn_thread_if_tty do
|
82
|
+
spawn_thread_if_tty do
|
83
83
|
log @imap.uid_copy(uid_set, mailbox)
|
84
84
|
log "Copied uid_set #{uid_set.inspect} to #{mailbox}"
|
85
85
|
end
|
data/lib/vmail/helpers.rb
CHANGED
data/lib/vmail/imap_client.rb
CHANGED
@@ -6,6 +6,7 @@ require 'mail'
|
|
6
6
|
require 'net/imap'
|
7
7
|
require 'time'
|
8
8
|
require 'logger'
|
9
|
+
require 'tempfile'
|
9
10
|
require 'vmail/helpers'
|
10
11
|
require 'vmail/address_quoter'
|
11
12
|
require 'vmail/database'
|
@@ -32,8 +33,8 @@ module Vmail
|
|
32
33
|
#load user-specified value for from field
|
33
34
|
@from = config['from'] || config['username']
|
34
35
|
@name = config['name']
|
35
|
-
@signature = config['signature']
|
36
|
-
@signature_script = config['signature_script']
|
36
|
+
@signature = config['signature']
|
37
|
+
@signature_script = config['signature_script']
|
37
38
|
@always_cc = config['always_cc']
|
38
39
|
@always_bcc = config['always_bcc']
|
39
40
|
@mailbox = nil
|
@@ -49,7 +50,7 @@ module Vmail
|
|
49
50
|
@authentication = config['authentication'] || 'plain'
|
50
51
|
@width = 100
|
51
52
|
|
52
|
-
@date_formatter_this_year = config['date_format'] || '%b %d %I:%M%P'
|
53
|
+
@date_formatter_this_year = config['date_format'] || '%b %d %I:%M%P'
|
53
54
|
@date_formatter_prev_years = config['date_format_previous_years'] || '%b %d %Y'
|
54
55
|
@date_width = DateTime.parse("12/12/2012 12:12:12").strftime(@date_formatter_this_year).length
|
55
56
|
current_message = nil
|
@@ -60,7 +61,7 @@ module Vmail
|
|
60
61
|
@imap = Net::IMAP.new(@imap_server, @imap_port, true, nil, false)
|
61
62
|
log @imap.login(@username, @password)
|
62
63
|
list_mailboxes # prefetch mailbox list
|
63
|
-
rescue
|
64
|
+
rescue
|
64
65
|
puts "VMAIL_ERROR: #{[$!.message, $!.backtrace].join("\n")}"
|
65
66
|
end
|
66
67
|
|
@@ -86,7 +87,7 @@ module Vmail
|
|
86
87
|
mailbox = mailbox_aliases[mailbox]
|
87
88
|
end
|
88
89
|
log "Selecting mailbox #{mailbox.inspect}"
|
89
|
-
reconnect_if_necessary(30) do
|
90
|
+
reconnect_if_necessary(30) do
|
90
91
|
log @imap.select(Net::IMAP.encode_utf7(mailbox))
|
91
92
|
end
|
92
93
|
log "Done"
|
@@ -106,7 +107,7 @@ module Vmail
|
|
106
107
|
select_mailbox(@mailbox, true)
|
107
108
|
end
|
108
109
|
|
109
|
-
# TODO no need for this if all shown messages are stored in SQLITE3
|
110
|
+
# TODO no need for this if all shown messages are stored in SQLITE3
|
110
111
|
# and keyed by UID.
|
111
112
|
def clear_cached_message
|
112
113
|
return unless STDIN.tty?
|
@@ -142,23 +143,23 @@ module Vmail
|
|
142
143
|
|
143
144
|
def prime_connection
|
144
145
|
return if @ids.nil? || @ids.empty?
|
145
|
-
reconnect_if_necessary(4) do
|
146
|
+
reconnect_if_necessary(4) do
|
146
147
|
# this is just to prime the IMAP connection
|
147
|
-
# It's necessary for some reason before update and deliver.
|
148
|
+
# It's necessary for some reason before update and deliver.
|
148
149
|
log "Priming connection"
|
149
150
|
res = @imap.fetch(@ids[-1], ["ENVELOPE"])
|
150
151
|
if res.nil?
|
151
152
|
# just go ahead, just log
|
152
153
|
log "Priming connection didn't work, connection seems broken, but still going ahead..."
|
153
154
|
end
|
154
|
-
end
|
155
|
+
end
|
155
156
|
end
|
156
157
|
|
157
158
|
def list_mailboxes
|
158
159
|
log 'loading mailboxes...'
|
159
160
|
@mailboxes ||= (@imap.list("", "*") || []).
|
160
161
|
select {|struct| struct.attr.none? {|a| a == :Noselect} }.
|
161
|
-
map {|struct|
|
162
|
+
map {|struct|
|
162
163
|
Net::IMAP.decode_utf7(struct.name)
|
163
164
|
}.uniq
|
164
165
|
@mailboxes.delete("INBOX")
|
@@ -217,7 +218,7 @@ module Vmail
|
|
217
218
|
# set a new range filter
|
218
219
|
# this may generate a negative rane, e.g., "19893:19992" but that seems harmless
|
219
220
|
update_query[0] = "#{old_num_messages}:#{@num_messages}"
|
220
|
-
ids = reconnect_if_necessary {
|
221
|
+
ids = reconnect_if_necessary {
|
221
222
|
log "Search #update_query"
|
222
223
|
@imap.search(Vmail::Query.args2string(update_query))
|
223
224
|
}
|
@@ -228,12 +229,24 @@ module Vmail
|
|
228
229
|
self.max_seqno = ids.max
|
229
230
|
log "- setting max_seqno to #{self.max_seqno}"
|
230
231
|
log "- new uids found: #{new_ids.inspect}"
|
232
|
+
update_message_list(new_ids) unless new_ids.empty?
|
231
233
|
new_ids
|
232
234
|
end
|
233
235
|
|
236
|
+
def update_message_list(new_ids)
|
237
|
+
new_emails = DRbObject.new_with_uri($drb_uri).update
|
238
|
+
return if new_emails.empty?
|
239
|
+
|
240
|
+
tempfile_path = Tempfile.new('vmail-').path
|
241
|
+
File.open(tempfile_path, 'w') { |file| file.write(new_emails) }
|
242
|
+
server_name = "VMAIL:#{ @username }"
|
243
|
+
|
244
|
+
system(%[vim --servername #{ server_name } --remote-expr 'UPDATE_MESSAGE_LIST("#{ tempfile_path }")'])
|
245
|
+
end
|
246
|
+
|
234
247
|
def update
|
235
248
|
prime_connection
|
236
|
-
new_ids = check_for_new_messages
|
249
|
+
new_ids = check_for_new_messages
|
237
250
|
if !new_ids.empty?
|
238
251
|
@ids = @ids + new_ids
|
239
252
|
message_ids = fetch_and_cache_headers(new_ids)
|
@@ -260,9 +273,9 @@ module Vmail
|
|
260
273
|
with_more_message_line(res)
|
261
274
|
end
|
262
275
|
|
263
|
-
def spawn_thread_if_tty(&block)
|
276
|
+
def spawn_thread_if_tty(&block)
|
264
277
|
if STDIN.tty?
|
265
|
-
Thread.new do
|
278
|
+
Thread.new do
|
266
279
|
reconnect_if_necessary(10, &block)
|
267
280
|
end
|
268
281
|
else
|
@@ -275,7 +288,7 @@ module Vmail
|
|
275
288
|
if !current_mailboxes.include?(mailbox)
|
276
289
|
log "Current mailboxes: #{current_mailboxes.inspect}"
|
277
290
|
log "Creating mailbox #{mailbox}"
|
278
|
-
log @imap.create(mailbox)
|
291
|
+
log @imap.create(mailbox)
|
279
292
|
@mailboxes = nil # force reload ...
|
280
293
|
list_mailboxes
|
281
294
|
end
|
@@ -338,7 +351,7 @@ module Vmail
|
|
338
351
|
subject = "Fwd: #{subject}"
|
339
352
|
end
|
340
353
|
|
341
|
-
new_message_template(subject, false) +
|
354
|
+
new_message_template(subject, false) +
|
342
355
|
"\n---------- Forwarded message ----------\n" +
|
343
356
|
original_body + signature
|
344
357
|
end
|
@@ -447,7 +460,7 @@ EOF
|
|
447
460
|
log "Open_html_part"
|
448
461
|
log current_mail.parts.inspect
|
449
462
|
multipart = current_mail.parts.detect {|part| part.multipart?}
|
450
|
-
html_part = if multipart
|
463
|
+
html_part = if multipart
|
451
464
|
multipart.parts.detect {|part| part.header["Content-Type"].to_s =~ /text\/html/}
|
452
465
|
elsif ! current_mail.parts.empty?
|
453
466
|
current_mail.parts.detect {|part| part.header["Content-Type"].to_s =~ /text\/html/}
|
@@ -465,7 +478,7 @@ EOF
|
|
465
478
|
@width = width.to_i
|
466
479
|
log "Setting window width to #{width}"
|
467
480
|
end
|
468
|
-
|
481
|
+
|
469
482
|
def smtp_settings
|
470
483
|
[:smtp, {:address => @smtp_server,
|
471
484
|
:port => @smtp_port,
|
@@ -499,7 +512,7 @@ EOF
|
|
499
512
|
close
|
500
513
|
log(revive_connection)
|
501
514
|
# hope this isn't an endless loop
|
502
|
-
reconnect_if_necessary do
|
515
|
+
reconnect_if_necessary do
|
503
516
|
block.call
|
504
517
|
end
|
505
518
|
rescue
|
@@ -525,11 +538,11 @@ EOF
|
|
525
538
|
end
|
526
539
|
end
|
527
540
|
|
528
|
-
trap("INT") {
|
541
|
+
trap("INT") {
|
529
542
|
require 'timeout'
|
530
|
-
puts "Closing imap connection"
|
543
|
+
puts "Closing imap connection"
|
531
544
|
begin
|
532
|
-
#Timeout::timeout(2) do
|
545
|
+
#Timeout::timeout(2) do
|
533
546
|
# just try to quit
|
534
547
|
# $gmail.close
|
535
548
|
#end
|
data/lib/vmail/inbox_poller.rb
CHANGED
@@ -3,9 +3,8 @@ require "vmail/imap_client"
|
|
3
3
|
module Vmail
|
4
4
|
class InboxPoller < ImapClient
|
5
5
|
|
6
|
-
|
7
6
|
# This is a second IMAP client operating in a separate process
|
8
|
-
|
7
|
+
|
9
8
|
def start_polling
|
10
9
|
n = [`which notify-send`.chomp, `which growlnotify`.chomp].detect {|c| c != ''}
|
11
10
|
if n
|
@@ -20,7 +19,7 @@ module Vmail
|
|
20
19
|
log "No notification tool detected. INBOX polling aborted."
|
21
20
|
return
|
22
21
|
end
|
23
|
-
|
22
|
+
|
24
23
|
sleep 30
|
25
24
|
log "INBOX POLLER: started polling"
|
26
25
|
@mailboxes.unshift "INBOX"
|
@@ -34,12 +33,88 @@ module Vmail
|
|
34
33
|
end
|
35
34
|
|
36
35
|
def update
|
37
|
-
new_ids = check_for_new_messages
|
36
|
+
new_ids = check_for_new_messages
|
38
37
|
if !new_ids.empty?
|
39
38
|
@ids = @ids + new_ids
|
40
|
-
|
41
|
-
|
42
|
-
|
39
|
+
|
40
|
+
notification_title = "Vmail: "
|
41
|
+
notification_body = ""
|
42
|
+
|
43
|
+
if new_ids.size == 1
|
44
|
+
# If there is a single email, message is more descriptive about the
|
45
|
+
# received email.
|
46
|
+
#
|
47
|
+
# Example:
|
48
|
+
#
|
49
|
+
# (title) Vmail: Colin Sullivan
|
50
|
+
# (body) New Pull request received!
|
51
|
+
#
|
52
|
+
log "single new message received!"
|
53
|
+
new_message = uncached_headers(new_ids)[0]
|
54
|
+
|
55
|
+
# Extract just sender's name from sender field
|
56
|
+
notification_title += new_message[:sender].gsub(/\<.*\>/, "").strip()
|
57
|
+
|
58
|
+
# Truncate message subject if necessary
|
59
|
+
if new_message[:subject].length > 128
|
60
|
+
# Extract first 128 characters from subject of email
|
61
|
+
notification_body += new_message[:subject][0..128] + "..."
|
62
|
+
else
|
63
|
+
notification_body += new_message[:subject]
|
64
|
+
end
|
65
|
+
|
66
|
+
else
|
67
|
+
# If there are multiple new messages, notification is just a brief
|
68
|
+
# listing.
|
69
|
+
#
|
70
|
+
# Example:
|
71
|
+
#
|
72
|
+
# (title) Vmail: 3 new messages
|
73
|
+
# (body) Colin Sullivan: New Pull request rec...
|
74
|
+
# Henry Cowell: I am back from the dead!
|
75
|
+
# ...
|
76
|
+
#
|
77
|
+
log "multiple new messages received!"
|
78
|
+
|
79
|
+
notification_title += new_ids.size.to_s() + " new messages"
|
80
|
+
|
81
|
+
# for each message
|
82
|
+
for i in 0...new_ids.size
|
83
|
+
new_message = uncached_headers(new_ids)[i]
|
84
|
+
|
85
|
+
# Create message line
|
86
|
+
message_line = ""
|
87
|
+
|
88
|
+
# Extract just sender's name from sender field
|
89
|
+
message_line += new_message[:sender].gsub(/\<.*\>/, "").strip()
|
90
|
+
|
91
|
+
# Extract subject
|
92
|
+
message_line += ": " + new_message[:subject]
|
93
|
+
|
94
|
+
# Concatenate line if necessary
|
95
|
+
if message_line.length > 32
|
96
|
+
message_line = message_line[0...29] + "..."
|
97
|
+
end
|
98
|
+
|
99
|
+
# Add to notification body
|
100
|
+
notification_body += message_line + "\n"
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
# Concatenate entire notification body if necessary
|
105
|
+
if notification_body.length > 128
|
106
|
+
notification_body = notification_body[0...125] + "..."
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
# Remove any '<>' characters from notification just incase, libnotify
|
112
|
+
# can't print '<'
|
113
|
+
notification_title = notification_title.tr('<>', '')
|
114
|
+
notification_body = notification_body.tr('<>', '')
|
115
|
+
|
116
|
+
@notifier.call notification_title, notification_body
|
117
|
+
|
43
118
|
end
|
44
119
|
rescue
|
45
120
|
log "VMAIL_ERROR: #{[$!.message, $!.backtrace].join("\n")}"
|
@@ -48,10 +123,10 @@ module Vmail
|
|
48
123
|
# doesn't try to access Sequel / sqlite3
|
49
124
|
def uncached_headers(id_set)
|
50
125
|
log "Fetching headers for #{id_set.size} messages"
|
51
|
-
results = reconnect_if_necessary do
|
126
|
+
results = reconnect_if_necessary do
|
52
127
|
@imap.fetch(id_set, ["FLAGS", "ENVELOPE", "RFC822.SIZE", "UID"])
|
53
128
|
end
|
54
|
-
results.reverse.map do |x|
|
129
|
+
results.reverse.map do |x|
|
55
130
|
envelope = x.attr["ENVELOPE"]
|
56
131
|
message_id = envelope.message_id
|
57
132
|
subject = Mail::Encodings.unquote_and_convert_to((envelope.subject || ''), 'UTF-8')
|
@@ -32,13 +32,13 @@ module Vmail
|
|
32
32
|
|
33
33
|
# helper method
|
34
34
|
def find_text_part2(part, content_type)
|
35
|
-
if part.multipart?
|
35
|
+
if part.multipart?
|
36
36
|
part.parts.
|
37
37
|
map {|p| find_text_part2(p, p.content_type)}.
|
38
38
|
compact.
|
39
39
|
select {|p| !p.attachment?}.
|
40
40
|
first
|
41
|
-
elsif content_type =~ %r[^text/plain] ||
|
41
|
+
elsif content_type =~ %r[^text/plain] ||
|
42
42
|
content_type =~ %r[text/plain] ||
|
43
43
|
content_type =~ %r[message/rfc]
|
44
44
|
part
|
@@ -47,18 +47,18 @@ module Vmail
|
|
47
47
|
|
48
48
|
def format_part(part)
|
49
49
|
if part && part.respond_to?(:header)
|
50
|
-
case part.header["Content-Type"].to_s
|
50
|
+
case part.header["Content-Type"].to_s
|
51
51
|
when /text\/html/
|
52
|
-
format_html_body(part)
|
52
|
+
format_html_body(part)
|
53
53
|
when /text\/plain/
|
54
|
-
format_text_body(part)
|
54
|
+
format_text_body(part)
|
55
55
|
when /message\/rfc/
|
56
56
|
m = Mail.new(part.body.decoded)
|
57
57
|
plaintext_part(m)
|
58
58
|
else # just format_text on it anyway
|
59
|
-
format_text_body(part)
|
59
|
+
format_text_body(part)
|
60
60
|
end
|
61
|
-
else
|
61
|
+
else
|
62
62
|
part.decoded.gsub("\r", '')
|
63
63
|
end
|
64
64
|
rescue
|
@@ -73,7 +73,7 @@ module Vmail
|
|
73
73
|
# depend on VMAIL_HTML_PART_READER
|
74
74
|
# variable
|
75
75
|
def format_html_body(part)
|
76
|
-
html_tool = ENV['VMAIL_HTML_PART_READER']
|
76
|
+
html_tool = ENV['VMAIL_HTML_PART_READER']
|
77
77
|
html = part.body.decoded.gsub("\r", '')
|
78
78
|
stdin, stdout, stderr = Open3.popen3(html_tool)
|
79
79
|
stdin.puts html
|
@@ -107,10 +107,10 @@ module Vmail
|
|
107
107
|
|
108
108
|
def utf8(string, this_encoding = encoding)
|
109
109
|
return '' unless string
|
110
|
-
out = if this_encoding && this_encoding.upcase != 'UTF-8'
|
110
|
+
out = if this_encoding && this_encoding.upcase != 'UTF-8'
|
111
111
|
string.encode!('utf-8', this_encoding, undef: :replace, invalid: :replace)
|
112
|
-
elsif this_encoding.upcase == 'UTF-8'
|
113
|
-
string
|
112
|
+
elsif this_encoding.upcase == 'UTF-8'
|
113
|
+
string
|
114
114
|
else
|
115
115
|
# assume UTF-8 and convert to ascii
|
116
116
|
string.encode!('us-ascii', 'utf-8', undef: :replace, invalid: :replace)
|
data/lib/vmail/options.rb
CHANGED
@@ -20,10 +20,10 @@ module Vmail
|
|
20
20
|
|
21
21
|
def parse(argv)
|
22
22
|
OptionParser.new do |opts|
|
23
|
-
opts.banner = "Usage: vmail [ options ] [ limit ] [ imap search query ]"
|
23
|
+
opts.banner = "Usage: vmail [ options ] [ limit ] [ imap search query ]"
|
24
24
|
opts.separator ""
|
25
25
|
opts.separator "Specific options:"
|
26
|
-
opts.on("-g[n]", "--getcontacts[n]", Integer, "Generate contacts file. n is number of emails to scan (default 500).") do |n|
|
26
|
+
opts.on("-g[n]", "--getcontacts[n]", Integer, "Generate contacts file. n is number of emails to scan (default 500).") do |n|
|
27
27
|
@get_contacts = true
|
28
28
|
@max_messages_to_scan = n || 500
|
29
29
|
end
|
@@ -46,7 +46,7 @@ module Vmail
|
|
46
46
|
else
|
47
47
|
STDERR.puts <<EOF
|
48
48
|
|
49
|
-
Missing config file!
|
49
|
+
Missing config file!
|
50
50
|
|
51
51
|
#{INSTRUCTIONS}
|
52
52
|
EOF
|
@@ -75,16 +75,16 @@ EOF
|
|
75
75
|
require 'vmail/contacts_extractor'
|
76
76
|
extractor = ContactsExtractor.new(@config['username'], @config['password'])
|
77
77
|
File.open(DEFAULT_CONTACTS_FILENAME, 'w') do |file|
|
78
|
-
extractor.extract(@max_messages_to_scan) do |address|
|
78
|
+
extractor.extract(@max_messages_to_scan) do |address|
|
79
79
|
STDERR.print '.'
|
80
80
|
file.puts(address.strip)
|
81
|
-
STDERR.flush
|
81
|
+
STDERR.flush
|
82
82
|
end
|
83
83
|
end
|
84
84
|
STDERR.print "\n"
|
85
85
|
puts "Saved file to #{DEFAULT_CONTACTS_FILENAME}"
|
86
86
|
puts "Sorting address..."
|
87
|
-
cmd = "sort #{DEFAULT_CONTACTS_FILENAME} | uniq > vmail-tmp.txt"
|
87
|
+
cmd = "sort #{DEFAULT_CONTACTS_FILENAME} | uniq > vmail-tmp.txt"
|
88
88
|
cmd2 = "mv vmail-tmp.txt #{DEFAULT_CONTACTS_FILENAME}"
|
89
89
|
`#{cmd}`
|
90
90
|
`#{cmd2}`
|
data/lib/vmail/query.rb
CHANGED
@@ -22,17 +22,17 @@ module Vmail
|
|
22
22
|
sender = current_message.sender
|
23
23
|
reply_quote_header = date ? "On #{date.strftime('%a, %b %d, %Y at %I:%M %p')}, #{sender} wrote:\n\n" : "#{sender} wrote:\n"
|
24
24
|
|
25
|
-
reply_body = reply_quote_header +
|
25
|
+
reply_body = reply_quote_header +
|
26
26
|
( current_message.plaintext.split(/^-+$/,2)[1].strip.gsub(/^(?=>)/, ">").gsub(/^(?!>)/, "> ") )
|
27
27
|
|
28
28
|
{
|
29
29
|
'references' => current_message.message_id,
|
30
30
|
# set 'from' to user-specified value
|
31
|
-
'from' => "#@name <#@from>",
|
32
|
-
'to' => reply_recipient,
|
33
|
-
'cc' => reply_cc,
|
31
|
+
'from' => "#@name <#@from>",
|
32
|
+
'to' => reply_recipient,
|
33
|
+
'cc' => reply_cc,
|
34
34
|
'bcc' => @always_bcc,
|
35
|
-
'subject' => reply_subject,
|
35
|
+
'subject' => reply_subject,
|
36
36
|
'body' => reply_body
|
37
37
|
}
|
38
38
|
rescue
|
@@ -52,12 +52,12 @@ module Vmail
|
|
52
52
|
[]
|
53
53
|
end
|
54
54
|
xs = xs.select {|x|
|
55
|
-
email = (x[/<([^>]+)>/, 1] || x)
|
55
|
+
email = (x[/<([^>]+)>/, 1] || x)
|
56
56
|
email !~ /#{reply_recipient}/ \
|
57
57
|
&& email !~ /#@username/ \
|
58
|
-
&& (@always_cc ? (email !~ /#{@always_cc}/) : true)
|
58
|
+
&& (@always_cc ? (email !~ /#{@always_cc}/) : true)
|
59
59
|
}
|
60
|
-
if @always_cc
|
60
|
+
if @always_cc
|
61
61
|
xs << @always_cc
|
62
62
|
end
|
63
63
|
xs.uniq.select {|x| x != reply_recipient }.join(', ')
|
data/lib/vmail/searching.rb
CHANGED
@@ -3,7 +3,7 @@ module Vmail
|
|
3
3
|
# The main function called by the client to retrieve messages
|
4
4
|
def search(query)
|
5
5
|
log "#search: #{query.inspect}"
|
6
|
-
@query = Vmail::Query.parse(query)
|
6
|
+
@query = Vmail::Query.parse(query)
|
7
7
|
# customizable @limit is Deprecated
|
8
8
|
@limit = 100
|
9
9
|
|
@@ -13,10 +13,10 @@ module Vmail
|
|
13
13
|
@ids = reconnect_if_necessary(180) do # timeout of 3 minutes
|
14
14
|
@imap.search(query_string)
|
15
15
|
end
|
16
|
-
@start_index = [@ids.size - @limit, 0].max
|
16
|
+
@start_index = [@ids.size - @limit, 0].max
|
17
17
|
else
|
18
18
|
# set the target range to the whole set, unless it is too big
|
19
|
-
@start_index = [@num_messages - @limit, 0].max
|
19
|
+
@start_index = [@num_messages - @limit, 0].max
|
20
20
|
@query.unshift "#{@start_index + 1}:#{@num_messages}"
|
21
21
|
query_string = Vmail::Query.args2string(@query)
|
22
22
|
log "Query: #{query_string.inspect}"
|
@@ -30,7 +30,7 @@ module Vmail
|
|
30
30
|
end
|
31
31
|
|
32
32
|
self.max_seqno = @ids[-1] # this is a instance var
|
33
|
-
log "- Query got #{@ids.size} results; max seqno: #{self.max_seqno}"
|
33
|
+
log "- Query got #{@ids.size} results; max seqno: #{self.max_seqno}"
|
34
34
|
clear_cached_message
|
35
35
|
|
36
36
|
select_ids = (search_query? ? @ids[[-@limit, 0].max, @limit] : @ids)
|
@@ -51,7 +51,7 @@ module Vmail
|
|
51
51
|
rescue
|
52
52
|
log "ERROR:\n#{$!.inspect}\n#{$!.backtrace.join("\n")}"
|
53
53
|
"Sorry there was an error. Please check vmail.log."
|
54
|
-
end
|
54
|
+
end
|
55
55
|
|
56
56
|
def search_query?
|
57
57
|
x = @query[-1] != 'all'
|
data/lib/vmail/send_options.rb
CHANGED
@@ -5,7 +5,7 @@ module Vmail
|
|
5
5
|
|
6
6
|
def parse(argv)
|
7
7
|
OptionParser.new do |opts|
|
8
|
-
opts.banner = "Usage: vmailsend"
|
8
|
+
opts.banner = "Usage: vmailsend"
|
9
9
|
opts.separator ""
|
10
10
|
opts.separator "Specific options:"
|
11
11
|
opts.on("-c", "--config path", String, "Path to config file") do |config_file|
|
@@ -30,7 +30,7 @@ module Vmail
|
|
30
30
|
else
|
31
31
|
puts <<EOF
|
32
32
|
|
33
|
-
Missing config file!
|
33
|
+
Missing config file!
|
34
34
|
|
35
35
|
#{INSTRUCTIONS}
|
36
36
|
EOF
|
@@ -3,7 +3,7 @@ module Vmail
|
|
3
3
|
module ShowingHeaders
|
4
4
|
|
5
5
|
def get_message_headers(message_ids)
|
6
|
-
messages = message_ids.map {|message_id|
|
6
|
+
messages = message_ids.map {|message_id|
|
7
7
|
m = Message[message_id]
|
8
8
|
if m.nil?
|
9
9
|
raise "Message #{message_id} not found"
|
@@ -16,10 +16,10 @@ module Vmail
|
|
16
16
|
|
17
17
|
def fetch_and_cache_headers(id_set)
|
18
18
|
log "Fetching headers for #{id_set.size} messages"
|
19
|
-
results = reconnect_if_necessary do
|
19
|
+
results = reconnect_if_necessary do
|
20
20
|
@imap.fetch(id_set, ["FLAGS", "ENVELOPE", "RFC822.SIZE", "UID"])
|
21
21
|
end
|
22
|
-
results.reverse.map do |x|
|
22
|
+
results.reverse.map do |x|
|
23
23
|
envelope = x.attr["ENVELOPE"]
|
24
24
|
message_id = envelope.message_id
|
25
25
|
begin
|
@@ -60,10 +60,10 @@ module Vmail
|
|
60
60
|
def extract_address(address_struct)
|
61
61
|
address = if address_struct.nil?
|
62
62
|
"Unknown"
|
63
|
-
else
|
64
|
-
email = [ (address_struct.mailbox ? Mail::Encodings.unquote_and_convert_to(address_struct.mailbox, 'UTF-8') : ""),
|
63
|
+
else
|
64
|
+
email = [ (address_struct.mailbox ? Mail::Encodings.unquote_and_convert_to(address_struct.mailbox, 'UTF-8') : ""),
|
65
65
|
(address_struct.host ? Mail::Encodings.unquote_and_convert_to(address_struct.host, 'UTF-8'): "")
|
66
|
-
].join('@')
|
66
|
+
].join('@')
|
67
67
|
if address_struct.name
|
68
68
|
"#{Mail::Encodings.unquote_and_convert_to((address_struct.name || ''), 'UTF-8')} <#{email}>"
|
69
69
|
else
|
@@ -77,7 +77,7 @@ module Vmail
|
|
77
77
|
date = DateTime.parse(message.date)
|
78
78
|
formatted_date = if date.year != Time.now.year
|
79
79
|
date.strftime @date_formatter_prev_years
|
80
|
-
else
|
80
|
+
else
|
81
81
|
date.strftime @date_formatter_this_year
|
82
82
|
end
|
83
83
|
address = if @mailbox == mailbox_aliases['sent']
|
@@ -92,8 +92,8 @@ module Vmail
|
|
92
92
|
row_text = [ format_flags(message.flags).col(2),
|
93
93
|
(formatted_date || '').col(@date_width),
|
94
94
|
address.col(address_col_width),
|
95
|
-
message.subject.col(subject_col_width),
|
96
|
-
number_to_human_size(message.size).rcol(7),
|
95
|
+
message.subject.col(subject_col_width),
|
96
|
+
number_to_human_size(message.size).rcol(7),
|
97
97
|
message.message_id ].join(' | ')
|
98
98
|
end
|
99
99
|
|
@@ -108,11 +108,11 @@ module Vmail
|
|
108
108
|
end
|
109
109
|
|
110
110
|
def with_more_message_line(res)
|
111
|
-
remaining = @start_index
|
111
|
+
remaining = @start_index
|
112
112
|
if remaining <= 1
|
113
113
|
return res
|
114
114
|
end
|
115
|
-
res + "\n> Load #{[100, remaining].min} more messages. #{remaining} remaining."
|
115
|
+
res + "\n> Load #{[100, remaining].min} more messages. #{remaining} remaining."
|
116
116
|
end
|
117
117
|
|
118
118
|
end
|
@@ -26,7 +26,7 @@ module Vmail
|
|
26
26
|
def show_message(message_id, raw=false)
|
27
27
|
message_id = message_id.strip.gsub('\\', '')
|
28
28
|
log "Show message: #{message_id.inspect}"
|
29
|
-
return current_message.rfc822 if raw
|
29
|
+
return current_message.rfc822 if raw
|
30
30
|
res = retry_if_needed { fetch_and_cache(message_id) }
|
31
31
|
log "Showing message message_id: #{message_id}"
|
32
32
|
@cur_message_id = message_id
|
@@ -35,10 +35,10 @@ module Vmail
|
|
35
35
|
|
36
36
|
def fetch_and_cache(message_id)
|
37
37
|
if message = cached_full_message?(message_id)
|
38
|
-
log "- full message cache hit"
|
38
|
+
log "- full message cache hit"
|
39
39
|
return message.plaintext
|
40
40
|
end
|
41
|
-
log "- full message cache miss"
|
41
|
+
log "- full message cache miss"
|
42
42
|
params = {message_id: message_id, label_id: @label.label_id}
|
43
43
|
labeling = Labeling[params] || Labeling.create(params)
|
44
44
|
unless (labeling && labeling.uid)
|
@@ -48,13 +48,13 @@ module Vmail
|
|
48
48
|
end
|
49
49
|
uid = labeling.uid
|
50
50
|
|
51
|
-
log "- fetching message uid #{uid}"
|
52
|
-
fetch_data = reconnect_if_necessary do
|
51
|
+
log "- fetching message uid #{uid}"
|
52
|
+
fetch_data = reconnect_if_necessary do
|
53
53
|
res = retry_if_needed do
|
54
54
|
@imap.uid_fetch(uid, ["FLAGS", "RFC822", "RFC822.SIZE"])
|
55
55
|
end
|
56
56
|
raise "Message uid #{uid} could not be fetched from server" if res.nil?
|
57
|
-
res[0]
|
57
|
+
res[0]
|
58
58
|
end
|
59
59
|
seqno = fetch_data.seqno
|
60
60
|
rfc822 = Mail.new(fetch_data.attr['RFC822'])
|
@@ -63,7 +63,7 @@ module Vmail
|
|
63
63
|
message = Message[message_id]
|
64
64
|
parts_list = format_parts_info(formatter.list_parts)
|
65
65
|
headers_hash = formatter.extract_headers
|
66
|
-
headers_hash['date']
|
66
|
+
headers_hash['date']
|
67
67
|
headers = format_headers headers_hash
|
68
68
|
# replace the date value with the one derived from the envelope
|
69
69
|
body = formatter.plaintext_part
|
@@ -88,7 +88,7 @@ EOF
|
|
88
88
|
end
|
89
89
|
|
90
90
|
begin
|
91
|
-
message.update(:plaintext => message_text)
|
91
|
+
message.update(:plaintext => message_text)
|
92
92
|
rescue
|
93
93
|
log message_text.encoding
|
94
94
|
#log message_text
|
@@ -96,7 +96,7 @@ EOF
|
|
96
96
|
end
|
97
97
|
message_text
|
98
98
|
rescue
|
99
|
-
msg = "Error encountered in fetch_and_cache(), message_id #{message_id} [#{@mailbox}]:\n#{$!}\n#{$!.backtrace.join("\n")}"
|
99
|
+
msg = "Error encountered in fetch_and_cache(), message_id #{message_id} [#{@mailbox}]:\n#{$!}\n#{$!.backtrace.join("\n")}"
|
100
100
|
log msg
|
101
101
|
msg
|
102
102
|
end
|
data/lib/vmail/version.rb
CHANGED
data/test/address_quoter_test.rb
CHANGED
@@ -15,20 +15,20 @@ class AddressQuoterTest < MiniTest::Unit::TestCase
|
|
15
15
|
assert_equal @expected, quote_addresses(@string) #=> "Bob Smith" <bobsmith@gmail.com>, "Jones, Rich A." <richjones@gmail.com>
|
16
16
|
assert_equal @expected2, quote_addresses(@string2) #=> "Bob Smith" <bobsmith@gmail.com>, "Jones, Rich A." <richjones@gmail.com>
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
def test_quoting_with_bare_email_address
|
20
20
|
string = "richjones@gmail.com"
|
21
|
-
assert_equal string, quote_addresses(string)
|
21
|
+
assert_equal string, quote_addresses(string)
|
22
22
|
|
23
23
|
string = "Bob Smith <bobsmith@gmail.com>, Jones, Rich A. <richjones@gmail.com>, peterbaker@gmail.com"
|
24
24
|
expected = %q("Bob Smith" <bobsmith@gmail.com>, "Jones, Rich A." <richjones@gmail.com>, peterbaker@gmail.com)
|
25
|
-
assert_equal expected, quote_addresses(string)
|
25
|
+
assert_equal expected, quote_addresses(string)
|
26
26
|
end
|
27
27
|
|
28
28
|
def test_quoting_already_quoted
|
29
29
|
string = %q(Bob Smith <bobsmith@gmail.com>, "Jones, Rich A." <richjones@gmail.com>, peterbaker@gmail.com)
|
30
30
|
expected = %q("Bob Smith" <bobsmith@gmail.com>, "Jones, Rich A." <richjones@gmail.com>, peterbaker@gmail.com)
|
31
|
-
assert_equal expected, quote_addresses(string)
|
31
|
+
assert_equal expected, quote_addresses(string)
|
32
32
|
end
|
33
33
|
|
34
34
|
end
|
@@ -19,7 +19,7 @@ describe Vmail::MessageFormatter do
|
|
19
19
|
end
|
20
20
|
|
21
21
|
describe "message has a text body but no Content-Type" do
|
22
|
-
before do
|
22
|
+
before do
|
23
23
|
@raw = File.read(File.expand_path('../fixtures/textbody-nocontenttype.eml', __FILE__))
|
24
24
|
@mail = Mail.new(@raw)
|
25
25
|
@formatter = Vmail::MessageFormatter.new(@mail)
|
@@ -52,12 +52,12 @@ describe Vmail::MessageFormatter do
|
|
52
52
|
end
|
53
53
|
it "should format the subject line in UTF-8" do
|
54
54
|
match = "독특닷컴과"
|
55
|
-
assert_match match, @formatter.extract_headers['subject']
|
55
|
+
assert_match match, @formatter.extract_headers['subject']
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
59
|
describe "when message has only an HTML body and no encoding info" do
|
60
|
-
before do
|
60
|
+
before do
|
61
61
|
@raw = File.read(File.expand_path('../fixtures/moleskine-html.eml', __FILE__))
|
62
62
|
@mail = Mail.new(@raw)
|
63
63
|
@formatter = Vmail::MessageFormatter.new(@mail)
|
@@ -69,12 +69,12 @@ describe Vmail::MessageFormatter do
|
|
69
69
|
|
70
70
|
describe "when message has two attachments" do
|
71
71
|
before do
|
72
|
-
@raw = read_fixture('with-attachments.eml')
|
72
|
+
@raw = read_fixture('with-attachments.eml')
|
73
73
|
@mail = Mail.new(@raw)
|
74
74
|
end
|
75
75
|
|
76
76
|
it "should extract two attachments" do
|
77
|
-
attachments = @mail.attachments
|
77
|
+
attachments = @mail.attachments
|
78
78
|
assert_equal 2, attachments.size
|
79
79
|
assert_equal ['image/png', 'image/gif'], attachments.map(&:mime_type)
|
80
80
|
end
|
@@ -88,7 +88,7 @@ describe Vmail::MessageFormatter do
|
|
88
88
|
end
|
89
89
|
|
90
90
|
it 'should extract the message/rfc822 part' do
|
91
|
-
assert_match /I hope everyone is having a great holiday season/,
|
91
|
+
assert_match /I hope everyone is having a great holiday season/,
|
92
92
|
@formatter.process_body
|
93
93
|
end
|
94
94
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
gem "minitest"
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'vmail/version'
|
4
|
+
require 'vmail/options'
|
5
|
+
require 'vmail/inbox_poller'
|
6
|
+
|
7
|
+
describe Vmail::InboxPoller do
|
8
|
+
before do
|
9
|
+
working_dir = ENV['VMAIL_HOME'] || "#{ENV['HOME']}/.vmail/default"
|
10
|
+
Dir.chdir(working_dir)
|
11
|
+
opts = Vmail::Options.new(["--config", ".vmailrc"])
|
12
|
+
opts.config
|
13
|
+
config = opts.config
|
14
|
+
@inbox_poller = Vmail::InboxPoller.start config
|
15
|
+
@notifier = @inbox_poller.initialize_notifier
|
16
|
+
end
|
17
|
+
|
18
|
+
after do
|
19
|
+
@inbox_poller.close
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "test notifications" do
|
23
|
+
it "does not fail" do
|
24
|
+
@notifier.call "This is a simple notification title", "This is a simple body"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "when a notification contains single quotes" do
|
29
|
+
it "does not fail" do
|
30
|
+
res = @notifier.call "Someone's notification", "Shouldn't fail with single quotes"
|
31
|
+
|
32
|
+
print "res: #{res}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/test/reply_template_test.rb
CHANGED
@@ -22,7 +22,7 @@ describe Vmail::ReplyTemplating do
|
|
22
22
|
expected = "Draculette Ko <violinist.ko@gmail.com>, Cookiemonster Youn <cookiemonster@gmail.com>, Racoon <raycoon@gmail.com>"
|
23
23
|
assert_equal expected, @rt.cc
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
def test_sender
|
27
27
|
assert_equal "Chappy Youn <chappy1@gmail.com>", @rt.sender
|
28
28
|
end
|
metadata
CHANGED
@@ -1,83 +1,94 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vmail
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.8.
|
4
|
+
version: 2.8.9
|
5
|
+
prerelease:
|
5
6
|
platform: ruby
|
6
7
|
authors:
|
7
8
|
- Daniel Choi
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date:
|
12
|
+
date: 2014-05-12 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: mail
|
15
16
|
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
16
18
|
requirements:
|
17
|
-
- - '>='
|
19
|
+
- - ! '>='
|
18
20
|
- !ruby/object:Gem::Version
|
19
21
|
version: 2.2.12
|
20
22
|
type: :runtime
|
21
23
|
prerelease: false
|
22
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
23
26
|
requirements:
|
24
|
-
- - '>='
|
27
|
+
- - ! '>='
|
25
28
|
- !ruby/object:Gem::Version
|
26
29
|
version: 2.2.12
|
27
30
|
- !ruby/object:Gem::Dependency
|
28
31
|
name: highline
|
29
32
|
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
30
34
|
requirements:
|
31
|
-
- - '>='
|
35
|
+
- - ! '>='
|
32
36
|
- !ruby/object:Gem::Version
|
33
37
|
version: 1.6.1
|
34
38
|
type: :runtime
|
35
39
|
prerelease: false
|
36
40
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
37
42
|
requirements:
|
38
|
-
- - '>='
|
43
|
+
- - ! '>='
|
39
44
|
- !ruby/object:Gem::Version
|
40
45
|
version: 1.6.1
|
41
46
|
- !ruby/object:Gem::Dependency
|
42
47
|
name: sequel
|
43
48
|
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
44
50
|
requirements:
|
45
|
-
- - '>='
|
51
|
+
- - ! '>='
|
46
52
|
- !ruby/object:Gem::Version
|
47
53
|
version: 3.24.1
|
48
54
|
type: :runtime
|
49
55
|
prerelease: false
|
50
56
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
51
58
|
requirements:
|
52
|
-
- - '>='
|
59
|
+
- - ! '>='
|
53
60
|
- !ruby/object:Gem::Version
|
54
61
|
version: 3.24.1
|
55
62
|
- !ruby/object:Gem::Dependency
|
56
63
|
name: sqlite3
|
57
64
|
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
58
66
|
requirements:
|
59
|
-
- - '>='
|
67
|
+
- - ! '>='
|
60
68
|
- !ruby/object:Gem::Version
|
61
69
|
version: 1.3.3
|
62
70
|
type: :runtime
|
63
71
|
prerelease: false
|
64
72
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
65
74
|
requirements:
|
66
|
-
- - '>='
|
75
|
+
- - ! '>='
|
67
76
|
- !ruby/object:Gem::Version
|
68
77
|
version: 1.3.3
|
69
78
|
- !ruby/object:Gem::Dependency
|
70
79
|
name: versionomy
|
71
80
|
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
72
82
|
requirements:
|
73
|
-
- - '>='
|
83
|
+
- - ! '>='
|
74
84
|
- !ruby/object:Gem::Version
|
75
85
|
version: 0.4.4
|
76
86
|
type: :runtime
|
77
87
|
prerelease: false
|
78
88
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
79
90
|
requirements:
|
80
|
-
- - '>='
|
91
|
+
- - ! '>='
|
81
92
|
- !ruby/object:Gem::Version
|
82
93
|
version: 0.4.4
|
83
94
|
description: Manage your email with Vim
|
@@ -134,47 +145,34 @@ files:
|
|
134
145
|
- test/fixtures/textbody-nocontenttype.eml
|
135
146
|
- test/fixtures/with-attachments.eml
|
136
147
|
- test/message_formatter_test.rb
|
148
|
+
- test/notifier_test.rb
|
137
149
|
- test/reply_template_test.rb
|
138
150
|
- test/test_helper.rb
|
139
151
|
- test/time_format_test.rb
|
140
152
|
- vmail.gemspec
|
141
153
|
homepage: http://danielchoi.com/software/vmail.html
|
142
154
|
licenses: []
|
143
|
-
metadata: {}
|
144
155
|
post_install_message:
|
145
156
|
rdoc_options: []
|
146
157
|
require_paths:
|
147
158
|
- lib
|
148
159
|
required_ruby_version: !ruby/object:Gem::Requirement
|
160
|
+
none: false
|
149
161
|
requirements:
|
150
|
-
- - '>='
|
162
|
+
- - ! '>='
|
151
163
|
- !ruby/object:Gem::Version
|
152
164
|
version: 1.9.0
|
153
165
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
166
|
+
none: false
|
154
167
|
requirements:
|
155
|
-
- - '>='
|
168
|
+
- - ! '>='
|
156
169
|
- !ruby/object:Gem::Version
|
157
170
|
version: '0'
|
158
171
|
requirements: []
|
159
172
|
rubyforge_project: vmail
|
160
|
-
rubygems_version:
|
173
|
+
rubygems_version: 1.8.25
|
161
174
|
signing_key:
|
162
|
-
specification_version:
|
175
|
+
specification_version: 3
|
163
176
|
summary: A Vim interface to Gmail
|
164
|
-
test_files:
|
165
|
-
|
166
|
-
- test/base64_test.rb
|
167
|
-
- test/fixtures/euc-kr-header.eml
|
168
|
-
- test/fixtures/euc-kr-html.eml
|
169
|
-
- test/fixtures/google-affiliate.eml
|
170
|
-
- test/fixtures/htmlbody.eml
|
171
|
-
- test/fixtures/moleskine-html.eml
|
172
|
-
- test/fixtures/reply-template-encoding-test.eml
|
173
|
-
- test/fixtures/reply_all.eml
|
174
|
-
- test/fixtures/rfc_part.eml
|
175
|
-
- test/fixtures/textbody-nocontenttype.eml
|
176
|
-
- test/fixtures/with-attachments.eml
|
177
|
-
- test/message_formatter_test.rb
|
178
|
-
- test/reply_template_test.rb
|
179
|
-
- test/test_helper.rb
|
180
|
-
- test/time_format_test.rb
|
177
|
+
test_files: []
|
178
|
+
has_rdoc:
|
checksums.yaml
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
---
|
2
|
-
SHA1:
|
3
|
-
metadata.gz: 3518bf85a7fa7234e20959f21d38d38673ccd756
|
4
|
-
data.tar.gz: 074a00c8760160288c904d9307745315276d713b
|
5
|
-
SHA512:
|
6
|
-
metadata.gz: a3e3c4c7d7328851e93a2b42c3c925a88d0cb587d736dc364e092e95d98ba58f57eda872fe9c8e964e23eba0f7699ee5e7579c48d8b8b9afdc88253d8b4f5a9b
|
7
|
-
data.tar.gz: 3890f56ce913f779e89e5d6155dc4e6381c670359926e1929e95b38570f42d145999540e57ee76bbc581fe6020839ad942e7e1e628ace978f70307e1755a8a18
|