sup 0.15.4 → 0.16.0
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.
- checksums.yaml +5 -13
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/CONTRIBUTORS +16 -13
- data/History.txt +8 -0
- data/README.md +0 -3
- data/ReleaseNotes +10 -0
- data/bin/sup-psych-ify-config-files +5 -0
- data/lib/sup/interactive_lock.rb +47 -32
- data/lib/sup/mbox.rb +0 -2
- data/lib/sup/message_chunks.rb +18 -22
- data/lib/sup/modes/contact_list_mode.rb +1 -1
- data/lib/sup/modes/inbox_mode.rb +0 -42
- data/lib/sup/modes/thread_index_mode.rb +42 -0
- data/lib/sup/modes/thread_view_mode.rb +9 -0
- data/lib/sup/person.rb +1 -1
- data/lib/sup/source.rb +1 -1
- data/lib/sup/util.rb +8 -0
- data/lib/sup/version.rb +1 -1
- metadata +71 -76
- metadata.gz.sig +0 -0
- data/bin/sup-sync-back-mbox +0 -181
checksums.yaml
CHANGED
|
@@ -1,15 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
|
|
5
|
-
data.tar.gz: !binary |-
|
|
6
|
-
YTA5YmU2MDgwNGZkZDc1MjMxMzg0NmJiNTg3NDU5NDNlMWIwMTUzNw==
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 58f12f8b8d3223e51c43fad6ebad16a8621992cb
|
|
4
|
+
data.tar.gz: b5d08b2c0a7734cd83b4d0613ce209b2b81b757e
|
|
7
5
|
SHA512:
|
|
8
|
-
metadata.gz:
|
|
9
|
-
|
|
10
|
-
OTg1OTUyNzNiZTI0NTI1YWJjMmNhMjIwM2I3NTAyOWYzOWRmZmE5N2ExNGMy
|
|
11
|
-
NjJlMGRiYzMyZWE3ZDVhMzc2NDIwMWQ5OTMxNmI4YmQ3M2I3NTg=
|
|
12
|
-
data.tar.gz: !binary |-
|
|
13
|
-
NjcyZTBkMzMxYTU3OTg5Njc3NmNjOThhOGViYzYwZmUwODhkYTFkMWMxY2Nl
|
|
14
|
-
ZDE3NGE3MWY4YWZkNjU1MzYwZjc3MGE0MzU5NTRmOTQ5OWYzZTBiZmU2MTIx
|
|
15
|
-
YWI0ZDNiZGExZDNlNGM2NDAxMDk4MTAxOTNjMjhhMjJhZWNjMjM=
|
|
6
|
+
metadata.gz: 084e53c311359b9bcb0e97e57ebbb4d49b7a30a1697492522c8cd799fc86ce9b289c46ddc21a8b597a06f737923f2c6303c57bbf85343647f74e2c50fd68da85
|
|
7
|
+
data.tar.gz: 307daf56455e61012cb480d5bed83781a395c38233cdc545b1bf58d0bfac3286b66f580d3e3880e96e5b5338013c65388f8b3950af1630f3ba2be9a29ad1a148
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data.tar.gz.sig
CHANGED
|
Binary file
|
data/CONTRIBUTORS
CHANGED
|
@@ -18,10 +18,12 @@ Clint Byrum <clint at the ubuntu dot coms>
|
|
|
18
18
|
Marcus Williams <marcus-sup at the bar-coded dot nets>
|
|
19
19
|
Lionel Ott <white.magic at the gmx dot des>
|
|
20
20
|
Gaudenz Steinlin <gaudenz at the soziologie dot chs>
|
|
21
|
-
|
|
21
|
+
Matthieu Rakotojaona <matthieu.rakotojaona at the gmail dot coms>
|
|
22
22
|
Ingmar Vanhassel <ingmar at the exherbo dot orgs>
|
|
23
|
+
Mark Alexander <marka at the pobox dot coms>
|
|
23
24
|
Edward Z. Yang <ezyang at the mit dot edus>
|
|
24
|
-
|
|
25
|
+
Timon Vonk <timonv at the gmail dot coms>
|
|
26
|
+
julien@macbook <julien.stechele at the gmail dot coms>
|
|
25
27
|
Christopher Warrington <chrisw at the rice dot edus>
|
|
26
28
|
W. Trevor King <wking at the drexel dot edus>
|
|
27
29
|
Richard Brown <rbrown at the exherbo dot orgs>
|
|
@@ -29,13 +31,14 @@ Anthony Martinez <pi+sup at the pihost dot uss>
|
|
|
29
31
|
Marc Hartstein <marc.hartstein at the alum.vassar dot edus>
|
|
30
32
|
Israel Herraiz <israel.herraiz at the gmail dot coms>
|
|
31
33
|
Bo Borgerson <gigabo at the gmail dot coms>
|
|
34
|
+
Atte Kojo <atte.kojo at the reaktor dot fis>
|
|
32
35
|
Michael Hamann <michael at the content-space dot des>
|
|
33
|
-
Jonathan Lassoff <jof at the thejof dot coms>
|
|
34
36
|
William Erik Baxter <web at the superscript dot coms>
|
|
35
|
-
|
|
36
|
-
Adeodato Simó <dato at the net.com.org dot ess>
|
|
37
|
+
Jonathan Lassoff <jof at the thejof dot coms>
|
|
37
38
|
Markus Klinik <markus.klinik at the gmx dot des>
|
|
39
|
+
Grant Hollingworth <grant at the antiflux dot orgs>
|
|
38
40
|
Ico Doornekamp <ico at the pruts dot nls>
|
|
41
|
+
Adeodato Simó <dato at the net.com.org dot ess>
|
|
39
42
|
Daniel Schoepe <daniel.schoepe at the googlemail dot coms>
|
|
40
43
|
Jason Petsod <jason at the petsod dot orgs>
|
|
41
44
|
James Taylor <james at the jamestaylor dot orgs>
|
|
@@ -46,8 +49,8 @@ Decklin Foster <decklin at the red-bean dot coms>
|
|
|
46
49
|
Cameron Matheson <cam+sup at the cammunism dot orgs>
|
|
47
50
|
Carl Worth <cworth at the cworth dot orgs>
|
|
48
51
|
Alex Vandiver <alex at the chmrr dot nets>
|
|
49
|
-
Andrew Pimlott <andrew at the pimlott dot nets>
|
|
50
52
|
Jeff Balogh <its.jeff.balogh at the gmail dot coms>
|
|
53
|
+
Andrew Pimlott <andrew at the pimlott dot nets>
|
|
51
54
|
Matías Aguirre <matiasaguirre at the gmail dot coms>
|
|
52
55
|
Kornilios Kourtis <kkourt at the cslab.ece.ntua dot grs>
|
|
53
56
|
Lars Fischer <fischer at the wiwi.uni-siegen dot des>
|
|
@@ -58,18 +61,18 @@ Alvaro Herrera <alvherre at the alvh.no-ip dot orgs>
|
|
|
58
61
|
Steven Lawrance <stl at the koffein dot nets>
|
|
59
62
|
Jonah <Jonah at the GoodCoffee dot cas>
|
|
60
63
|
ian <itaylor at the uark dot edus>
|
|
61
|
-
|
|
64
|
+
MichaelRevell <mikearevell at the gmail dot coms>
|
|
62
65
|
Per Andersson <avtobiff at the gmail dot coms>
|
|
66
|
+
Todd Eisenberger <teisenbe at the andrew.cmu dot edus>
|
|
67
|
+
Gregor Hoffleit <gregor at the sam.mediasupervision dot des>
|
|
63
68
|
Adam Lloyd <adam at the alloy-d dot nets>
|
|
64
|
-
MichaelRevell <mikearevell at the gmail dot coms>
|
|
65
69
|
0xACE <0xACE at the users.noreply.github dot coms>
|
|
66
|
-
Gregor Hoffleit <gregor at the sam.mediasupervision dot des>
|
|
67
70
|
Steven Walter <swalter at the monarch.(none)>
|
|
68
|
-
|
|
69
|
-
|
|
71
|
+
Jon M. Dugan <jdugan at the es dot nets>
|
|
72
|
+
Horacio Sanson <horacio at the skillupjapan.co dot jps>
|
|
70
73
|
Matthias Vallentin <vallentin at the icir dot orgs>
|
|
71
74
|
akojo <atte.kojo at the gmail dot coms>
|
|
72
|
-
|
|
73
|
-
|
|
75
|
+
William A. Kennington III <william at the wkennington dot coms>
|
|
76
|
+
Stefan Lundström <lundst at the snabb.(none)>
|
|
74
77
|
Johannes Larsen <johs.a.larsen at the gmail dot coms>
|
|
75
78
|
Kirill Smelkov <kirr at the landau.phys.spbu dot rus>
|
data/History.txt
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
== 0.16.0 / 2014-03-21
|
|
2
|
+
|
|
3
|
+
* sup-sync-back-mbox removed.
|
|
4
|
+
* safer mime-view attachment file name handling
|
|
5
|
+
* show thread labels in thread-view-mode
|
|
6
|
+
* remove lock file if there is no sup alive
|
|
7
|
+
* deprecate migration script on ruby > 2.1
|
|
8
|
+
|
|
1
9
|
== 0.15.4 / 2014-02-06
|
|
2
10
|
|
|
3
11
|
* Various bugfixes
|
data/README.md
CHANGED
|
@@ -20,9 +20,6 @@ Features:
|
|
|
20
20
|
|
|
21
21
|
Current limitations:
|
|
22
22
|
|
|
23
|
-
* [Ruby 2.0 support][ruby20] is very fresh, consider it experimental. Patches
|
|
24
|
-
are welcome
|
|
25
|
-
|
|
26
23
|
* Sup does in general not play nicely with other mail clients, not all
|
|
27
24
|
changes can be synced back to the mail source. Refer to [Maildir Syncback][maildir-syncback]
|
|
28
25
|
in the wiki for this recently included feature. Maildir Syncback
|
data/ReleaseNotes
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
Release 0.16.0:
|
|
2
|
+
|
|
3
|
+
Removed unfinished and abandoned sup-sync-back-mbox.
|
|
4
|
+
|
|
5
|
+
Safer mime-view attachment file name handling, a temp file name is used
|
|
6
|
+
while the extension is only used if it is alphanumeric.
|
|
7
|
+
|
|
8
|
+
The migration script for YAML documents is now deprecated for ruby > 2.1
|
|
9
|
+
and will be removed in the future.
|
|
10
|
+
|
|
1
11
|
Release 0.15.4:
|
|
2
12
|
|
|
3
13
|
Bugfixes.
|
data/lib/sup/interactive_lock.rb
CHANGED
|
@@ -25,49 +25,64 @@ module InteractiveLock
|
|
|
25
25
|
begin
|
|
26
26
|
Index.lock
|
|
27
27
|
rescue Index::LockError => e
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
begin
|
|
29
|
+
Process.kill 0, e.pid.to_i # 0 signal test the existence of PID
|
|
30
|
+
stream.puts <<EOS
|
|
31
|
+
Error: the index is locked by another process! User '#{e.user}' on
|
|
32
|
+
host '#{e.host}' is running #{e.pname} with pid #{e.pid}.
|
|
33
|
+
The process was alive as of at least #{time_ago_in_words e.mtime} ago.
|
|
32
34
|
|
|
33
35
|
EOS
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
success = if $stdin.gets =~ /^\s*y(es)?\s*$/i
|
|
38
|
-
stream.puts "Ok, trying to kill process..."
|
|
39
|
-
|
|
40
|
-
begin
|
|
36
|
+
stream.print "Should I ask that process to kill itself (y/n)? "
|
|
37
|
+
stream.flush
|
|
38
|
+
if $stdin.gets =~ /^\s*y(es)?\s*$/i
|
|
41
39
|
Process.kill "TERM", e.pid.to_i
|
|
42
40
|
sleep DELAY
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
stream.puts "Let's try that again."
|
|
42
|
+
begin
|
|
43
|
+
Index.lock
|
|
44
|
+
rescue Index::LockError => e
|
|
45
|
+
stream.puts "I couldn't lock the index. The lockfile might just be stale."
|
|
46
|
+
stream.print "Should I just remove it and continue? (y/n) "
|
|
47
|
+
stream.flush
|
|
48
|
+
if $stdin.gets =~ /^\s*y(es)?\s*$/i
|
|
49
|
+
begin
|
|
50
|
+
FileUtils.rm e.path
|
|
51
|
+
rescue Errno::ENOENT
|
|
52
|
+
stream.puts "The lockfile doesn't exists. We continue."
|
|
53
|
+
end
|
|
54
|
+
stream.puts "Let's try that one more time."
|
|
55
|
+
begin
|
|
56
|
+
Index.lock
|
|
57
|
+
rescue Index::LockError => e
|
|
58
|
+
stream.puts "I couldn't unlock the index."
|
|
59
|
+
return false
|
|
60
|
+
end
|
|
61
|
+
return true
|
|
62
|
+
end
|
|
63
|
+
end
|
|
45
64
|
end
|
|
46
|
-
|
|
47
|
-
stream.puts "
|
|
65
|
+
rescue Errno::ESRCH # no such process
|
|
66
|
+
stream.puts "I couldn't lock the index. The lockfile might just be stale."
|
|
67
|
+
begin
|
|
68
|
+
FileUtils.rm e.path
|
|
69
|
+
rescue Errno::ENOENT
|
|
70
|
+
stream.puts "The lockfile doesn't exists. We continue."
|
|
71
|
+
end
|
|
72
|
+
stream.puts "Let's try that one more time."
|
|
48
73
|
begin
|
|
74
|
+
sleep DELAY
|
|
49
75
|
Index.lock
|
|
50
76
|
rescue Index::LockError => e
|
|
51
|
-
stream.puts "I couldn't
|
|
52
|
-
|
|
53
|
-
stream.flush
|
|
54
|
-
|
|
55
|
-
if $stdin.gets =~ /^\s*y(es)?\s*$/i
|
|
56
|
-
FileUtils.rm e.path
|
|
57
|
-
|
|
58
|
-
stream.puts "Let's try that one more time."
|
|
59
|
-
begin
|
|
60
|
-
Index.lock
|
|
61
|
-
true
|
|
62
|
-
rescue Index::LockError => e
|
|
63
|
-
end
|
|
64
|
-
end
|
|
77
|
+
stream.puts "I couldn't unlock the index."
|
|
78
|
+
return false
|
|
65
79
|
end
|
|
80
|
+
return true
|
|
66
81
|
end
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
success
|
|
82
|
+
stream.puts "Sorry, couldn't unlock the index."
|
|
83
|
+
return false
|
|
70
84
|
end
|
|
85
|
+
return true
|
|
71
86
|
end
|
|
72
87
|
end
|
|
73
88
|
|
data/lib/sup/mbox.rb
CHANGED
|
@@ -119,8 +119,6 @@ class MBox < Source
|
|
|
119
119
|
## we're just moving messages around on disk, than reading things
|
|
120
120
|
## into memory with raw_message.
|
|
121
121
|
##
|
|
122
|
-
## i hoped never to have to move shit around on disk but
|
|
123
|
-
## sup-sync-back-mbox has to do it.
|
|
124
122
|
def each_raw_message_line offset
|
|
125
123
|
@mutex.synchronize do
|
|
126
124
|
ensure_open
|
data/lib/sup/message_chunks.rb
CHANGED
|
@@ -60,8 +60,6 @@ end
|
|
|
60
60
|
module Redwood
|
|
61
61
|
module Chunk
|
|
62
62
|
class Attachment
|
|
63
|
-
## please see note in write_to_disk on important usage
|
|
64
|
-
## of quotes to avoid remote command injection.
|
|
65
63
|
HookManager.register "mime-decode", <<EOS
|
|
66
64
|
Decodes a MIME attachment into text form. The text will be displayed
|
|
67
65
|
directly in Sup. For attachments that you wish to use a separate program
|
|
@@ -79,8 +77,6 @@ Return value:
|
|
|
79
77
|
EOS
|
|
80
78
|
|
|
81
79
|
|
|
82
|
-
## please see note in write_to_disk on important usage
|
|
83
|
-
## of quotes to avoid remote command injection.
|
|
84
80
|
HookManager.register "mime-view", <<EOS
|
|
85
81
|
Views a non-text MIME attachment. This hook allows you to run
|
|
86
82
|
third-party programs for attachments that require such a thing (e.g.
|
|
@@ -132,8 +128,6 @@ EOS
|
|
|
132
128
|
when /^text\/plain\b/
|
|
133
129
|
@raw_content
|
|
134
130
|
else
|
|
135
|
-
## please see note in write_to_disk on important usage
|
|
136
|
-
## of quotes to avoid remote command injection.
|
|
137
131
|
HookManager.run "mime-decode", :content_type => @content_type,
|
|
138
132
|
:filename => lambda { write_to_disk },
|
|
139
133
|
:charset => encoded_content.charset,
|
|
@@ -171,8 +165,6 @@ EOS
|
|
|
171
165
|
def initial_state; :open end
|
|
172
166
|
def viewable?; @lines.nil? end
|
|
173
167
|
def view_default! path
|
|
174
|
-
## please see note in write_to_disk on important usage
|
|
175
|
-
## of quotes to avoid remote command injection.
|
|
176
168
|
case RbConfig::CONFIG['arch']
|
|
177
169
|
when /darwin/
|
|
178
170
|
cmd = "open #{path}"
|
|
@@ -185,28 +177,32 @@ EOS
|
|
|
185
177
|
end
|
|
186
178
|
|
|
187
179
|
def view!
|
|
188
|
-
|
|
189
|
-
## of quotes to avoid remote command injection.
|
|
190
|
-
write_to_disk do |file|
|
|
191
|
-
|
|
192
|
-
@@view_tempfiles.push file # make sure the tempfile is not garbage collected before sup stops
|
|
193
|
-
|
|
180
|
+
write_to_disk do |path|
|
|
194
181
|
ret = HookManager.run "mime-view", :content_type => @content_type,
|
|
195
|
-
:filename =>
|
|
196
|
-
ret || view_default!(
|
|
182
|
+
:filename => path
|
|
183
|
+
ret || view_default!(path)
|
|
197
184
|
end
|
|
198
185
|
end
|
|
199
186
|
|
|
200
|
-
## note that the path returned from write_to_disk is
|
|
201
|
-
## Shellwords.escaped and is intended to be used without single
|
|
202
|
-
## or double quotes. the use of either opens sup up for remote
|
|
203
|
-
## code injection through the file name.
|
|
204
187
|
def write_to_disk
|
|
205
188
|
begin
|
|
206
|
-
|
|
189
|
+
# Add the original extension to the generated tempfile name only if the
|
|
190
|
+
# extension is "safe" (won't be interpreted by the shell). Since
|
|
191
|
+
# Tempfile.new always generates safe file names this should prevent
|
|
192
|
+
# attacking the user with funny attachment file names.
|
|
193
|
+
tempname = if (File.extname @filename) =~ /^\.[[:alnum:]]+$/ then
|
|
194
|
+
["sup-attachment", File.extname(@filename)]
|
|
195
|
+
else
|
|
196
|
+
"sup-attachment"
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
file = Tempfile.new(tempname)
|
|
207
200
|
file.print @raw_content
|
|
208
201
|
file.flush
|
|
209
|
-
|
|
202
|
+
|
|
203
|
+
@@view_tempfiles.push file # make sure the tempfile is not garbage collected before sup stops
|
|
204
|
+
|
|
205
|
+
yield file.path if block_given?
|
|
210
206
|
return file.path
|
|
211
207
|
ensure
|
|
212
208
|
file.close
|
|
@@ -130,7 +130,7 @@ protected
|
|
|
130
130
|
def text_for_contact p
|
|
131
131
|
aalias = ContactManager.alias_for(p) || ""
|
|
132
132
|
[[:tagged_color, @tags.tagged?(p) ? ">" : " "],
|
|
133
|
-
[:
|
|
133
|
+
[:text_color, sprintf("%-#{@awidth}s %-#{@nwidth}s %s", aalias, p.name, p.email)]]
|
|
134
134
|
end
|
|
135
135
|
|
|
136
136
|
def regen_text
|
data/lib/sup/modes/inbox_mode.rb
CHANGED
|
@@ -6,7 +6,6 @@ class InboxMode < ThreadIndexMode
|
|
|
6
6
|
register_keymap do |k|
|
|
7
7
|
## overwrite toggle_archived with archive
|
|
8
8
|
k.add :archive, "Archive thread (remove from inbox)", 'a'
|
|
9
|
-
k.add :read_and_archive, "Archive thread (remove from inbox) and mark read", 'A'
|
|
10
9
|
k.add :refine_search, "Refine search", '|'
|
|
11
10
|
end
|
|
12
11
|
|
|
@@ -64,47 +63,6 @@ class InboxMode < ThreadIndexMode
|
|
|
64
63
|
threads.each { |t| Index.save_thread t }
|
|
65
64
|
end
|
|
66
65
|
|
|
67
|
-
def read_and_archive
|
|
68
|
-
return unless cursor_thread
|
|
69
|
-
thread = cursor_thread # to make sure lambda only knows about 'old' cursor_thread
|
|
70
|
-
|
|
71
|
-
was_unread = thread.labels.member? :unread
|
|
72
|
-
UndoManager.register "reading and archiving thread" do
|
|
73
|
-
thread.apply_label :inbox
|
|
74
|
-
thread.apply_label :unread if was_unread
|
|
75
|
-
add_or_unhide thread.first
|
|
76
|
-
Index.save_thread thread
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
cursor_thread.remove_label :unread
|
|
80
|
-
cursor_thread.remove_label :inbox
|
|
81
|
-
hide_thread cursor_thread
|
|
82
|
-
regen_text
|
|
83
|
-
Index.save_thread thread
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def multi_read_and_archive threads
|
|
87
|
-
old_labels = threads.map { |t| t.labels.dup }
|
|
88
|
-
|
|
89
|
-
threads.each do |t|
|
|
90
|
-
t.remove_label :unread
|
|
91
|
-
t.remove_label :inbox
|
|
92
|
-
hide_thread t
|
|
93
|
-
end
|
|
94
|
-
regen_text
|
|
95
|
-
|
|
96
|
-
UndoManager.register "reading and archiving #{threads.size.pluralize 'thread'}" do
|
|
97
|
-
threads.zip(old_labels).each do |t, l|
|
|
98
|
-
t.labels = l
|
|
99
|
-
add_or_unhide t.first
|
|
100
|
-
Index.save_thread t
|
|
101
|
-
end
|
|
102
|
-
regen_text
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
threads.each { |t| Index.save_thread t }
|
|
106
|
-
end
|
|
107
|
-
|
|
108
66
|
def handle_unarchived_update sender, m
|
|
109
67
|
add_or_unhide m
|
|
110
68
|
end
|
|
@@ -33,6 +33,7 @@ EOS
|
|
|
33
33
|
k.add_multi "Load all threads (! to confirm) :", '!' do |kk|
|
|
34
34
|
kk.add :load_all_threads, "Load all threads (may list a _lot_ of threads)", '!'
|
|
35
35
|
end
|
|
36
|
+
k.add :read_and_archive, "Archive thread (remove from inbox) and mark read", 'A'
|
|
36
37
|
k.add :cancel_search, "Cancel current search", :ctrl_g
|
|
37
38
|
k.add :reload, "Refresh view", '@'
|
|
38
39
|
k.add :toggle_archived, "Toggle archived status", 'a'
|
|
@@ -732,6 +733,47 @@ EOS
|
|
|
732
733
|
end
|
|
733
734
|
ignore_concurrent_calls :load_threads
|
|
734
735
|
|
|
736
|
+
def read_and_archive
|
|
737
|
+
return unless cursor_thread
|
|
738
|
+
thread = cursor_thread # to make sure lambda only knows about 'old' cursor_thread
|
|
739
|
+
|
|
740
|
+
was_unread = thread.labels.member? :unread
|
|
741
|
+
UndoManager.register "reading and archiving thread" do
|
|
742
|
+
thread.apply_label :inbox
|
|
743
|
+
thread.apply_label :unread if was_unread
|
|
744
|
+
add_or_unhide thread.first
|
|
745
|
+
Index.save_thread thread
|
|
746
|
+
end
|
|
747
|
+
|
|
748
|
+
cursor_thread.remove_label :unread
|
|
749
|
+
cursor_thread.remove_label :inbox
|
|
750
|
+
hide_thread cursor_thread
|
|
751
|
+
regen_text
|
|
752
|
+
Index.save_thread thread
|
|
753
|
+
end
|
|
754
|
+
|
|
755
|
+
def multi_read_and_archive threads
|
|
756
|
+
old_labels = threads.map { |t| t.labels.dup }
|
|
757
|
+
|
|
758
|
+
threads.each do |t|
|
|
759
|
+
t.remove_label :unread
|
|
760
|
+
t.remove_label :inbox
|
|
761
|
+
hide_thread t
|
|
762
|
+
end
|
|
763
|
+
regen_text
|
|
764
|
+
|
|
765
|
+
UndoManager.register "reading and archiving #{threads.size.pluralize 'thread'}" do
|
|
766
|
+
threads.zip(old_labels).each do |t, l|
|
|
767
|
+
t.labels = l
|
|
768
|
+
add_or_unhide t.first
|
|
769
|
+
Index.save_thread t
|
|
770
|
+
end
|
|
771
|
+
regen_text
|
|
772
|
+
end
|
|
773
|
+
|
|
774
|
+
threads.each { |t| Index.save_thread t }
|
|
775
|
+
end
|
|
776
|
+
|
|
735
777
|
def resize rows, cols
|
|
736
778
|
regen_text
|
|
737
779
|
super
|
|
@@ -692,6 +692,15 @@ EOS
|
|
|
692
692
|
end
|
|
693
693
|
end
|
|
694
694
|
|
|
695
|
+
|
|
696
|
+
def status
|
|
697
|
+
user_labels = @thread.labels.to_a.map do |l|
|
|
698
|
+
l.to_s if LabelManager.user_defined_labels.member?(l)
|
|
699
|
+
end.compact.join(",")
|
|
700
|
+
user_labels = (user_labels.empty? and "" or "<#{user_labels}>")
|
|
701
|
+
[user_labels, super].join(" -- ")
|
|
702
|
+
end
|
|
703
|
+
|
|
695
704
|
private
|
|
696
705
|
|
|
697
706
|
def initial_state_for m
|
data/lib/sup/person.rb
CHANGED
data/lib/sup/source.rb
CHANGED
data/lib/sup/util.rb
CHANGED
|
@@ -267,6 +267,14 @@ end
|
|
|
267
267
|
class String
|
|
268
268
|
def display_length
|
|
269
269
|
@display_length ||= Unicode.width(self.fix_encoding!, false)
|
|
270
|
+
|
|
271
|
+
# if Unicode.width fails and returns -1, fall back to
|
|
272
|
+
# regular String#length, see pull-request: #256.
|
|
273
|
+
if @display_length < 0
|
|
274
|
+
@display_length = self.length
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
@display_length
|
|
270
278
|
end
|
|
271
279
|
|
|
272
280
|
def slice_by_display_length len
|
data/lib/sup/version.rb
CHANGED
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.
|
|
4
|
+
version: 0.16.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- William Morgan
|
|
@@ -11,253 +11,248 @@ authors:
|
|
|
11
11
|
autorequire:
|
|
12
12
|
bindir: bin
|
|
13
13
|
cert_chain:
|
|
14
|
-
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
YXBuUHBzdEJxcWR2NjBSQjhITkd5ZEhRZUV6NnVzNXozbmorS2NoUHFKNjU3
|
|
37
|
-
RHo4b1gvTm02LzI0CjdRU1FwQ2g4eEJZZFNXRXBvSUUwelVTWTc3THRWVFJW
|
|
38
|
-
d0lyOXVEcFdUVHI5a0NWQklOQnNPUU5qV0tydUVXalYKK0pNdURzK2lXZWZw
|
|
39
|
-
RjRSM0J5U29PYzFRNFdvRVMzK29jMHFvMzdNc0FaeWZuUUlQVFpreUxaQ014
|
|
40
|
-
ZUw2TWhhNApoRmMyeUFOQmo4dm9hWTVDNzRDZzJWcUV4dGNuU2F4VXRXOXdD
|
|
41
|
-
NHc1aE9sZzBBVmZiMUpXemc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0t
|
|
42
|
-
Cg==
|
|
43
|
-
date: 2014-02-06 00:00:00.000000000 Z
|
|
14
|
+
- |
|
|
15
|
+
-----BEGIN CERTIFICATE-----
|
|
16
|
+
MIIDVDCCAjygAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQDDAJlZzEV
|
|
17
|
+
MBMGCgmSJomT8ixkARkWBWdhdXRlMRUwEwYKCZImiZPyLGQBGRYFdmV0c2oxEzAR
|
|
18
|
+
BgoJkiaJk/IsZAEZFgNjb20wHhcNMTMwNTA4MTAzODQ3WhcNMTQwNTA4MTAzODQ3
|
|
19
|
+
WjBQMQswCQYDVQQDDAJlZzEVMBMGCgmSJomT8ixkARkWBWdhdXRlMRUwEwYKCZIm
|
|
20
|
+
iZPyLGQBGRYFdmV0c2oxEzARBgoJkiaJk/IsZAEZFgNjb20wggEiMA0GCSqGSIb3
|
|
21
|
+
DQEBAQUAA4IBDwAwggEKAoIBAQC7sNc5zY4MrYB7eywE/aK2IoDqpM9lq4ZFlHzt
|
|
22
|
+
Pmq1LG6ah2lu/HfjqxiPoqwY7QkdSOGDLSk7G8YBqDA/tODhkPPSTqxBDzYyCO46
|
|
23
|
+
haWTtoN5tJkxIDJKp1nVXHi0Mlb4GJVKd9P0q95BeBYBfs8vyPN+y4b4Gebgx9U3
|
|
24
|
+
KqMDbe5h9MAPZGmtiRFMb3ugmiujDm7v8fACa5EtSvK/lxMkRDglecT/knE99NYI
|
|
25
|
+
l35SO/Bune1bxYmkwW64mQ4wRlGVeAnX+19msALfS9rdJL26dfW2LgqWi5QoVTBH
|
|
26
|
+
KNKTl/i3fxK0mzgtnoRCWdMJQFNNonFTnPUUawi1c9Kh4AdPAgMBAAGjOTA3MAkG
|
|
27
|
+
A1UdEwQCMAAwHQYDVR0OBBYEFJNCOxL0SWcbW2M+DIEUzAMz1bZsMAsGA1UdDwQE
|
|
28
|
+
AwIEsDANBgkqhkiG9w0BAQUFAAOCAQEAr3QUayd0geBDExO+WwzaEPAuUZ3zWQYG
|
|
29
|
+
G9vrplCkmJtjS/X/wVAef7Jn/V5MNkXKXsiOgXJXki+n7HulNZUf1rzr7Un96gVJ
|
|
30
|
+
1hq/ZTuapnPpstBqqdv60RB8HNGydHQeEz6us5z3nj+KchPqJ657Dz8oX/Nm6/24
|
|
31
|
+
7QSQpCh8xBYdSWEpoIE0zUSY77LtVTRVwIr9uDpWTTr9kCVBINBsOQNjWKruEWjV
|
|
32
|
+
+JMuDs+iWefpF4R3BySoOc1Q4WoES3+oc0qo37MsAZyfnQIPTZkyLZCMxeL6Mha4
|
|
33
|
+
hFc2yANBj8voaY5C74Cg2VqExtcnSaxUtW9wC4w5hOlg0AVfb1JWzg==
|
|
34
|
+
-----END CERTIFICATE-----
|
|
35
|
+
date: 2014-03-21 00:00:00.000000000 Z
|
|
44
36
|
dependencies:
|
|
45
37
|
- !ruby/object:Gem::Dependency
|
|
46
38
|
name: xapian-ruby
|
|
47
39
|
requirement: !ruby/object:Gem::Requirement
|
|
48
40
|
requirements:
|
|
49
|
-
- - ~>
|
|
41
|
+
- - "~>"
|
|
50
42
|
- !ruby/object:Gem::Version
|
|
51
43
|
version: 1.2.15
|
|
52
44
|
type: :runtime
|
|
53
45
|
prerelease: false
|
|
54
46
|
version_requirements: !ruby/object:Gem::Requirement
|
|
55
47
|
requirements:
|
|
56
|
-
- - ~>
|
|
48
|
+
- - "~>"
|
|
57
49
|
- !ruby/object:Gem::Version
|
|
58
50
|
version: 1.2.15
|
|
59
51
|
- !ruby/object:Gem::Dependency
|
|
60
52
|
name: ncursesw
|
|
61
53
|
requirement: !ruby/object:Gem::Requirement
|
|
62
54
|
requirements:
|
|
63
|
-
- - ~>
|
|
55
|
+
- - "~>"
|
|
64
56
|
- !ruby/object:Gem::Version
|
|
65
57
|
version: 1.4.0
|
|
66
58
|
type: :runtime
|
|
67
59
|
prerelease: false
|
|
68
60
|
version_requirements: !ruby/object:Gem::Requirement
|
|
69
61
|
requirements:
|
|
70
|
-
- - ~>
|
|
62
|
+
- - "~>"
|
|
71
63
|
- !ruby/object:Gem::Version
|
|
72
64
|
version: 1.4.0
|
|
73
65
|
- !ruby/object:Gem::Dependency
|
|
74
66
|
name: rmail-sup
|
|
75
67
|
requirement: !ruby/object:Gem::Requirement
|
|
76
68
|
requirements:
|
|
77
|
-
- - ~>
|
|
69
|
+
- - "~>"
|
|
78
70
|
- !ruby/object:Gem::Version
|
|
79
71
|
version: 1.0.1
|
|
80
72
|
type: :runtime
|
|
81
73
|
prerelease: false
|
|
82
74
|
version_requirements: !ruby/object:Gem::Requirement
|
|
83
75
|
requirements:
|
|
84
|
-
- - ~>
|
|
76
|
+
- - "~>"
|
|
85
77
|
- !ruby/object:Gem::Version
|
|
86
78
|
version: 1.0.1
|
|
87
79
|
- !ruby/object:Gem::Dependency
|
|
88
80
|
name: highline
|
|
89
81
|
requirement: !ruby/object:Gem::Requirement
|
|
90
82
|
requirements:
|
|
91
|
-
- -
|
|
83
|
+
- - ">="
|
|
92
84
|
- !ruby/object:Gem::Version
|
|
93
85
|
version: '0'
|
|
94
86
|
type: :runtime
|
|
95
87
|
prerelease: false
|
|
96
88
|
version_requirements: !ruby/object:Gem::Requirement
|
|
97
89
|
requirements:
|
|
98
|
-
- -
|
|
90
|
+
- - ">="
|
|
99
91
|
- !ruby/object:Gem::Version
|
|
100
92
|
version: '0'
|
|
101
93
|
- !ruby/object:Gem::Dependency
|
|
102
94
|
name: trollop
|
|
103
95
|
requirement: !ruby/object:Gem::Requirement
|
|
104
96
|
requirements:
|
|
105
|
-
- -
|
|
97
|
+
- - ">="
|
|
106
98
|
- !ruby/object:Gem::Version
|
|
107
99
|
version: '1.12'
|
|
108
100
|
type: :runtime
|
|
109
101
|
prerelease: false
|
|
110
102
|
version_requirements: !ruby/object:Gem::Requirement
|
|
111
103
|
requirements:
|
|
112
|
-
- -
|
|
104
|
+
- - ">="
|
|
113
105
|
- !ruby/object:Gem::Version
|
|
114
106
|
version: '1.12'
|
|
115
107
|
- !ruby/object:Gem::Dependency
|
|
116
108
|
name: lockfile
|
|
117
109
|
requirement: !ruby/object:Gem::Requirement
|
|
118
110
|
requirements:
|
|
119
|
-
- -
|
|
111
|
+
- - ">="
|
|
120
112
|
- !ruby/object:Gem::Version
|
|
121
113
|
version: '0'
|
|
122
114
|
type: :runtime
|
|
123
115
|
prerelease: false
|
|
124
116
|
version_requirements: !ruby/object:Gem::Requirement
|
|
125
117
|
requirements:
|
|
126
|
-
- -
|
|
118
|
+
- - ">="
|
|
127
119
|
- !ruby/object:Gem::Version
|
|
128
120
|
version: '0'
|
|
129
121
|
- !ruby/object:Gem::Dependency
|
|
130
122
|
name: mime-types
|
|
131
123
|
requirement: !ruby/object:Gem::Requirement
|
|
132
124
|
requirements:
|
|
133
|
-
- - ~>
|
|
125
|
+
- - "~>"
|
|
134
126
|
- !ruby/object:Gem::Version
|
|
135
127
|
version: '1.0'
|
|
136
128
|
type: :runtime
|
|
137
129
|
prerelease: false
|
|
138
130
|
version_requirements: !ruby/object:Gem::Requirement
|
|
139
131
|
requirements:
|
|
140
|
-
- - ~>
|
|
132
|
+
- - "~>"
|
|
141
133
|
- !ruby/object:Gem::Version
|
|
142
134
|
version: '1.0'
|
|
143
135
|
- !ruby/object:Gem::Dependency
|
|
144
136
|
name: locale
|
|
145
137
|
requirement: !ruby/object:Gem::Requirement
|
|
146
138
|
requirements:
|
|
147
|
-
- - ~>
|
|
139
|
+
- - "~>"
|
|
148
140
|
- !ruby/object:Gem::Version
|
|
149
141
|
version: '2.0'
|
|
150
142
|
type: :runtime
|
|
151
143
|
prerelease: false
|
|
152
144
|
version_requirements: !ruby/object:Gem::Requirement
|
|
153
145
|
requirements:
|
|
154
|
-
- - ~>
|
|
146
|
+
- - "~>"
|
|
155
147
|
- !ruby/object:Gem::Version
|
|
156
148
|
version: '2.0'
|
|
157
149
|
- !ruby/object:Gem::Dependency
|
|
158
150
|
name: chronic
|
|
159
151
|
requirement: !ruby/object:Gem::Requirement
|
|
160
152
|
requirements:
|
|
161
|
-
- - ~>
|
|
153
|
+
- - "~>"
|
|
162
154
|
- !ruby/object:Gem::Version
|
|
163
155
|
version: 0.9.1
|
|
164
156
|
type: :runtime
|
|
165
157
|
prerelease: false
|
|
166
158
|
version_requirements: !ruby/object:Gem::Requirement
|
|
167
159
|
requirements:
|
|
168
|
-
- - ~>
|
|
160
|
+
- - "~>"
|
|
169
161
|
- !ruby/object:Gem::Version
|
|
170
162
|
version: 0.9.1
|
|
171
163
|
- !ruby/object:Gem::Dependency
|
|
172
164
|
name: unicode
|
|
173
165
|
requirement: !ruby/object:Gem::Requirement
|
|
174
166
|
requirements:
|
|
175
|
-
- - ~>
|
|
167
|
+
- - "~>"
|
|
176
168
|
- !ruby/object:Gem::Version
|
|
177
169
|
version: 0.4.4
|
|
178
170
|
type: :runtime
|
|
179
171
|
prerelease: false
|
|
180
172
|
version_requirements: !ruby/object:Gem::Requirement
|
|
181
173
|
requirements:
|
|
182
|
-
- - ~>
|
|
174
|
+
- - "~>"
|
|
183
175
|
- !ruby/object:Gem::Version
|
|
184
176
|
version: 0.4.4
|
|
185
177
|
- !ruby/object:Gem::Dependency
|
|
186
178
|
name: bundler
|
|
187
179
|
requirement: !ruby/object:Gem::Requirement
|
|
188
180
|
requirements:
|
|
189
|
-
- - ~>
|
|
181
|
+
- - "~>"
|
|
190
182
|
- !ruby/object:Gem::Version
|
|
191
183
|
version: '1.3'
|
|
192
184
|
type: :development
|
|
193
185
|
prerelease: false
|
|
194
186
|
version_requirements: !ruby/object:Gem::Requirement
|
|
195
187
|
requirements:
|
|
196
|
-
- - ~>
|
|
188
|
+
- - "~>"
|
|
197
189
|
- !ruby/object:Gem::Version
|
|
198
190
|
version: '1.3'
|
|
199
191
|
- !ruby/object:Gem::Dependency
|
|
200
192
|
name: rake
|
|
201
193
|
requirement: !ruby/object:Gem::Requirement
|
|
202
194
|
requirements:
|
|
203
|
-
- -
|
|
195
|
+
- - ">="
|
|
204
196
|
- !ruby/object:Gem::Version
|
|
205
197
|
version: '0'
|
|
206
198
|
type: :development
|
|
207
199
|
prerelease: false
|
|
208
200
|
version_requirements: !ruby/object:Gem::Requirement
|
|
209
201
|
requirements:
|
|
210
|
-
- -
|
|
202
|
+
- - ">="
|
|
211
203
|
- !ruby/object:Gem::Version
|
|
212
204
|
version: '0'
|
|
213
205
|
- !ruby/object:Gem::Dependency
|
|
214
206
|
name: minitest
|
|
215
207
|
requirement: !ruby/object:Gem::Requirement
|
|
216
208
|
requirements:
|
|
217
|
-
- - ~>
|
|
209
|
+
- - "~>"
|
|
218
210
|
- !ruby/object:Gem::Version
|
|
219
211
|
version: '4.7'
|
|
220
212
|
type: :development
|
|
221
213
|
prerelease: false
|
|
222
214
|
version_requirements: !ruby/object:Gem::Requirement
|
|
223
215
|
requirements:
|
|
224
|
-
- - ~>
|
|
216
|
+
- - "~>"
|
|
225
217
|
- !ruby/object:Gem::Version
|
|
226
218
|
version: '4.7'
|
|
227
219
|
- !ruby/object:Gem::Dependency
|
|
228
220
|
name: rr
|
|
229
221
|
requirement: !ruby/object:Gem::Requirement
|
|
230
222
|
requirements:
|
|
231
|
-
- - ~>
|
|
223
|
+
- - "~>"
|
|
232
224
|
- !ruby/object:Gem::Version
|
|
233
225
|
version: 1.0.5
|
|
234
226
|
type: :development
|
|
235
227
|
prerelease: false
|
|
236
228
|
version_requirements: !ruby/object:Gem::Requirement
|
|
237
229
|
requirements:
|
|
238
|
-
- - ~>
|
|
230
|
+
- - "~>"
|
|
239
231
|
- !ruby/object:Gem::Version
|
|
240
232
|
version: 1.0.5
|
|
241
233
|
- !ruby/object:Gem::Dependency
|
|
242
234
|
name: gpgme
|
|
243
235
|
requirement: !ruby/object:Gem::Requirement
|
|
244
236
|
requirements:
|
|
245
|
-
- -
|
|
237
|
+
- - ">="
|
|
246
238
|
- !ruby/object:Gem::Version
|
|
247
239
|
version: 2.0.2
|
|
248
240
|
type: :development
|
|
249
241
|
prerelease: false
|
|
250
242
|
version_requirements: !ruby/object:Gem::Requirement
|
|
251
243
|
requirements:
|
|
252
|
-
- -
|
|
244
|
+
- - ">="
|
|
253
245
|
- !ruby/object:Gem::Version
|
|
254
246
|
version: 2.0.2
|
|
255
|
-
description:
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
247
|
+
description: |2
|
|
248
|
+
Sup is a console-based email client for people with a lot of email.
|
|
249
|
+
|
|
250
|
+
* GMail-like thread-centered archiving, tagging and muting
|
|
251
|
+
* Handling mail from multiple mbox and Maildir sources
|
|
252
|
+
* Blazing fast full-text search with a rich query language
|
|
253
|
+
* Multiple accounts - pick the right one when sending mail
|
|
254
|
+
* Ruby-programmable hooks
|
|
255
|
+
* Automatically tracking recent contacts
|
|
261
256
|
email: sup-talk@rubyforge.org
|
|
262
257
|
executables:
|
|
263
258
|
- sup
|
|
@@ -268,7 +263,6 @@ executables:
|
|
|
268
263
|
- sup-recover-sources
|
|
269
264
|
- sup-sync
|
|
270
265
|
- sup-sync-back-maildir
|
|
271
|
-
- sup-sync-back-mbox
|
|
272
266
|
- sup-tweak-labels
|
|
273
267
|
- sup-psych-ify-config-files
|
|
274
268
|
extensions: []
|
|
@@ -288,7 +282,6 @@ files:
|
|
|
288
282
|
- bin/sup-recover-sources
|
|
289
283
|
- bin/sup-sync
|
|
290
284
|
- bin/sup-sync-back-maildir
|
|
291
|
-
- bin/sup-sync-back-mbox
|
|
292
285
|
- bin/sup-tweak-labels
|
|
293
286
|
- lib/sup.rb
|
|
294
287
|
- lib/sup/account.rb
|
|
@@ -359,26 +352,28 @@ homepage: http://supmua.org
|
|
|
359
352
|
licenses:
|
|
360
353
|
- GPL-2
|
|
361
354
|
metadata: {}
|
|
362
|
-
post_install_message:
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
355
|
+
post_install_message: |
|
|
356
|
+
SUP: If you are upgrading Sup from before version 0.14.0: Please
|
|
357
|
+
run `sup-psych-ify-config-files` to migrate from 0.13.
|
|
358
|
+
|
|
359
|
+
Check https://github.com/sup-heliotrope/sup/wiki/Migration-0.13-to-0.14
|
|
360
|
+
for more detailed and up-to-date instructions.
|
|
366
361
|
rdoc_options: []
|
|
367
362
|
require_paths:
|
|
368
363
|
- lib
|
|
369
364
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
370
365
|
requirements:
|
|
371
|
-
- -
|
|
366
|
+
- - ">="
|
|
372
367
|
- !ruby/object:Gem::Version
|
|
373
368
|
version: 1.9.2
|
|
374
369
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
375
370
|
requirements:
|
|
376
|
-
- -
|
|
371
|
+
- - ">="
|
|
377
372
|
- !ruby/object:Gem::Version
|
|
378
373
|
version: '0'
|
|
379
374
|
requirements: []
|
|
380
375
|
rubyforge_project:
|
|
381
|
-
rubygems_version: 2.2.
|
|
376
|
+
rubygems_version: 2.2.2
|
|
382
377
|
signing_key:
|
|
383
378
|
specification_version: 4
|
|
384
379
|
summary: A console-based email client with the best features of GMail, mutt and Emacs
|
metadata.gz.sig
CHANGED
|
Binary file
|
data/bin/sup-sync-back-mbox
DELETED
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
|
|
3
|
-
$:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
|
|
4
|
-
|
|
5
|
-
require 'rubygems'
|
|
6
|
-
require 'uri'
|
|
7
|
-
require 'tempfile'
|
|
8
|
-
require 'trollop'
|
|
9
|
-
require "sup"
|
|
10
|
-
|
|
11
|
-
fail "not working yet"
|
|
12
|
-
|
|
13
|
-
## save a message 'm' to an open file pointer 'fp'
|
|
14
|
-
def save m, fp
|
|
15
|
-
m.source.each_raw_message_line(m.source_info) { |l| fp.print l }
|
|
16
|
-
end
|
|
17
|
-
def die msg
|
|
18
|
-
$stderr.puts "Error: #{msg}"
|
|
19
|
-
exit(-1)
|
|
20
|
-
end
|
|
21
|
-
def has_any_from_source_with_label? index, source, label
|
|
22
|
-
query = { :source_id => source.id, :label => label, :limit => 1, :load_spam => true, :load_deleted => true, :load_killed => true }
|
|
23
|
-
index.num_results_for(query) != 0
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
opts = Trollop::options do
|
|
27
|
-
version "sup-sync-back-mbox (sup #{Redwood::VERSION})"
|
|
28
|
-
banner <<EOS
|
|
29
|
-
Drop or move messages from Sup sources that are marked as deleted or
|
|
30
|
-
spam in the Sup index.
|
|
31
|
-
|
|
32
|
-
Currently only works with mbox sources.
|
|
33
|
-
|
|
34
|
-
Usage:
|
|
35
|
-
sup-sync-back-mbox [options] <source>*
|
|
36
|
-
|
|
37
|
-
where <source>* is zero or more source URIs. If no sources are given,
|
|
38
|
-
sync back all usual sources.
|
|
39
|
-
|
|
40
|
-
You almost certainly want to run sup-sync --changed after this command.
|
|
41
|
-
Running this does not change the index.
|
|
42
|
-
|
|
43
|
-
Options include:
|
|
44
|
-
EOS
|
|
45
|
-
opt :drop_deleted, "Drop deleted messages.", :default => false, :short => "d"
|
|
46
|
-
opt :move_deleted, "Move deleted messages to a local mbox file.", :type => String, :short => :none
|
|
47
|
-
opt :drop_spam, "Drop spam messages.", :default => false, :short => "s"
|
|
48
|
-
opt :move_spam, "Move spam messages to a local mbox file.", :type => String, :short => :none
|
|
49
|
-
|
|
50
|
-
opt :with_dotlockfile, "Specific dotlockfile location (mbox files only).", :default => "/usr/bin/dotlockfile", :short => :none
|
|
51
|
-
opt :dont_use_dotlockfile, "Don't use dotlockfile to lock mbox files. Dangerous if other processes modify them concurrently.", :default => false, :short => :none
|
|
52
|
-
|
|
53
|
-
opt :verbose, "Print message ids as they're processed."
|
|
54
|
-
opt :dry_run, "Don't actually modify the index. Probably only useful with --verbose.", :short => "-n"
|
|
55
|
-
opt :version, "Show version information", :short => :none
|
|
56
|
-
|
|
57
|
-
conflicts :drop_deleted, :move_deleted
|
|
58
|
-
conflicts :drop_spam, :move_spam
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
unless opts[:drop_deleted] || opts[:move_deleted] || opts[:drop_spam] || opts[:move_spam]
|
|
62
|
-
puts <<EOS
|
|
63
|
-
Nothing to do. Please specify at least one of --drop-deleted, --move-deleted,
|
|
64
|
-
--drop-spam, or --move-spam.
|
|
65
|
-
EOS
|
|
66
|
-
|
|
67
|
-
exit
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
Redwood::start
|
|
71
|
-
index = Redwood::Index.init
|
|
72
|
-
index.lock_interactively or exit
|
|
73
|
-
|
|
74
|
-
deleted_fp, spam_fp = nil
|
|
75
|
-
unless opts[:dry_run]
|
|
76
|
-
deleted_fp = File.open(opts[:move_deleted], "a") if opts[:move_deleted]
|
|
77
|
-
spam_fp = File.open(opts[:move_spam], "a") if opts[:move_spam]
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
dotlockfile = opts[:with_dotlockfile] || "/usr/bin/dotlockfile"
|
|
81
|
-
|
|
82
|
-
begin
|
|
83
|
-
index.load
|
|
84
|
-
|
|
85
|
-
sources = ARGV.map do |uri|
|
|
86
|
-
s = Redwood::SourceManager.source_for(uri) or die "unknown source: #{uri}. Did you add it with sup-add first?"
|
|
87
|
-
s.is_a?(Redwood::MBox) or die "#{uri} is not an mbox source."
|
|
88
|
-
s
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
if sources.empty?
|
|
92
|
-
sources = Redwood::SourceManager.usual_sources.select { |s| s.is_a? Redwood::MBox }
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
unless sources.all? { |s| s.file_path.nil? } || File.executable?(dotlockfile) || opts[:dont_use_dotlockfile]
|
|
96
|
-
die <<EOS
|
|
97
|
-
can't execute dotlockfile binary: #{dotlockfile}. Specify --with-dotlockfile
|
|
98
|
-
if it's in a nonstandard location, or, if you want to live dangerously, try
|
|
99
|
-
--dont-use-dotlockfile
|
|
100
|
-
EOS
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
modified_sources = []
|
|
104
|
-
sources.each do |source|
|
|
105
|
-
$stderr.puts "Scanning #{source}..."
|
|
106
|
-
|
|
107
|
-
unless ((opts[:drop_deleted] || opts[:move_deleted]) && has_any_from_source_with_label?(index, source, :deleted)) || ((opts[:drop_spam] || opts[:move_spam]) && has_any_from_source_with_label?(index, source, :spam))
|
|
108
|
-
$stderr.puts "Nothing to do from this source; skipping"
|
|
109
|
-
next
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
source.reset!
|
|
113
|
-
num_dropped = num_moved = num_scanned = 0
|
|
114
|
-
|
|
115
|
-
out_fp = Tempfile.new "sup-sync-back-mbox-#{source.id}"
|
|
116
|
-
Redwood::PollManager.each_message_from source do |m|
|
|
117
|
-
num_scanned += 1
|
|
118
|
-
|
|
119
|
-
if(m_old = index.build_message(m.id))
|
|
120
|
-
labels = m_old.labels
|
|
121
|
-
|
|
122
|
-
if labels.member? :deleted
|
|
123
|
-
if opts[:drop_deleted]
|
|
124
|
-
puts "Dropping deleted message #{source}##{m.source_info}" if opts[:verbose]
|
|
125
|
-
num_dropped += 1
|
|
126
|
-
elsif opts[:move_deleted] && labels.member?(:deleted)
|
|
127
|
-
puts "Moving deleted message #{source}##{m.source_info}" if opts[:verbose]
|
|
128
|
-
save m, deleted_fp unless opts[:dry_run]
|
|
129
|
-
num_moved += 1
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
elsif labels.member? :spam
|
|
133
|
-
if opts[:drop_spam]
|
|
134
|
-
puts "Dropping spam message #{source}##{m.source_info}" if opts[:verbose]
|
|
135
|
-
num_dropped += 1
|
|
136
|
-
elsif opts[:move_spam] && labels.member?(:spam)
|
|
137
|
-
puts "Moving spam message #{source}##{m.source_info}" if opts[:verbose]
|
|
138
|
-
save m, spam_fp unless opts[:dry_run]
|
|
139
|
-
num_moved += 1
|
|
140
|
-
end
|
|
141
|
-
else
|
|
142
|
-
save m, out_fp unless opts[:dry_run]
|
|
143
|
-
end
|
|
144
|
-
else
|
|
145
|
-
save m, out_fp unless opts[:dry_run]
|
|
146
|
-
end
|
|
147
|
-
end
|
|
148
|
-
$stderr.puts "Scanned #{num_scanned}, dropped #{num_dropped}, moved #{num_moved} messages from #{source}."
|
|
149
|
-
modified_sources << source if num_dropped > 0 || num_moved > 0
|
|
150
|
-
out_fp.close unless opts[:dry_run]
|
|
151
|
-
|
|
152
|
-
unless opts[:dry_run] || (num_dropped == 0 && num_moved == 0)
|
|
153
|
-
deleted_fp.flush if deleted_fp
|
|
154
|
-
spam_fp.flush if spam_fp
|
|
155
|
-
unless opts[:dont_use_dotlockfile]
|
|
156
|
-
puts "Locking #{source.file_path}..."
|
|
157
|
-
system "#{opts[:dotlockfile]} -l #{source.file_path}"
|
|
158
|
-
puts "Writing #{source.file_path}..."
|
|
159
|
-
FileUtils.cp out_fp.path, source.file_path
|
|
160
|
-
puts "Unlocking #{source.file_path}..."
|
|
161
|
-
system "#{opts[:dotlockfile]} -u #{source.file_path}"
|
|
162
|
-
end
|
|
163
|
-
end
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
unless opts[:dry_run]
|
|
167
|
-
deleted_fp.close if deleted_fp
|
|
168
|
-
spam_fp.close if spam_fp
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
$stderr.puts "Done."
|
|
172
|
-
unless modified_sources.empty?
|
|
173
|
-
$stderr.puts "You should now run: sup-sync --changed #{modified_sources.join(' ')}"
|
|
174
|
-
end
|
|
175
|
-
rescue Exception => e
|
|
176
|
-
File.open("sup-exception-log.txt", "w") { |f| f.puts e.backtrace }
|
|
177
|
-
raise
|
|
178
|
-
ensure
|
|
179
|
-
Redwood::finish
|
|
180
|
-
index.unlock
|
|
181
|
-
end
|