vmail 2.8.7 → 2.8.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/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
|