vmail 0.4.4 → 0.4.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -63,8 +63,6 @@ You can omit the password key-value pair if you'd rather not have the password
63
63
  saved in the file. In that case, you'll prompted for the password each time you
64
64
  start vmail.
65
65
 
66
-
67
-
68
66
  ## Contacts autocompletion
69
67
 
70
68
  vmail uses Vim autocompletion to help you auto-complete email addresses.
@@ -400,22 +398,6 @@ vmail gem is downloaded from).
400
398
  [github]:https://github.com/danchoi/vmail
401
399
  [rubygems]:https://rubygems.org/gems/vmail
402
400
 
403
- ## Additional configuration options
404
-
405
- The default IMAP server vmail uses is 'imap.gmail.com` and the default port is
406
- `993`. If you want to change these values, e.g, because you are behind a
407
- firewall which blocks IMAP, you can change these values by specifying new ones
408
- in your .vmailrc, like so:
409
-
410
- server: localhost
411
- port: 2999
412
-
413
- Then you can create an SSH tunnel, e.g.
414
-
415
- ssh -f user@example.com -L 2999:imap.gmail.com:993 -N
416
-
417
- (Thanks to Dave Bolton for this patch.)
418
-
419
401
  ## Bug reports, feature requests
420
402
 
421
403
  Please file bug reports and feature requests in the [vmail github issue tracker][tracker].
data/Rakefile CHANGED
@@ -12,11 +12,6 @@ task :web do
12
12
  end
13
13
  end
14
14
 
15
- desc "git push and rake release bumped version"
16
- task :bumped do
17
- puts `git commit -a -m'bump' && git push && rake release`
18
- end
19
-
20
15
  desc "Run tests"
21
16
  task :test do
22
17
  $:.unshift File.expand_path("test")
data/bin/vmail CHANGED
File without changes
File without changes
@@ -453,7 +453,6 @@ function! s:select_mailbox()
453
453
  return
454
454
  endif
455
455
  let s:mailbox = mailbox
456
- let s:query = "100 all"
457
456
  let command = s:select_mailbox_command . shellescape(s:mailbox)
458
457
  call system(command)
459
458
  redraw
@@ -691,9 +690,9 @@ func! s:message_window_mappings()
691
690
  nnoremap <silent> <buffer> q :close<cr>
692
691
 
693
692
  nnoremap <silent> <buffer> <leader># :close<cr>:call <SID>focus_list_window()<cr>:call <SID>delete_messages("Deleted")<cr>
693
+ nmap <silent> <buffer> <leader>d <leader>#
694
694
  nnoremap <silent> <buffer> <leader>* :call <SID>focus_list_window()<cr>:call <SID>toggle_star()<cr>
695
- noremap <silent> <buffer> <leader>! :call <SID>focus_list_window()<cr>:call <SID>delete_messages("[Gmail]/Spam")<CR>
696
- noremap <silent> <buffer> <leader>e :call <SID>focus_list_window()<cr>:call <SID>archive_messages()<CR>
695
+ nmap <silent> <buffer> s <leader>*
697
696
 
698
697
  nnoremap <silent> <buffer> <Leader>b :call <SID>focus_list_window()<cr>call <SID>move_to_mailbox(0)<CR>
699
698
  nnoremap <silent> <buffer> <Leader>B :call <SID>focus_list_window()<cr>call <SID>move_to_mailbox(1)<CR>
@@ -27,13 +27,11 @@ module Vmail
27
27
  @logger = Logger.new(config['logfile'] || STDERR)
28
28
  @logger.level = Logger::DEBUG
29
29
  @current_mail = nil
30
- @current_id = nil
31
- @imap_server = config['server'] || 'imap.gmail.com'
32
- @imap_port = config['port'] || 993
30
+ @current_uid = nil
33
31
  end
34
32
 
35
33
  def open
36
- @imap = Net::IMAP.new(@imap_server, @imap_port, true, nil, false)
34
+ @imap = Net::IMAP.new('imap.gmail.com', 993, true, nil, false)
37
35
  @imap.login(@username, @password)
38
36
  end
39
37
 
@@ -43,11 +41,11 @@ module Vmail
43
41
  @imap.disconnect
44
42
  end
45
43
 
46
- def select_mailbox(mailbox, force=false)
44
+ def select_mailbox(mailbox)
47
45
  if MailboxAliases[mailbox]
48
46
  mailbox = MailboxAliases[mailbox]
49
47
  end
50
- if mailbox == @mailbox && !force
48
+ if mailbox == @mailbox
51
49
  return
52
50
  end
53
51
  log "selecting mailbox #{mailbox.inspect}"
@@ -55,23 +53,11 @@ module Vmail
55
53
  log @imap.select(mailbox)
56
54
  end
57
55
  @mailbox = mailbox
58
- get_mailbox_status
59
- get_highest_message_id
56
+ @all_uids = []
57
+ @bad_uids = []
60
58
  return "OK"
61
59
  end
62
60
 
63
- def get_highest_message_id
64
- # get highest message ID
65
- res = @imap.fetch([1,"*"], ["ENVELOPE"])
66
- @num_messages = res[-1].seqno
67
- log "HIGHEST ID: #@num_messages"
68
- end
69
-
70
- def get_mailbox_status
71
- @status = @imap.status(@mailbox, ["MESSAGES", "RECENT", "UNSEEN"])
72
- log "mailbox status: #{@status.inspect}"
73
- end
74
-
75
61
  def revive_connection
76
62
  log "reviving connection"
77
63
  open
@@ -79,18 +65,6 @@ module Vmail
79
65
  @imap.select(@mailbox)
80
66
  end
81
67
 
82
- def prime_connection
83
- reconnect_if_necessary(4) do
84
- # this is just to prime the IMAP connection
85
- # It's necessary for some reason before update and deliver.
86
- log "priming connection for delivering"
87
- res = @imap.fetch(@ids[-1], ["ENVELOPE"])
88
- if res.nil?
89
- raise IOError, "IMAP connection seems broken"
90
- end
91
- end
92
- end
93
-
94
68
  def list_mailboxes
95
69
  @mailboxes ||= (@imap.list("[Gmail]/", "%") + @imap.list("", "%")).
96
70
  select {|struct| struct.attr.none? {|a| a == :Noselect} }.
@@ -109,19 +83,20 @@ module Vmail
109
83
  @mailboxes
110
84
  end
111
85
 
112
- # id_set may be a range, array, or string
113
- def fetch_envelopes(id_set)
114
- log "fetch_envelopes: #{id_set.inspect}"
115
- if id_set.is_a?(String)
116
- id_set = id_set.split(',')
86
+ def fetch_headers(uid_set)
87
+ if uid_set.is_a?(String)
88
+ uid_set = uid_set.split(",").map(&:to_i)
89
+ elsif uid_set.is_a?(Integer)
90
+ uid_set = [uid_set]
117
91
  end
118
- max_id = id_set.to_a[-1]
119
- if id_set.to_a.empty?
92
+ max_uid = uid_set.max
93
+ log "fetch headers for #{uid_set.inspect}"
94
+ if uid_set.empty?
120
95
  log "empty set"
121
96
  return ""
122
97
  end
123
98
  results = reconnect_if_necessary do
124
- @imap.fetch(id_set, ["FLAGS", "ENVELOPE", "RFC822.SIZE" ])
99
+ @imap.uid_fetch(uid_set, ["FLAGS", "ENVELOPE", "RFC822.SIZE" ])
125
100
  end
126
101
  log "extracting headers"
127
102
  lines = results.
@@ -132,13 +107,13 @@ module Vmail
132
107
  Time.now
133
108
  end
134
109
  }.
135
- map {|x| format_list_row(x, max_id)}
110
+ map {|x| format_header(x, max_uid)}
136
111
  log "returning result"
137
112
  return lines.join("\n")
138
113
  end
139
114
 
140
- def format_list_row(fetch_data, max_id=nil)
141
- id = fetch_data.seqno
115
+ def format_header(fetch_data, max_uid=nil)
116
+ uid = fetch_data.attr["UID"]
142
117
  envelope = fetch_data.attr["ENVELOPE"]
143
118
  size = fetch_data.attr["RFC822.SIZE"]
144
119
  flags = fetch_data.attr["FLAGS"]
@@ -173,18 +148,18 @@ module Vmail
173
148
  subject = envelope.subject || ''
174
149
  subject = Mail::Encodings.unquote_and_convert_to(subject, 'UTF-8')
175
150
  flags = format_flags(flags)
176
- first_col_width = max_id.to_s.length
151
+ first_col_width = max_uid.to_s.length
177
152
  mid_width = @width - (first_col_width + 33)
178
153
  address_col_width = (mid_width * 0.3).ceil
179
154
  subject_col_width = (mid_width * 0.7).floor
180
- [id.to_s.col(first_col_width),
155
+ [uid.to_s.col(first_col_width),
181
156
  (date_formatted || '').col(14),
182
157
  address.col(address_col_width),
183
158
  subject.col(subject_col_width),
184
159
  number_to_human_size(size).rcol(6),
185
160
  flags.rcol(7)].join(' ')
186
161
  rescue
187
- "#{id.to_s} : error extracting this header"
162
+ "#{uid.to_s} : error extracting this header"
188
163
  end
189
164
 
190
165
  UNITS = [:b, :kb, :mb, :gb].freeze
@@ -214,119 +189,83 @@ module Vmail
214
189
  end
215
190
 
216
191
  def search(limit, *query)
217
- limit = limit.to_i
218
- limit = 100 if limit.to_s !~ /^\d+$/
192
+ log "uid_search limit: #{limit} query: #{@query.inspect}"
193
+ limit = 25 if limit.to_s !~ /^\d+$/
219
194
  query = ['ALL'] if query.empty?
220
- if query.size == 1 && query[0].downcase == 'all'
221
- # form a sequence range
222
- query.unshift [[@num_messages - limit.to_i + 1 , 1].max, @num_messages].join(':')
223
- @all_search = true
224
- else
225
- # this is a special query search
226
- # set the target range to the whole set
227
- query.unshift "1:#@num_messages"
228
- @all_search = false
229
- end
230
- log "@all_search #{@all_search}"
231
- @query = query
232
- log "search query: #@query.inspect"
233
- @ids = reconnect_if_necessary do
234
- @imap.search(@query.join(' '))
235
- end
236
- # save ids in @ids, because filtered search relies on it
237
- fetch_ids = if @all_search
238
- @ids
239
- else #filtered search
240
- @start_index = [@ids.length - limit, 0].max
241
- @ids[@start_index..-1]
242
- end
243
- log "search query got #{@ids.size} results"
244
- res = fetch_envelopes(fetch_ids)
245
- add_more_message_line(res, fetch_ids[0])
195
+ @query = query.join(' ')
196
+ log "uid_search #@query #{limit}"
197
+ @all_uids = reconnect_if_necessary do
198
+ @imap.uid_search(@query)
199
+ end
200
+ uids = @all_uids[-([limit.to_i, @all_uids.size].min)..-1] || []
201
+ res = fetch_headers(uids)
202
+ add_more_message_line(res, uids)
246
203
  end
247
204
 
248
205
  def update
249
- prime_connection
250
- old_num_messages = @num_messages
251
- # we need to re-select the mailbox to get the new highest id
252
- select_mailbox(@mailbox, true)
253
- update_query = @query
254
- # set a new range filter
255
- update_query[0] = "#{old_num_messages}:#{@num_messages}"
256
- ids = reconnect_if_necessary {
257
- log "search #update_query"
258
- @imap.search(update_query.join(' '))
206
+ reconnect_if_necessary(4) do
207
+ # this is just to prime the IMAP connection
208
+ # It's necessary for some reason.
209
+ log "priming connection for update"
210
+ res = @imap.uid_fetch(@all_uids[-1], ["ENVELOPE"])
211
+ if res.nil?
212
+ raise IOError, "IMAP connection seems broken"
213
+ end
214
+ end
215
+ uids = reconnect_if_necessary {
216
+ log "uid_search #@query"
217
+ @imap.uid_search(@query)
259
218
  }
260
- # TODO change this. will throw error now
261
- new_ids = ids.select {|x| x > @ids.max}
262
- @ids = @ids + new_ids
263
- log "UPDATE: NEW UIDS: #{new_ids.inspect}"
264
- if !new_ids.empty?
265
- res = fetch_envelopes(new_ids)
219
+ new_uids = uids - @all_uids
220
+ log "UPDATE: NEW UIDS: #{new_uids.inspect}"
221
+ if !new_uids.empty?
222
+ res = fetch_headers(new_uids)
223
+ @all_uids = uids
266
224
  res
267
225
  end
268
226
  end
269
227
 
270
- # gets 100 messages prior to id
271
- def more_messages(message_id, limit=100)
272
- log "more_messages: message_id #{message_id}"
273
- message_id = message_id.to_i
274
- if @all_search
275
- x = [(message_id - limit), 0].max
276
- y = [message_id - 1, 0].max
277
- res = fetch_envelopes((x..y))
278
- add_more_message_line(res, x)
279
- else
280
- # filter search query
281
- log "@start_index #@start_index"
282
- x = [(@start_index - limit), 0].max
283
- y = [@start_index - 1, 0].max
284
- @start_index = x
285
- res = fetch_envelopes(@ids[x..y])
286
- add_more_message_line(res, @ids[x])
287
- end
288
- end
289
-
290
- def add_more_message_line(res, start_id)
291
- log "add_more_message_line for start_id #{start_id}"
292
- if @all_search
293
- return res if start_id.nil?
294
- if start_id <= 1
295
- return res
296
- end
297
- remaining = start_id - 1
298
- else # filter search
299
- remaining = @ids.index(start_id) - 1
300
- end
301
- if remaining < 1
302
- log "none remaining"
303
- return res
228
+ # gets 100 messages prior to uid
229
+ def more_messages(uid, limit=100)
230
+ uid = uid.to_i
231
+ x = [(@all_uids.index(uid) - limit), 0].max
232
+ y = [@all_uids.index(uid) - 1, 0].max
233
+ uids = @all_uids[x..y]
234
+ res = fetch_headers(uids)
235
+ add_more_message_line(res, uids)
236
+ end
237
+
238
+ def add_more_message_line(res, uids)
239
+ return res if uids.empty?
240
+ start_index = @all_uids.index(uids[0])
241
+ if start_index > 0
242
+ remaining = start_index
243
+ res = "> Load #{[100, remaining].min} more messages. #{remaining} remaining.\n" + res
304
244
  end
305
- log "remaining messages: #{remaining}"
306
- "> Load #{[100, remaining].min} more messages. #{remaining} remaining.\n" + res
245
+ res
307
246
  end
308
247
 
309
- def show_message(id, raw=false, forwarded=false)
310
- id = id.to_i
248
+ def show_message(uid, raw=false, forwarded=false)
249
+ uid = uid.to_i
311
250
  if forwarded
312
251
  return @current_message.split(/\n-{20,}\n/, 2)[1]
313
252
  end
314
253
  return @current_mail.to_s if raw
315
- return @current_message if id == @current_id
316
- log "fetching #{id.inspect}"
254
+ return @current_message if uid == @current_uid
255
+ log "fetching #{uid.inspect}"
317
256
  fetch_data = reconnect_if_necessary do
318
- @imap.fetch(id, ["FLAGS", "RFC822", "RFC822.SIZE"])[0]
257
+ @imap.uid_fetch(uid, ["FLAGS", "RFC822", "RFC822.SIZE"])[0]
319
258
  end
320
259
  res = fetch_data.attr["RFC822"]
321
260
  mail = Mail.new(res)
322
- @current_id = id
261
+ @current_uid = uid
323
262
  @current_mail = mail # used later to show raw message or extract attachments if any
324
263
  log "saving current mail with parts: #{@current_mail.parts.inspect}"
325
264
  formatter = Vmail::MessageFormatter.new(mail)
326
265
  out = formatter.process_body
327
266
  size = fetch_data.attr["RFC822.SIZE"]
328
267
  @current_message = <<-EOF
329
- #{@mailbox} #{id} #{number_to_human_size size} #{format_parts_info(formatter.list_parts)}
268
+ #{@mailbox} #{uid} #{number_to_human_size size} #{format_parts_info(formatter.list_parts)}
330
269
  ---------------------------------------
331
270
  #{format_headers(formatter.extract_headers)}
332
271
 
@@ -344,36 +283,36 @@ EOF
344
283
  end
345
284
  end
346
285
 
347
- # id_set is a string comming from the vim client
286
+ # uid_set is a string comming from the vim client
348
287
  # action is -FLAGS or +FLAGS
349
- def flag(id_set, action, flg)
350
- if id_set.is_a?(String)
351
- id_set = id_set.split(",").map(&:to_i)
288
+ def flag(uid_set, action, flg)
289
+ if uid_set.is_a?(String)
290
+ uid_set = uid_set.split(",").map(&:to_i)
352
291
  end
353
292
  # #<struct Net::IMAP::FetchData seqno=17423, attr={"FLAGS"=>[:Seen, "Flagged"], "UID"=>83113}>
354
- log "flag #{id_set} #{flg} #{action}"
293
+ log "flag #{uid_set} #{flg} #{action}"
355
294
  if flg == 'Deleted'
356
295
  # for delete, do in a separate thread because deletions are slow
357
296
  Thread.new do
358
297
  unless @mailbox == '[Gmail]/Trash'
359
- @imap.copy(id_set, "[Gmail]/Trash")
298
+ @imap.uid_copy(uid_set, "[Gmail]/Trash")
360
299
  end
361
- res = @imap.store(id_set, action, [flg.to_sym])
300
+ res = @imap.uid_store(uid_set, action, [flg.to_sym])
362
301
  end
363
- id_set.each { |id| @all_ids.delete(id) }
302
+ uid_set.each { |uid| @all_uids.delete(uid) }
364
303
  elsif flg == '[Gmail]/Spam'
365
- @imap.copy(id_set, "[Gmail]/Spam")
366
- res = @imap.store(id_set, action, [:Deleted])
367
- "#{id} deleted"
304
+ @imap.uid_copy(uid_set, "[Gmail]/Spam")
305
+ res = @imap.uid_store(uid_set, action, [:Deleted])
306
+ "#{uid} deleted"
368
307
  else
369
308
  log "Flagging"
370
- res = @imap.store(id_set, action, [flg.to_sym])
309
+ res = @imap.uid_store(uid_set, action, [flg.to_sym])
371
310
  # log res.inspect
372
- fetch_envelopes(id_set)
311
+ fetch_headers(uid_set)
373
312
  end
374
313
  end
375
314
 
376
- def move_to(id_set, mailbox)
315
+ def move_to(uid_set, mailbox)
377
316
  if mailbox == 'all'
378
317
  log "archiving messages"
379
318
  end
@@ -381,24 +320,24 @@ EOF
381
320
  mailbox = MailboxAliases[mailbox]
382
321
  end
383
322
  create_if_necessary mailbox
384
- if id_set.is_a?(String)
385
- id_set = id_set.split(",").map(&:to_i)
323
+ if uid_set.is_a?(String)
324
+ uid_set = uid_set.split(",").map(&:to_i)
386
325
  end
387
- log "move_to #{id_set.inspect} #{mailbox}"
388
- log @imap.copy(id_set, mailbox)
389
- log @imap.store(id_set, '+FLAGS', [:Deleted])
326
+ log "move_to #{uid_set.inspect} #{mailbox}"
327
+ log @imap.uid_copy(uid_set, mailbox)
328
+ log @imap.uid_store(uid_set, '+FLAGS', [:Deleted])
390
329
  end
391
330
 
392
- def copy_to(id_set, mailbox)
331
+ def copy_to(uid_set, mailbox)
393
332
  if MailboxAliases[mailbox]
394
333
  mailbox = MailboxAliases[mailbox]
395
334
  end
396
335
  create_if_necessary mailbox
397
- log "copy #{id_set.inspect} #{mailbox}"
398
- if id_set.is_a?(String)
399
- id_set = id_set.split(",").map(&:to_i)
336
+ log "copy #{uid_set.inspect} #{mailbox}"
337
+ if uid_set.is_a?(String)
338
+ uid_set = uid_set.split(",").map(&:to_i)
400
339
  end
401
- log @imap.copy(id_set, mailbox)
340
+ log @imap.uid_copy(uid_set, mailbox)
402
341
  end
403
342
 
404
343
  def create_if_necessary(mailbox)
@@ -411,18 +350,18 @@ EOF
411
350
  end
412
351
  end
413
352
 
414
- def append_to_file(file, id_set)
415
- if id_set.is_a?(String)
416
- id_set = id_set.split(",").map(&:to_i)
353
+ def append_to_file(file, uid_set)
354
+ if uid_set.is_a?(String)
355
+ uid_set = uid_set.split(",").map(&:to_i)
417
356
  end
418
357
  log "append messages to file: #{file}"
419
- id_set.each do |id|
420
- message = show_message(id)
358
+ uid_set.each do |uid|
359
+ message = show_message(uid)
421
360
  divider = "#{'=' * 39}\n"
422
361
  File.open(file, 'a') {|f| f.puts(divider + message + "\n\n")}
423
- log "appended id #{id}"
362
+ log "appended uid #{uid}"
424
363
  end
425
- "printed #{id_set.size} message#{id_set.size == 1 ? '' : 's'} to #{file.strip}"
364
+ "printed #{uid_set.size} message#{uid_set.size == 1 ? '' : 's'} to #{file.strip}"
426
365
  end
427
366
 
428
367
 
@@ -445,9 +384,9 @@ EOF
445
384
  lines.join("\n")
446
385
  end
447
386
 
448
- def reply_template(id, replyall=false)
449
- log "sending reply template for #{id}"
450
- fetch_data = @imap.fetch(id.to_i, ["FLAGS", "ENVELOPE", "RFC822"])[0]
387
+ def reply_template(uid, replyall=false)
388
+ log "sending reply template for #{uid}"
389
+ fetch_data = @imap.uid_fetch(uid.to_i, ["FLAGS", "ENVELOPE", "RFC822"])[0]
451
390
  envelope = fetch_data.attr['ENVELOPE']
452
391
  recipient = [envelope.reply_to, envelope.from].flatten.map {|x| address_to_string(x)}[0]
453
392
  cc = [envelope.to, envelope.cc]
@@ -478,8 +417,8 @@ EOF
478
417
  "\n\n#@signature"
479
418
  end
480
419
 
481
- def forward_template(id)
482
- original_body = show_message(id, false, true)
420
+ def forward_template(uid)
421
+ original_body = show_message(uid, false, true)
483
422
  new_message_template +
484
423
  "\n---------- Forwarded message ----------\n" +
485
424
  original_body + signature
@@ -488,7 +427,15 @@ EOF
488
427
  def deliver(text)
489
428
  # parse the text. The headers are yaml. The rest is text body.
490
429
  require 'net/smtp'
491
- prime_connection
430
+ reconnect_if_necessary(4) do
431
+ # this is just to prime the IMAP connection
432
+ # It's necessary for some reason.
433
+ log "priming connection for delivering"
434
+ res = @imap.uid_fetch(@all_uids[-1], ["ENVELOPE"])
435
+ if res.nil?
436
+ raise IOError, "IMAP connection seems broken"
437
+ end
438
+ end
492
439
  mail = new_mail_from_input(text)
493
440
  mail.delivery_method(*smtp_settings)
494
441
  log mail.deliver!
@@ -571,8 +518,8 @@ EOF
571
518
  "saved:\n" + saved.map {|x| "- #{x}"}.join("\n")
572
519
  end
573
520
 
574
- def open_html_part(id)
575
- log "open_html_part #{id}"
521
+ def open_html_part(uid)
522
+ log "open_html_part #{uid}"
576
523
  log @current_mail.parts.inspect
577
524
  multipart = @current_mail.parts.detect {|part| part.multipart?}
578
525
  html_part = if multipart
@@ -624,9 +571,6 @@ EOF
624
571
  log(revive_connection)
625
572
  # try just once
626
573
  block.call
627
- rescue
628
- log "error: #{$!}"
629
- raise
630
574
  end
631
575
 
632
576
  def self.start(config)
@@ -1,3 +1,3 @@
1
1
  module Vmail
2
- VERSION = "0.4.4"
2
+ VERSION = "0.4.5"
3
3
  end
@@ -23,6 +23,10 @@
23
23
 
24
24
  <div class="sidebar">
25
25
 
26
+ <h4>share this</h4>
27
+
28
+ <span class="st_twitter_large" displayText="Tweet"></span><span class="st_facebook_large" displayText="Facebook"></span><span class="st_ybuzz_large" displayText="Yahoo! Buzz"></span><span class="st_gbuzz_large" displayText="Google Buzz"></span><span class="st_email_large" displayText="Email"></span><span class="st_sharethis_large" displayText="ShareThis"></span>
29
+
26
30
  <h4>links</h4>
27
31
  <ul>
28
32
  <li><a href="https://github.com/danchoi/vmail">github repo</a></li>
@@ -30,10 +34,6 @@
30
34
  <li><a href="https://github.com/danchoi/vmail/issues">issue tracker</a></li>
31
35
  <li><a href="http://www.google.com/search?sourceid=chrome&ie=UTF-8&q=vmail+vim#hl=en&tbo=1&tbs=mbl:1,mbl_sv:0&q=link:http://danielchoi.com/software/vmail.html&sa=X&ei=iw0JTYnsPMT_lgfgvMC1AQ&ved=0CAUQ6QcwCg&fp=1&cad=b">web reactions</a></li>
32
36
  </ul>
33
- <h4>share this</h4>
34
-
35
- <span class="st_twitter_large" displayText="Tweet"></span><span class="st_facebook_large" displayText="Facebook"></span><span class="st_ybuzz_large" displayText="Yahoo! Buzz"></span><span class="st_gbuzz_large" displayText="Google Buzz"></span><span class="st_email_large" displayText="Email"></span><span class="st_sharethis_large" displayText="ShareThis"></span>
36
-
37
37
  </div>
38
38
 
39
39
  </div>
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 4
8
- - 4
9
- version: 0.4.4
8
+ - 5
9
+ version: 0.4.5
10
10
  platform: ruby
11
11
  authors:
12
12
  - Daniel Choi