vmail 0.9.3 → 0.9.4
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +2 -0
- data/lib/vmail.vim +8 -2
- data/lib/vmail/imap_client.rb +72 -38
- data/lib/vmail/version.rb +1 -1
- metadata +2 -2
data/README.markdown
CHANGED
@@ -138,6 +138,8 @@ top of the list that looks something like this:
|
|
138
138
|
|
139
139
|
Put the cursor on this line and press ENTER to load more of these messages.
|
140
140
|
|
141
|
+
Tip: To go straight to the top line and load more messages, type `gg<ENTER>`.
|
142
|
+
|
141
143
|
Unread messages are marked with a `+` symbol.
|
142
144
|
|
143
145
|
To view the raw RFC822 version of a message, type `,R` while viewing the message.
|
data/lib/vmail.vim
CHANGED
@@ -493,7 +493,7 @@ function! s:select_mailbox()
|
|
493
493
|
let s:query = "100 all"
|
494
494
|
let command = s:select_mailbox_command . shellescape(s:mailbox)
|
495
495
|
redraw
|
496
|
-
echom "selecting mailbox ". s:mailbox ". please wait..."
|
496
|
+
echom "selecting mailbox: ". s:mailbox . ". please wait..."
|
497
497
|
call system(command)
|
498
498
|
redraw
|
499
499
|
" now get latest 100 messages
|
@@ -509,7 +509,8 @@ function! s:select_mailbox()
|
|
509
509
|
setlocal nomodifiable
|
510
510
|
write
|
511
511
|
normal z.
|
512
|
-
|
512
|
+
redraw
|
513
|
+
echom "current mailbox: ". s:mailbox
|
513
514
|
endfunction
|
514
515
|
|
515
516
|
func! s:search_query()
|
@@ -740,6 +741,11 @@ func! s:show_help()
|
|
740
741
|
"exec "split " . helpfile
|
741
742
|
endfunc
|
742
743
|
|
744
|
+
" --------------------------------------------------------------------------------
|
745
|
+
" CONVENIENCE FUNCS
|
746
|
+
|
747
|
+
|
748
|
+
|
743
749
|
" --------------------------------------------------------------------------------
|
744
750
|
" MAPPINGS
|
745
751
|
|
data/lib/vmail/imap_client.rb
CHANGED
@@ -46,6 +46,20 @@ module Vmail
|
|
46
46
|
@message_cache
|
47
47
|
end
|
48
48
|
|
49
|
+
# keys are [mailbox, limit, query]
|
50
|
+
def message_list_cache
|
51
|
+
@message_list_cache ||= {}
|
52
|
+
end
|
53
|
+
|
54
|
+
def current_message_list_cache
|
55
|
+
# third key is the non id_set/range part of query
|
56
|
+
(message_list_cache[[@mailbox, @limit, @query[1..-1], @all_search]] ||= [])
|
57
|
+
end
|
58
|
+
|
59
|
+
def current_message_list_cache=(val)
|
60
|
+
message_list_cache[[@mailbox, @limit, @query[1..-1], @all_search]] ||= val
|
61
|
+
end
|
62
|
+
|
49
63
|
def open
|
50
64
|
@imap = Net::IMAP.new(@imap_server, @imap_port, true, nil, false)
|
51
65
|
@imap.login(@username, @password)
|
@@ -102,7 +116,9 @@ module Vmail
|
|
102
116
|
end
|
103
117
|
end
|
104
118
|
|
119
|
+
# not used for anything
|
105
120
|
def get_mailbox_status
|
121
|
+
return
|
106
122
|
@status = @imap.status(@mailbox, ["MESSAGES", "RECENT", "UNSEEN"])
|
107
123
|
log "mailbox status: #{@status.inspect}"
|
108
124
|
end
|
@@ -148,15 +164,20 @@ module Vmail
|
|
148
164
|
end
|
149
165
|
|
150
166
|
# id_set may be a range, array, or string
|
151
|
-
def
|
152
|
-
log "
|
167
|
+
def fetch_row_text(id_set, are_uids=false, is_update=false)
|
168
|
+
log "fetch_row_text: #{id_set.inspect}"
|
153
169
|
if id_set.is_a?(String)
|
154
170
|
id_set = id_set.split(',')
|
155
171
|
end
|
156
172
|
if id_set.to_a.empty?
|
157
|
-
log "empty set"
|
173
|
+
log "- empty set"
|
158
174
|
return ""
|
159
175
|
end
|
176
|
+
new_message_rows = fetch_envelopes(id_set, are_uids, is_update)
|
177
|
+
new_message_rows.map {|x| x[:row_text]}.join("\n")
|
178
|
+
end
|
179
|
+
|
180
|
+
def fetch_envelopes(id_set, are_uids, is_update)
|
160
181
|
results = reconnect_if_necessary do
|
161
182
|
if are_uids
|
162
183
|
@imap.uid_fetch(id_set, ["FLAGS", "ENVELOPE", "RFC822.SIZE", "UID" ])
|
@@ -168,33 +189,34 @@ module Vmail
|
|
168
189
|
error = "expected fetch results but got nil"
|
169
190
|
log(error) && raise(error)
|
170
191
|
end
|
171
|
-
log "extracting headers"
|
192
|
+
log "- extracting headers"
|
193
|
+
log "- current message list cache has #{current_message_list_cache.size} items"
|
172
194
|
new_message_rows = results.map {|x| extract_row_data(x) }
|
173
195
|
if are_uids
|
174
196
|
# replace old row_text values
|
175
197
|
new_message_rows.each {|new_row_data|
|
176
|
-
|
198
|
+
current_message_list_cache.
|
177
199
|
select {|old_row_data| old_row_data[:uid] == new_row_data[:uid]}.
|
178
200
|
each {|old_row_data| old_row_data[:row_text] = new_row_data[:row_text]}
|
179
201
|
}
|
180
202
|
else
|
181
|
-
|
182
203
|
if is_update
|
183
|
-
log "adding messages from update to end of list"
|
184
|
-
|
204
|
+
log "- adding messages from update to end of list"
|
205
|
+
current_message_list_cache.concat new_message_rows
|
185
206
|
else
|
186
207
|
# this adds old messages to the top of the list
|
187
208
|
# put new rows before the current ones
|
188
|
-
log "adding more messages to head of list"
|
189
|
-
|
209
|
+
log "- adding more messages to head of list"
|
210
|
+
self.current_message_list_cache.unshift(*new_message_rows)
|
190
211
|
end
|
191
212
|
end
|
192
|
-
log "
|
193
|
-
|
194
|
-
|
195
|
-
|
213
|
+
log "- new current message list cache has #{current_message_list_cache.size} items"
|
214
|
+
# current_message_list_cache is automatically cached to keyed message_list_cache
|
215
|
+
log "- returning #{new_message_rows.size} new rows and caching result"
|
216
|
+
new_message_rows
|
196
217
|
end
|
197
218
|
|
219
|
+
|
198
220
|
# TODO extract this to another class or module and write unit tests
|
199
221
|
def extract_row_data(fetch_data)
|
200
222
|
seqno = fetch_data.seqno
|
@@ -284,15 +306,23 @@ module Vmail
|
|
284
306
|
# form a sequence range
|
285
307
|
query.unshift [[@num_messages - limit.to_i + 1 , 1].max, @num_messages].join(':')
|
286
308
|
@all_search = true
|
287
|
-
else
|
288
|
-
# this is a special query search
|
309
|
+
else # this is a special query search
|
289
310
|
# set the target range to the whole set
|
290
311
|
query.unshift "1:#@num_messages"
|
291
312
|
@all_search = false
|
292
313
|
end
|
293
|
-
|
294
|
-
@
|
314
|
+
@query = query.map {|x| x.to_s.downcase}
|
315
|
+
@limit = limit
|
295
316
|
log "search query: #{@query.inspect}"
|
317
|
+
if !current_message_list_cache.empty?
|
318
|
+
log "- CACHE HIT"
|
319
|
+
res = current_message_list_cache.map {|x| x[:row_text]}.join("\n")
|
320
|
+
@ids = current_message_list_cache.map {|x| x[:seqno]}
|
321
|
+
return add_more_message_line(res, current_message_list_cache[0][:seqno])
|
322
|
+
end
|
323
|
+
log "- CACHE MISS"
|
324
|
+
log "- @all_search #{@all_search}"
|
325
|
+
@query = query
|
296
326
|
@ids = reconnect_if_necessary(180) do # increase timeout to 3 minutes
|
297
327
|
@imap.search(@query.join(' '))
|
298
328
|
end
|
@@ -303,10 +333,11 @@ module Vmail
|
|
303
333
|
@start_index = [@ids.length - limit, 0].max
|
304
334
|
@ids[@start_index..-1]
|
305
335
|
end
|
306
|
-
log "search query got #{@ids.size} results"
|
307
|
-
|
336
|
+
log "- search query got #{@ids.size} results"
|
337
|
+
# this will hold all the data extracted from these message envelopes
|
338
|
+
current_message_list_cache = []
|
308
339
|
clear_cached_message
|
309
|
-
res =
|
340
|
+
res = fetch_row_text(fetch_ids)
|
310
341
|
add_more_message_line(res, fetch_ids[0])
|
311
342
|
end
|
312
343
|
|
@@ -315,42 +346,44 @@ module Vmail
|
|
315
346
|
old_num_messages = @num_messages
|
316
347
|
# we need to re-select the mailbox to get the new highest id
|
317
348
|
reload_mailbox
|
318
|
-
update_query = @query
|
349
|
+
update_query = @query.dup
|
319
350
|
# set a new range filter
|
351
|
+
# this may generate a negative rane, e.g., "19893:19992" but that seems harmless
|
320
352
|
update_query[0] = "#{old_num_messages}:#{@num_messages}"
|
321
353
|
ids = reconnect_if_necessary {
|
322
354
|
log "search #update_query"
|
323
355
|
@imap.search(update_query.join(' '))
|
324
356
|
}
|
325
357
|
# TODO change this. will throw error now
|
326
|
-
max_seqno =
|
358
|
+
max_seqno = current_message_list_cache[-1][:seqno]
|
327
359
|
log "looking for seqnos > #{max_seqno}"
|
328
360
|
new_ids = ids.select {|seqno| seqno > max_seqno}
|
329
361
|
@ids = @ids + new_ids
|
330
362
|
log "update: new uids: #{new_ids.inspect}"
|
331
363
|
if !new_ids.empty?
|
332
|
-
res =
|
364
|
+
res = fetch_row_text(new_ids, false, true)
|
333
365
|
res
|
366
|
+
else
|
367
|
+
nil
|
334
368
|
end
|
335
369
|
end
|
336
370
|
|
337
371
|
# gets 100 messages prior to id
|
338
372
|
def more_messages(limit=100)
|
339
|
-
message_id =
|
373
|
+
message_id = current_message_list_cache[0][:seqno]
|
340
374
|
log "more_messages: message_id #{message_id}"
|
341
375
|
message_id = message_id.to_i
|
342
376
|
if @all_search
|
343
377
|
x = [(message_id - limit), 0].max
|
344
378
|
y = [message_id - 1, 0].max
|
345
|
-
res =
|
379
|
+
res = fetch_row_text((x..y))
|
346
380
|
add_more_message_line(res, x)
|
347
|
-
else
|
348
|
-
# filter search query
|
381
|
+
else # filter search query
|
349
382
|
log "@start_index #@start_index"
|
350
383
|
x = [(@start_index - limit), 0].max
|
351
384
|
y = [@start_index - 1, 0].max
|
352
385
|
@start_index = x
|
353
|
-
res =
|
386
|
+
res = fetch_row_text(@ids[x..y])
|
354
387
|
add_more_message_line(res, @ids[x])
|
355
388
|
end
|
356
389
|
end
|
@@ -381,7 +414,8 @@ module Vmail
|
|
381
414
|
|
382
415
|
prefetch_adjacent(index)
|
383
416
|
|
384
|
-
|
417
|
+
log "show message index #{index}"
|
418
|
+
envelope_data = current_message_list_cache[index]
|
385
419
|
seqno = envelope_data[:seqno]
|
386
420
|
uid = envelope_data[:uid]
|
387
421
|
log "showing message index: #{index} seqno: #{seqno} uid #{uid}"
|
@@ -406,7 +440,7 @@ module Vmail
|
|
406
440
|
end
|
407
441
|
|
408
442
|
def fetch_and_cache(index)
|
409
|
-
envelope_data =
|
443
|
+
envelope_data = current_message_list_cache[index]
|
410
444
|
return unless envelope_data
|
411
445
|
seqno = envelope_data[:seqno]
|
412
446
|
uid = envelope_data[:uid]
|
@@ -492,16 +526,16 @@ EOF
|
|
492
526
|
raise "expecting String" unless index_range_as_string.is_a?(String)
|
493
527
|
raise "expecting a range as string" unless index_range_as_string =~ /^\d+\.\.\d+$/
|
494
528
|
log "converting index_range #{index_range_as_string} to uids"
|
495
|
-
uids =
|
529
|
+
uids = current_message_list_cache[eval(index_range_as_string)].map {|row| row[:uid]}
|
496
530
|
log "converted index_range #{index_range_as_string} to uids #{uids.inspect}"
|
497
531
|
uids
|
498
532
|
end
|
499
533
|
|
500
534
|
def remove_uid_set_from_cached_lists(uid_set)
|
501
|
-
# delete from cached @ids and
|
535
|
+
# delete from cached @ids and current_message_list_cache
|
502
536
|
seqnos_to_delete = []
|
503
537
|
uid_set.each {|uid|
|
504
|
-
row =
|
538
|
+
row = current_message_list_cache.detect {|row| row[:uid] == uid}
|
505
539
|
seqno = row[:seqno]
|
506
540
|
log "deleting seqno #{seqno} from @ids"
|
507
541
|
@ids.delete seqno
|
@@ -509,17 +543,17 @@ EOF
|
|
509
543
|
}
|
510
544
|
log "seqnos_to_delete: #{seqnos_to_delete.inspect}"
|
511
545
|
seqnos_to_delete.reverse.each do |seqno|
|
512
|
-
startsize =
|
546
|
+
startsize = current_message_list_cache.size
|
513
547
|
log "deleting row with seqno #{seqno}"
|
514
|
-
|
515
|
-
endsize =
|
548
|
+
current_message_list_cache.delete_if {|x| x[:seqno] == seqno}
|
549
|
+
endsize = current_message_list_cache.size
|
516
550
|
log "deleted #{startsize - endsize} rows"
|
517
551
|
end
|
518
552
|
# now we need to decrement all the higher sequence numbers!
|
519
553
|
basenum = seqnos_to_delete.min # this is the lowested seqno deleted
|
520
554
|
diff = seqnos_to_delete.size # substract this from all seqnos >= basenum
|
521
555
|
changes = []
|
522
|
-
|
556
|
+
current_message_list_cache.each do |row|
|
523
557
|
if row[:seqno] >= basenum
|
524
558
|
changes << "#{row[:seqno]}->#{row[:seqno] - diff}"
|
525
559
|
row[:seqno] -= diff
|
data/lib/vmail/version.rb
CHANGED