sup 0.9 → 0.9.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of sup might be problematic. Click here for more details.

data/CONTRIBUTORS CHANGED
@@ -14,16 +14,24 @@ Marc Hartstein <marc.hartstein at the alum.vassar dot edus>
14
14
  Israel Herraiz <israel.herraiz at the gmail dot coms>
15
15
  Grant Hollingworth <grant at the antiflux dot orgs>
16
16
  Adeodato Simó <dato at the net.com.org dot ess>
17
- Steve Goldman <sgoldman at the tower-research dot coms>
18
17
  Edward Z. Yang <ezyang at the mit dot edus>
18
+ Steve Goldman <sgoldman at the tower-research dot coms>
19
19
  Decklin Foster <decklin at the red-bean dot coms>
20
+ Cameron Matheson <cam+sup at the cammunism dot orgs>
21
+ Tero Tilus <tero at the tilus dot nets>
20
22
  Alex Vandiver <alex at the chmrr dot nets>
21
23
  Jeff Balogh <its.jeff.balogh at the gmail dot coms>
24
+ Andrew Pimlott <andrew at the pimlott dot nets>
25
+ Peter Harkins <ph at the malaprop dot orgs>
26
+ Anthony Martinez <pi at the pihost dot uss>
22
27
  Carl Worth <cworth at the cworth dot orgs>
23
28
  Kornilios Kourtis <kkourt at the cslab.ece.ntua dot grs>
24
29
  Giorgio Lando <patroclo7 at the gmail dot coms>
25
30
  Benoît PIERRE <benoit.pierre at the gmail dot coms>
26
- Ian Taylor <ian at the lorf dot orgs>
27
- Stefan Lundström
31
+ ian <ian at the lorf dot orgs>
32
+ Steven Walter <swalter at the monarch.(none)>
28
33
  Michael Hamann <michael at the content-space dot des>
34
+ Stefan Lundström <lundst at the snabb.(none)>
35
+ William Erik Baxter <web at the superscript dot coms>
36
+ Jon M. Dugan <jdugan at the es dot nets>
29
37
  Kirill Smelkov <kirr at the landau.phys.spbu dot rus>
data/History.txt CHANGED
@@ -1,3 +1,16 @@
1
+ == 0.9.1 / 2009-12-10
2
+ * Make textfield behave more like readline, including C-w
3
+ * Add ask_for_to config option. You can set all ask_for_* options to false, and
4
+ composing a message will go immediately to the editor.
5
+ * RFC 2047 decode attachment file names
6
+ * default ask_for_to to true
7
+ * add undo power to thread-view-mode
8
+ * display labels of polled messages
9
+ * increase numbers in contact-list-mode
10
+ * fix --compose option, and add a --subject option
11
+ * include hook filename in error messages
12
+ * As always, many bugfixes and tweaks.
13
+
1
14
  == 0.9 / 2009-10-01
2
15
  * Experimental Xapian backend to replace Ferret. Not everything works with it,
3
16
  but it's fast and less likely to barf. See release notes.
data/ReleaseNotes CHANGED
@@ -1,3 +1,10 @@
1
+ Release 0.9.1:
2
+
3
+ This is mainly a bugfix release, with a couple minor new features rolled up.
4
+
5
+ If you are using the Ferret backend, consider convering soon. I will probably
6
+ add a deprecation notice in 0.10, and you support will be dropped in 0.11.
7
+
1
8
  Release 0.9:
2
9
 
3
10
  There's a new Xapian backend as an alternative to the Ferret one. It's still in
data/bin/sup CHANGED
@@ -7,7 +7,7 @@ require 'fileutils'
7
7
  require 'trollop'
8
8
  require "sup"
9
9
 
10
- BIN_VERSION = "0.9"
10
+ BIN_VERSION = "0.9.1"
11
11
 
12
12
  unless Redwood::VERSION == BIN_VERSION
13
13
  $stderr.puts <<EOS
@@ -36,8 +36,11 @@ EOS
36
36
  opt :no_initial_poll, "Don't poll for new messages when starting."
37
37
  opt :search, "Search for this query upon startup", :type => String
38
38
  opt :compose, "Compose message to this recipient upon startup", :type => String
39
+ opt :subject, "When composing, use this subject", :type => String, :short => "j"
39
40
  end
40
41
 
42
+ Trollop::die :subject, "requires --compose" if $opts[:subject] && !$opts[:compose]
43
+
41
44
  Redwood::HookManager.register "startup", <<EOS
42
45
  Executes at startup
43
46
  No variables.
@@ -196,7 +199,10 @@ begin
196
199
  imode.load_threads :num => ibuf.content_height, :when_done => lambda { |num| reporting_thread("poll after loading inbox") { sleep 1; PollManager.poll } unless $opts[:no_threads] || $opts[:no_initial_poll] }
197
200
 
198
201
  if $opts[:compose]
199
- ComposeMode.spawn_nicely :to_default => $opts[:compose]
202
+ to = Person.from_address_list $opts[:compose]
203
+ mode = ComposeMode.new :to => to, :subj => $opts[:subject]
204
+ BufferManager.spawn "New Message", mode
205
+ mode.edit_message
200
206
  end
201
207
 
202
208
  unless $opts[:no_threads]
@@ -354,7 +360,7 @@ unless Redwood::exceptions.empty?
354
360
  ----------------------------------------------------------------
355
361
  I'm very sorry. It seems that an error occurred in Sup. Please
356
362
  accept my sincere apologies. If you don't mind, please send the
357
- contents of ~/.sup/exception-log.txt and a brief report of the
363
+ contents of #{BASE_DIR}/exception-log.txt and a brief report of the
358
364
  circumstances to sup-talk at rubyforge dot orgs so that I might
359
365
  address this problem. Thank you!
360
366
 
data/lib/sup.rb CHANGED
@@ -37,7 +37,7 @@ class Module
37
37
  end
38
38
 
39
39
  module Redwood
40
- VERSION = "0.9"
40
+ VERSION = "0.9.1"
41
41
 
42
42
  BASE_DIR = ENV["SUP_BASE"] || File.join(ENV["HOME"], ".sup")
43
43
  CONFIG_FN = File.join(BASE_DIR, "config.yaml")
@@ -221,6 +221,7 @@ else
221
221
  :editor => ENV["EDITOR"] || "/usr/bin/vim -f -c 'setlocal spell spelllang=en_us' -c 'set filetype=mail'",
222
222
  :thread_by_subject => false,
223
223
  :edit_signature => false,
224
+ :ask_for_to => true,
224
225
  :ask_for_cc => true,
225
226
  :ask_for_bcc => false,
226
227
  :ask_for_subject => true,
data/lib/sup/account.rb CHANGED
@@ -10,6 +10,17 @@ class Account < Person
10
10
  @sendmail = h[:sendmail]
11
11
  @signature = h[:signature]
12
12
  end
13
+
14
+ # Default sendmail command for bouncing mail,
15
+ # deduced from #sendmail
16
+ def bounce_sendmail
17
+ sendmail.sub(/\s(\-(ti|it|t))\b/) do |match|
18
+ case $1
19
+ when '-t' then ''
20
+ else ' -i'
21
+ end
22
+ end
23
+ end
13
24
  end
14
25
 
15
26
  class AccountManager
@@ -340,7 +340,7 @@ EOS
340
340
  query = {}
341
341
 
342
342
  subs = HookManager.run("custom-search", :subs => s) || s
343
- subs = s.gsub(/\b(to|from):(\S+)\b/) do
343
+ subs = subs.gsub(/\b(to|from):(\S+)\b/) do
344
344
  field, name = $1, $2
345
345
  if(p = ContactManager.contact_for(name))
346
346
  [field, p.email]
data/lib/sup/hook.rb CHANGED
@@ -78,10 +78,11 @@ class HookManager
78
78
  context = @contexts[hook] ||= HookContext.new(name)
79
79
 
80
80
  result = nil
81
+ fn = fn_for name
81
82
  begin
82
- result = context.__run hook, fn_for(name), locals
83
+ result = context.__run hook, fn, locals
83
84
  rescue Exception => e
84
- log "error running hook: #{e.message}"
85
+ log "error running #{fn}: #{e.message}"
85
86
  log e.backtrace.join("\n")
86
87
  @hooks[name] = nil # disable it
87
88
  BufferManager.flash "Error running hook: #{e.message}" if BufferManager.instantiated?
data/lib/sup/mbox.rb CHANGED
@@ -14,7 +14,7 @@ module MBox
14
14
  ## hack -- make Time.parse fail when trying to substitute values from Time.now
15
15
  Time.parse time, 0
16
16
  true
17
- rescue NoMethodError
17
+ rescue NoMethodError, ArgumentError
18
18
  warn "found invalid date in potential mbox split line, not splitting: #{l.inspect}"
19
19
  false
20
20
  end
data/lib/sup/message.rb CHANGED
@@ -494,12 +494,14 @@ private
494
494
 
495
495
  ## if there's a filename, we'll treat it as an attachment.
496
496
  if filename
497
+ ## filename could be 2047 encoded
498
+ filename = Rfc2047.decode_to $encoding, filename
497
499
  # add this to the attachments list if its not a generated html
498
500
  # attachment (should we allow images with generated names?).
499
501
  # Lowercase the filename because searches are easier that way
500
502
  @attachments.push filename.downcase unless filename =~ /^sup-attachment-/
501
503
  add_label :attachment unless filename =~ /^sup-attachment-/
502
- content_type = m.header.content_type.downcase || "application/unknown" # sometimes RubyMail gives us nil
504
+ content_type = (m.header.content_type || "application/unknown").downcase # sometimes RubyMail gives us nil
503
505
  [Chunk::Attachment.new(content_type, filename, m, sibling_types)]
504
506
 
505
507
  ## otherwise, it's body text
@@ -21,7 +21,7 @@ class ComposeMode < EditMessageMode
21
21
  end
22
22
 
23
23
  def self.spawn_nicely opts={}
24
- to = opts[:to] || BufferManager.ask_for_contacts(:people, "To: ", [opts[:to_default]]) or return
24
+ to = opts[:to] || (BufferManager.ask_for_contacts(:people, "To: ", [opts[:to_default]]) or return if ($config[:ask_for_to] != false))
25
25
  cc = opts[:cc] || (BufferManager.ask_for_contacts(:people, "Cc: ") or return if $config[:ask_for_cc])
26
26
  bcc = opts[:bcc] || (BufferManager.ask_for_contacts(:people, "Bcc: ") or return if $config[:ask_for_bcc])
27
27
  subj = opts[:subj] || (BufferManager.ask(:subject, "Subject: ") or return if $config[:ask_for_subject])
@@ -16,7 +16,7 @@ module CanAliasContacts
16
16
  end
17
17
 
18
18
  class ContactListMode < LineCursorMode
19
- LOAD_MORE_CONTACTS_NUM = 10
19
+ LOAD_MORE_CONTACTS_NUM = 100
20
20
 
21
21
  register_keymap do |k|
22
22
  k.add :load_more, "Load #{LOAD_MORE_CONTACTS_NUM} more contacts", 'M'
@@ -106,7 +106,7 @@ class ContactListMode < LineCursorMode
106
106
  end
107
107
 
108
108
  def load
109
- @num ||= buffer.content_height
109
+ @num ||= (buffer.content_height * 2)
110
110
  @user_contacts = ContactManager.contacts_with_aliases
111
111
  num = [@num - @user_contacts.length, 0].max
112
112
  BufferManager.say("Loading #{num} contacts from index...") do
@@ -29,9 +29,9 @@ class ForwardMode < EditMessageMode
29
29
  end
30
30
 
31
31
  def self.spawn_nicely opts={}
32
- to = opts[:to] || BufferManager.ask_for_contacts(:people, "To: ") or return
33
- cc = opts[:cc] || BufferManager.ask_for_contacts(:people, "Cc: ") or return if $config[:ask_for_cc]
34
- bcc = opts[:bcc] || BufferManager.ask_for_contacts(:people, "Bcc: ") or return if $config[:ask_for_bcc]
32
+ to = opts[:to] || (BufferManager.ask_for_contacts(:people, "To: ") or return if ($config[:ask_for_to] != false))
33
+ cc = opts[:cc] || (BufferManager.ask_for_contacts(:people, "Cc: ") or return if $config[:ask_for_cc])
34
+ bcc = opts[:bcc] || (BufferManager.ask_for_contacts(:people, "Bcc: ") or return if $config[:ask_for_bcc])
35
35
 
36
36
  attachment_hash = {}
37
37
  attachments = opts[:attachments] || []
@@ -10,7 +10,7 @@ class ThreadViewMode < LineCursorMode
10
10
  attr_accessor :state
11
11
  end
12
12
 
13
- DATE_FORMAT = "%B %e %Y %l:%M%P"
13
+ DATE_FORMAT = "%B %e %Y %l:%M%p"
14
14
  INDENT_SPACES = 2 # how many spaces to indent child messages
15
15
 
16
16
  HookManager.register "detailed-headers", <<EOS
@@ -202,12 +202,7 @@ EOS
202
202
  m = @message_lines[curpos] or return
203
203
  to = BufferManager.ask_for_contacts(:people, "Bounce To: ") or return
204
204
 
205
- defcmd = AccountManager.default_account.sendmail.sub(/\s(\-(ti|it|t))\b/) do |match|
206
- case "$1"
207
- when '-t' then ''
208
- else ' -i'
209
- end
210
- end
205
+ defcmd = AccountManager.default_account.bounce_sendmail
211
206
 
212
207
  cmd = case (hookcmd = HookManager.run "bounce-command", :from => m.from, :to => to)
213
208
  when nil, /^$/ then defcmd
@@ -254,7 +249,8 @@ EOS
254
249
  end
255
250
 
256
251
  def edit_labels
257
- reserved_labels = @thread.labels.select { |l| LabelManager::RESERVED_LABELS.include? l }
252
+ old_labels = @thread.labels
253
+ reserved_labels = old_labels.select { |l| LabelManager::RESERVED_LABELS.include? l }
258
254
  new_labels = BufferManager.ask_for_labels :label, "Labels for thread: ", @thread.labels
259
255
 
260
256
  return unless new_labels
@@ -262,6 +258,10 @@ EOS
262
258
  new_labels.each { |l| LabelManager << l }
263
259
  update
264
260
  UpdateManager.relay self, :labeled, @thread.first
261
+ UndoManager.register "labeling thread" do
262
+ @thread.labels = old_labels
263
+ UpdateManager.relay self, :labeled, @thread.first
264
+ end
265
265
  end
266
266
 
267
267
  def toggle_starred
@@ -476,6 +476,10 @@ EOS
476
476
  dispatch op do
477
477
  @thread.remove_label :inbox
478
478
  UpdateManager.relay self, :archived, @thread.first
479
+ UndoManager.register "archiving 1 thread" do
480
+ @thread.apply_label :inbox
481
+ UpdateManager.relay self, :unarchived, @thread.first
482
+ end
479
483
  end
480
484
  end
481
485
 
@@ -483,6 +487,10 @@ EOS
483
487
  dispatch op do
484
488
  @thread.apply_label :spam
485
489
  UpdateManager.relay self, :spammed, @thread.first
490
+ UndoManager.register "marking 1 thread as spam" do
491
+ @thread.remove_label :spam
492
+ UpdateManager.relay self, :unspammed, @thread.first
493
+ end
486
494
  end
487
495
  end
488
496
 
@@ -490,6 +498,10 @@ EOS
490
498
  dispatch op do
491
499
  @thread.apply_label :deleted
492
500
  UpdateManager.relay self, :deleted, @thread.first
501
+ UndoManager.register "deleting 1 thread" do
502
+ @thread.remove_label :deleted
503
+ UpdateManager.relay self, :undeleted, @thread.first
504
+ end
493
505
  end
494
506
  end
495
507
 
data/lib/sup/poll.rb CHANGED
@@ -45,9 +45,9 @@ EOS
45
45
  HookManager.run "before-poll"
46
46
 
47
47
  BufferManager.flash "Polling for new messages..."
48
- num, numi, from_and_subj, from_and_subj_inbox = @mode.poll
48
+ num, numi, from_and_subj, from_and_subj_inbox, loaded_labels = @mode.poll
49
49
  if num > 0
50
- BufferManager.flash "Loaded #{num.pluralize 'new message'}, #{numi} to inbox."
50
+ BufferManager.flash "Loaded #{num.pluralize 'new message'}, #{numi} to inbox. Labels: #{loaded_labels.map{|l| l.to_s}.join(', ')}"
51
51
  else
52
52
  BufferManager.flash "No new messages."
53
53
  end
@@ -76,6 +76,7 @@ EOS
76
76
  total_num = total_numi = 0
77
77
  from_and_subj = []
78
78
  from_and_subj_inbox = []
79
+ loaded_labels = Set.new
79
80
 
80
81
  @mutex.synchronize do
81
82
  SourceManager.usual_sources.each do |source|
@@ -107,6 +108,7 @@ EOS
107
108
  else
108
109
  yield "Found new message at #{m.source_info} with labels #{m.labels.to_a * ','}"
109
110
  add_new_message m
111
+ loaded_labels.merge m.labels
110
112
  num += 1
111
113
  from_and_subj << [m.from && m.from.longname, m.subj]
112
114
  if (m.labels & [:inbox, :spam, :deleted, :killed]) == Set.new([:inbox])
@@ -121,11 +123,12 @@ EOS
121
123
  total_numi += numi
122
124
  end
123
125
 
126
+ loaded_labels = loaded_labels - LabelManager::HIDDEN_RESERVED_LABELS - [:inbox, :killed]
124
127
  yield "Done polling; loaded #{total_num} new messages total"
125
128
  @last_poll = Time.now
126
129
  @polling = false
127
130
  end
128
- [total_num, total_numi, from_and_subj, from_and_subj_inbox]
131
+ [total_num, total_numi, from_and_subj, from_and_subj_inbox, loaded_labels]
129
132
  end
130
133
 
131
134
  ## like Source#each, but yields successive Message objects, which have their
data/lib/sup/textfield.rb CHANGED
@@ -102,12 +102,21 @@ class TextField
102
102
  Ncurses::Form::REQ_DEL_CHAR
103
103
  when Ncurses::KEY_BACKSPACE, 127 # 127 is also a backspace keysym
104
104
  Ncurses::Form::REQ_DEL_PREV
105
- when 1 #ctrl-a
105
+ when ?\C-a
106
+ nop
106
107
  Ncurses::Form::REQ_BEG_FIELD
107
- when 5 #ctrl-e
108
+ when ?\C-e
108
109
  Ncurses::Form::REQ_END_FIELD
109
- when 11 # ctrl-k
110
+ when ?\C-k
110
111
  Ncurses::Form::REQ_CLR_EOF
112
+ when ?\C-u
113
+ set_cursed_value cursed_value_after_point
114
+ Ncurses::Form.form_driver @form, Ncurses::Form::REQ_END_FIELD
115
+ nop
116
+ Ncurses::Form::REQ_BEG_FIELD
117
+ when ?\C-w
118
+ Ncurses::Form.form_driver @form, Ncurses::Form::REQ_PREV_CHAR
119
+ Ncurses::Form.form_driver @form, Ncurses::Form::REQ_DEL_WORD
111
120
  when Ncurses::KEY_UP, Ncurses::KEY_DOWN
112
121
  unless @history.empty?
113
122
  value = get_cursed_value
@@ -156,5 +165,17 @@ private
156
165
  def set_cursed_value v
157
166
  @field.set_field_buffer 0, v
158
167
  end
168
+
169
+ def cursed_value_after_point
170
+ point = Ncurses.curx - @question.length
171
+ get_cursed_value[point..-1]
172
+ end
173
+
174
+ ## this is almost certainly unnecessary, but it's the only way
175
+ ## i could get ncurses to remember my form's value
176
+ def nop
177
+ Ncurses::Form.form_driver @form, " "[0]
178
+ Ncurses::Form.form_driver @form, Ncurses::Form::REQ_DEL_PREV
179
+ end
159
180
  end
160
181
  end
@@ -3,7 +3,7 @@ require 'set'
3
3
 
4
4
  module Redwood
5
5
 
6
- # This index implementation uses Xapian for searching and GDBM for storage. It
6
+ # This index implementation uses Xapian for searching and storage. It
7
7
  # tends to be slightly faster than Ferret for indexing and significantly faster
8
8
  # for searching due to precomputing thread membership.
9
9
  class XapianIndex < BaseIndex
@@ -193,7 +193,7 @@ EOS
193
193
  query = {}
194
194
 
195
195
  subs = HookManager.run("custom-search", :subs => s) || s
196
- subs = s.gsub(/\b(to|from):(\S+)\b/) do
196
+ subs = subs.gsub(/\b(to|from):(\S+)\b/) do
197
197
  field, name = $1, $2
198
198
  if(p = ContactManager.contact_for(name))
199
199
  [field, p.email]
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sup
3
3
  version: !ruby/object:Gem::Version
4
- version: "0.9"
4
+ version: 0.9.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - William Morgan
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-10-01 14:34:52 -04:00
12
+ date: 2009-12-11 10:02:24 -05:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -209,8 +209,10 @@ files:
209
209
  - lib/sup/mbox/ssh-file.rb
210
210
  - lib/sup/mbox/loader.rb
211
211
  - lib/sup/mbox/ssh-loader.rb
212
- has_rdoc: false
212
+ has_rdoc: true
213
213
  homepage: http://sup.rubyforge.org/
214
+ licenses: []
215
+
214
216
  post_install_message:
215
217
  rdoc_options: []
216
218
 
@@ -231,9 +233,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
231
233
  requirements: []
232
234
 
233
235
  rubyforge_project:
234
- rubygems_version: 1.3.1
236
+ rubygems_version: 1.3.5
235
237
  signing_key:
236
- specification_version: 2
238
+ specification_version: 3
237
239
  summary: A console-based email client with the best features of GMail, mutt, and emacs. Features full text search, labels, tagged operations, multiple buffers, recent contacts, and more.
238
240
  test_files: []
239
241