sup 0.14.1.1 → 0.15.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CONTRIBUTORS +14 -11
- data/History.txt +44 -0
- data/README.md +9 -4
- data/ReleaseNotes +8 -0
- data/bin/sup +1 -0
- data/bin/sup-add +2 -1
- data/bin/sup-config +3 -0
- data/bin/sup-sync-back-maildir +127 -0
- data/bin/{sup-sync-back → sup-sync-back-mbox} +3 -3
- data/lib/sup.rb +75 -3
- data/lib/sup/index.rb +54 -16
- data/lib/sup/label.rb +2 -2
- data/lib/sup/maildir.rb +120 -47
- data/lib/sup/mbox.rb +1 -1
- data/lib/sup/message.rb +65 -2
- data/lib/sup/modes/edit_message_mode.rb +16 -8
- data/lib/sup/modes/forward_mode.rb +13 -4
- data/lib/sup/modes/reply_mode.rb +6 -0
- data/lib/sup/modes/search_list_mode.rb +12 -0
- data/lib/sup/modes/thread_index_mode.rb +30 -0
- data/lib/sup/modes/thread_view_mode.rb +15 -5
- data/lib/sup/poll.rb +62 -17
- data/lib/sup/search.rb +18 -0
- data/lib/sup/sent.rb +1 -1
- data/lib/sup/source.rb +32 -4
- data/lib/sup/thread.rb +6 -0
- data/lib/sup/util.rb +12 -2
- data/lib/sup/util/query.rb +5 -2
- data/lib/sup/version.rb +1 -1
- metadata +17 -16
@@ -197,7 +197,15 @@ EOS
|
|
197
197
|
@file = Tempfile.new ["sup.#{self.class.name.gsub(/.*::/, '').camel_to_hyphy}", ".eml"]
|
198
198
|
@file.puts format_headers(@header - NON_EDITABLE_HEADERS).first
|
199
199
|
@file.puts
|
200
|
-
|
200
|
+
|
201
|
+
begin
|
202
|
+
text = @body.join("\n")
|
203
|
+
rescue Encoding::CompatibilityError
|
204
|
+
text = @body.map { |x| x.fix_encoding! }.join("\n")
|
205
|
+
debug "encoding problem while writing message, trying to rescue, but expect errors: #{text}"
|
206
|
+
end
|
207
|
+
|
208
|
+
@file.puts text
|
201
209
|
@file.puts sig if ($config[:edit_signature] and !@sig_edited)
|
202
210
|
@file.close
|
203
211
|
end
|
@@ -205,13 +213,13 @@ EOS
|
|
205
213
|
def set_sig_edit_flag
|
206
214
|
sig = sig_lines.join("\n")
|
207
215
|
if $config[:edit_signature]
|
208
|
-
pbody = @body.join("\n")
|
216
|
+
pbody = @body.map { |x| x.fix_encoding! }.join("\n").fix_encoding!
|
209
217
|
blen = pbody.length
|
210
218
|
slen = sig.length
|
211
219
|
|
212
220
|
if blen > slen and pbody[blen-slen..blen] == sig
|
213
221
|
@sig_edited = false
|
214
|
-
@body = pbody[0..blen-slen].split("\n")
|
222
|
+
@body = pbody[0..blen-slen].fix_encoding!.split("\n")
|
215
223
|
else
|
216
224
|
@sig_edited = true
|
217
225
|
end
|
@@ -319,7 +327,7 @@ EOS
|
|
319
327
|
end
|
320
328
|
|
321
329
|
def delete_attachment
|
322
|
-
i = curpos - @attachment_lines_offset - DECORATION_LINES -
|
330
|
+
i = curpos - @attachment_lines_offset - (@selectors.empty? ? 0 : DECORATION_LINES) - @selectors.size
|
323
331
|
if i >= 0 && i < @attachments.size && BufferManager.ask_yes_or_no("Delete attachment #{@attachment_names[i]}?")
|
324
332
|
@attachments.delete_at i
|
325
333
|
@attachment_names.delete_at i
|
@@ -551,9 +559,9 @@ protected
|
|
551
559
|
m.header[k] =
|
552
560
|
case v
|
553
561
|
when String
|
554
|
-
(k.match(/subject/i) ? mime_encode_subject(v) : mime_encode_address(v)).fix_encoding!
|
562
|
+
(k.match(/subject/i) ? mime_encode_subject(v).dup.fix_encoding! : mime_encode_address(v)).dup.fix_encoding!
|
555
563
|
when Array
|
556
|
-
(v.map { |v| mime_encode_address v }.join ", ").fix_encoding!
|
564
|
+
(v.map { |v| mime_encode_address v }.join ", ").dup.fix_encoding!
|
557
565
|
end
|
558
566
|
end
|
559
567
|
|
@@ -635,12 +643,12 @@ private
|
|
635
643
|
if HookManager.enabled? "mentions-attachments"
|
636
644
|
HookManager.run "mentions-attachments", :header => @header, :body => @body
|
637
645
|
else
|
638
|
-
@body.any? { |l| l =~ /^[^>]/ && l =~ /\battach(ment|ed|ing|)\b/i }
|
646
|
+
@body.any? { |l| l.fix_encoding! =~ /^[^>]/ && l.fix_encoding! =~ /\battach(ment|ed|ing|)\b/i }
|
639
647
|
end
|
640
648
|
end
|
641
649
|
|
642
650
|
def top_posting?
|
643
|
-
@body.join("\n") =~ /(\S+)\s*Excerpts from.*\n(>.*\n)+\s*\Z/
|
651
|
+
@body.map { |x| x.fix_encoding! }.join("\n").fix_encoding! =~ /(\S+)\s*Excerpts from.*\n(>.*\n)+\s*\Z/
|
644
652
|
end
|
645
653
|
|
646
654
|
def sig_lines
|
@@ -7,9 +7,10 @@ class ForwardMode < EditMessageMode
|
|
7
7
|
"From" => AccountManager.default_account.full_address,
|
8
8
|
}
|
9
9
|
|
10
|
+
@m = opts[:message]
|
10
11
|
header["Subject"] =
|
11
|
-
if
|
12
|
-
"Fwd: " +
|
12
|
+
if @m
|
13
|
+
"Fwd: " + @m.subj
|
13
14
|
elsif opts[:attachments]
|
14
15
|
"Fwd: " + opts[:attachments].keys.join(", ")
|
15
16
|
end
|
@@ -19,8 +20,8 @@ class ForwardMode < EditMessageMode
|
|
19
20
|
header["Bcc"] = opts[:bcc].map { |p| p.full_address }.join(", ") if opts[:bcc]
|
20
21
|
|
21
22
|
body =
|
22
|
-
if
|
23
|
-
forward_body_lines
|
23
|
+
if @m
|
24
|
+
forward_body_lines @m
|
24
25
|
elsif opts[:attachments]
|
25
26
|
["Note: #{opts[:attachments].size.pluralize 'attachment'}."]
|
26
27
|
end
|
@@ -68,6 +69,14 @@ protected
|
|
68
69
|
m.quotable_header_lines + [""] + m.quotable_body_lines +
|
69
70
|
["--- End forwarded message ---"]
|
70
71
|
end
|
72
|
+
|
73
|
+
def send_message
|
74
|
+
return unless super # super returns true if the mail has been sent
|
75
|
+
if @m
|
76
|
+
@m.add_label :forwarded
|
77
|
+
Index.save_message @m
|
78
|
+
end
|
79
|
+
end
|
71
80
|
end
|
72
81
|
|
73
82
|
end
|
data/lib/sup/modes/reply_mode.rb
CHANGED
@@ -145,6 +145,12 @@ protected
|
|
145
145
|
def rename_selected_search
|
146
146
|
old_name, num_unread = @searches[curpos]
|
147
147
|
return unless old_name
|
148
|
+
|
149
|
+
if SearchManager.predefined_searches.has_key? old_name
|
150
|
+
BufferManager.flash "Cannot be edited: predefined search."
|
151
|
+
return
|
152
|
+
end
|
153
|
+
|
148
154
|
new_name = BufferManager.ask :save_search, "Rename this saved search: ", old_name
|
149
155
|
return unless new_name && new_name !~ /^\s*$/ && new_name != old_name
|
150
156
|
new_name.strip!
|
@@ -163,6 +169,12 @@ protected
|
|
163
169
|
def edit_selected_search
|
164
170
|
name, num_unread = @searches[curpos]
|
165
171
|
return unless name
|
172
|
+
|
173
|
+
if SearchManager.predefined_searches.has_key? name
|
174
|
+
BufferManager.flash "Cannot be edited: predefined search."
|
175
|
+
return
|
176
|
+
end
|
177
|
+
|
166
178
|
old_search_string = SearchManager.search_string_for name
|
167
179
|
new_search_string = BufferManager.ask :search, "Edit this saved search: ", (old_search_string + " ")
|
168
180
|
return unless new_search_string && new_search_string !~ /^\s*$/ && new_search_string != old_search_string
|
@@ -200,6 +200,26 @@ EOS
|
|
200
200
|
BufferManager.draw_screen
|
201
201
|
end
|
202
202
|
|
203
|
+
def handle_updated_update sender, m
|
204
|
+
t = thread_containing(m) or return
|
205
|
+
l = @lines[t] or return
|
206
|
+
@ts_mutex.synchronize do
|
207
|
+
@ts.delete_message m
|
208
|
+
@ts.add_message m
|
209
|
+
end
|
210
|
+
Index.save_thread t
|
211
|
+
update_text_for_line l
|
212
|
+
end
|
213
|
+
|
214
|
+
def handle_location_deleted_update sender, m
|
215
|
+
t = thread_containing(m)
|
216
|
+
delete_thread t if t and t.first.id == m.id
|
217
|
+
@ts_mutex.synchronize do
|
218
|
+
@ts.delete_message m if t
|
219
|
+
end
|
220
|
+
update
|
221
|
+
end
|
222
|
+
|
203
223
|
def handle_single_message_deleted_update sender, m
|
204
224
|
@ts_mutex.synchronize do
|
205
225
|
return unless @ts.contains? m
|
@@ -755,6 +775,16 @@ protected
|
|
755
775
|
update
|
756
776
|
end
|
757
777
|
|
778
|
+
def delete_thread t
|
779
|
+
@mutex.synchronize do
|
780
|
+
i = @threads.index(t) or return
|
781
|
+
@threads.delete_at i
|
782
|
+
@size_widgets.delete_at i
|
783
|
+
@date_widgets.delete_at i
|
784
|
+
@tags.drop_tag_for t
|
785
|
+
end
|
786
|
+
end
|
787
|
+
|
758
788
|
def hide_thread t
|
759
789
|
@mutex.synchronize do
|
760
790
|
i = @threads.index(t) or return
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'shellwords'
|
2
|
+
|
1
3
|
module Redwood
|
2
4
|
|
3
5
|
class ThreadViewMode < LineCursorMode
|
@@ -246,6 +248,8 @@ EOS
|
|
246
248
|
sm.puts m.raw_message
|
247
249
|
end
|
248
250
|
raise SendmailCommandFailed, "Couldn't execute #{cmd}" unless $? == 0
|
251
|
+
m.add_label :forwarded
|
252
|
+
Index.save_message m
|
249
253
|
rescue SystemCallError, SendmailCommandFailed => e
|
250
254
|
warn "problem sending mail: #{e.message}"
|
251
255
|
BufferManager.flash "Problem sending mail: #{e.message}"
|
@@ -359,8 +363,14 @@ EOS
|
|
359
363
|
when Chunk::Attachment
|
360
364
|
default_dir = $config[:default_attachment_save_dir]
|
361
365
|
default_dir = ENV["HOME"] if default_dir.nil? || default_dir.empty?
|
362
|
-
default_fn = File.expand_path File.join(default_dir, chunk.filename)
|
363
|
-
fn = BufferManager.ask_for_filename :filename, "Save attachment to file: ", default_fn
|
366
|
+
default_fn = File.expand_path File.join(default_dir, Shellwords.escape(chunk.filename))
|
367
|
+
fn = BufferManager.ask_for_filename :filename, "Save attachment to file or directory: ", default_fn, true
|
368
|
+
|
369
|
+
# if user selects directory use file name from message
|
370
|
+
if fn and File.directory? fn
|
371
|
+
fn = File.join(fn, Shellwords.escape(chunk.filename))
|
372
|
+
end
|
373
|
+
|
364
374
|
save_to_file(fn) { |f| f.print chunk.raw_content } if fn
|
365
375
|
else
|
366
376
|
m = @message_lines[curpos]
|
@@ -382,7 +392,7 @@ EOS
|
|
382
392
|
num_errors = 0
|
383
393
|
m.chunks.each do |chunk|
|
384
394
|
next unless chunk.is_a?(Chunk::Attachment)
|
385
|
-
fn = File.join(folder, chunk.filename)
|
395
|
+
fn = File.join(folder, Shellwords.escape(chunk.filename))
|
386
396
|
num_errors += 1 unless save_to_file(fn, false) { |f| f.print chunk.raw_content }
|
387
397
|
num += 1
|
388
398
|
end
|
@@ -780,13 +790,13 @@ private
|
|
780
790
|
@person_lines[start] = m.from
|
781
791
|
[[prefix_widget, open_widget, new_widget, attach_widget, starred_widget,
|
782
792
|
[color,
|
783
|
-
"#{m.from ? m.from.mediumname : '?'} to #{m.recipients.map { |l| l.shortname }.join(', ')} #{m.date.to_nice_s} (#{m.date.to_nice_distance_s})"]]]
|
793
|
+
"#{m.from ? m.from.mediumname.fix_encoding! : '?'} to #{m.recipients.map { |l| l.shortname.fix_encoding! }.join(', ')} #{m.date.to_nice_s.fix_encoding!} (#{m.date.to_nice_distance_s.fix_encoding!})"]]]
|
784
794
|
|
785
795
|
when :closed
|
786
796
|
@person_lines[start] = m.from
|
787
797
|
[[prefix_widget, open_widget, new_widget, attach_widget, starred_widget,
|
788
798
|
[color,
|
789
|
-
"#{m.from ? m.from.mediumname : '?'}, #{m.date.to_nice_s} (#{m.date.to_nice_distance_s}) #{m.snippet}"]]]
|
799
|
+
"#{m.from ? m.from.mediumname.fix_encoding! : '?'}, #{m.date.to_nice_s.fix_encoding!} (#{m.date.to_nice_distance_s.fix_encoding!}) #{m.snippet ? m.snippet.fix_encoding! : ''}"]]]
|
790
800
|
|
791
801
|
when :detailed
|
792
802
|
@person_lines[start] = m.from
|
data/lib/sup/poll.rb
CHANGED
@@ -25,6 +25,9 @@ Variables:
|
|
25
25
|
num_total: the total number of messages
|
26
26
|
num_inbox_total: the total number of new messages in the inbox.
|
27
27
|
num_inbox_total_unread: the total number of unread messages in the inbox
|
28
|
+
num_updated: the total number of updated messages
|
29
|
+
num_deleted: the total number of deleted messages
|
30
|
+
labels: the labels that were applied
|
28
31
|
from_and_subj: an array of (from email address, subject) pairs
|
29
32
|
from_and_subj_inbox: an array of (from email address, subject) pairs for
|
30
33
|
only those messages appearing in the inbox
|
@@ -52,23 +55,32 @@ EOS
|
|
52
55
|
BufferManager.flash "Polling for new messages..."
|
53
56
|
end
|
54
57
|
|
55
|
-
num, numi, from_and_subj, from_and_subj_inbox, loaded_labels = @mode.poll
|
58
|
+
num, numi, numu, numd, from_and_subj, from_and_subj_inbox, loaded_labels = @mode.poll
|
56
59
|
clear_running_totals if @should_clear_running_totals
|
57
60
|
@running_totals[:num] += num
|
58
61
|
@running_totals[:numi] += numi
|
62
|
+
@running_totals[:numu] += numu
|
63
|
+
@running_totals[:numd] += numd
|
59
64
|
@running_totals[:loaded_labels] += loaded_labels || []
|
60
65
|
|
61
66
|
|
62
67
|
if HookManager.enabled? "after-poll"
|
63
68
|
hook_args = { :num => num, :num_inbox => numi,
|
64
69
|
:num_total => @running_totals[:num], :num_inbox_total => @running_totals[:numi],
|
70
|
+
:num_updated => @running_totals[:numu],
|
71
|
+
:num_deleted => @running_totals[:numd],
|
72
|
+
:labels => @running_totals[:loaded_labels],
|
65
73
|
:from_and_subj => from_and_subj, :from_and_subj_inbox => from_and_subj_inbox,
|
66
74
|
:num_inbox_total_unread => lambda { Index.num_results_for :labels => [:inbox, :unread] } }
|
67
75
|
|
68
76
|
HookManager.run("after-poll", hook_args)
|
69
77
|
else
|
70
78
|
if @running_totals[:num] > 0
|
71
|
-
|
79
|
+
flash_msg = "Loaded #{@running_totals[:num].pluralize 'new message'}, #{@running_totals[:numi]} to inbox. " if @running_totals[:num] > 0
|
80
|
+
flash_msg += "Updated #{@running_totals[:numu].pluralize 'message'}. " if @running_totals[:numu] > 0
|
81
|
+
flash_msg += "Deleted #{@running_totals[:numd].pluralize 'message'}. " if @running_totals[:numd] > 0
|
82
|
+
flash_msg += "Labels: #{@running_totals[:loaded_labels].map{|l| l.to_s}.join(', ')}." if @running_totals[:loaded_labels].size > 0
|
83
|
+
BufferManager.flash flash_msg
|
72
84
|
else
|
73
85
|
BufferManager.flash "No new messages."
|
74
86
|
end
|
@@ -115,7 +127,7 @@ EOS
|
|
115
127
|
end
|
116
128
|
|
117
129
|
def do_poll
|
118
|
-
total_num = total_numi = 0
|
130
|
+
total_num = total_numi = total_numu = total_numd = 0
|
119
131
|
from_and_subj = []
|
120
132
|
from_and_subj_inbox = []
|
121
133
|
loaded_labels = Set.new
|
@@ -129,16 +141,23 @@ EOS
|
|
129
141
|
next
|
130
142
|
end
|
131
143
|
|
132
|
-
|
133
|
-
numi = 0
|
144
|
+
msg = ""
|
145
|
+
num = numi = numu = numd = 0
|
134
146
|
poll_from source do |action,m,old_m,progress|
|
135
147
|
if action == :delete
|
136
148
|
yield "Deleting #{m.id}"
|
149
|
+
loaded_labels.merge m.labels
|
150
|
+
numd += 1
|
151
|
+
elsif action == :update
|
152
|
+
yield "Message at #{m.source_info} is an update of an old message. Updating labels from #{old_m.labels.to_a * ','} => #{m.labels.to_a * ','}"
|
153
|
+
loaded_labels.merge m.labels
|
154
|
+
numu += 1
|
137
155
|
elsif action == :add
|
138
156
|
if old_m
|
139
157
|
new_locations = (m.locations - old_m.locations)
|
140
158
|
if not new_locations.empty?
|
141
|
-
yield "Message at #{new_locations[0].info}
|
159
|
+
yield "Message at #{new_locations[0].info} has changed its source location. Updating labels from #{old_m.labels.to_a * ','} => #{m.labels.to_a * ','}"
|
160
|
+
numu += 1
|
142
161
|
else
|
143
162
|
yield "Skipping already-imported message at #{m.locations[-1].info}"
|
144
163
|
end
|
@@ -155,25 +174,29 @@ EOS
|
|
155
174
|
else fail
|
156
175
|
end
|
157
176
|
end
|
158
|
-
|
177
|
+
msg += "Found #{num} messages, #{numi} to inbox. " unless num == 0
|
178
|
+
msg += "Updated #{numu} messages. " unless numu == 0
|
179
|
+
msg += "Deleted #{numd} messages." unless numd == 0
|
180
|
+
yield msg unless msg == ""
|
159
181
|
total_num += num
|
160
182
|
total_numi += numi
|
183
|
+
total_numu += numu
|
184
|
+
total_numd += numd
|
161
185
|
end
|
162
186
|
|
163
187
|
loaded_labels = loaded_labels - LabelManager::HIDDEN_RESERVED_LABELS - [:inbox, :killed]
|
164
188
|
yield "Done polling; loaded #{total_num} new messages total"
|
165
189
|
@last_poll = Time.now
|
166
190
|
end
|
167
|
-
[total_num, total_numi, from_and_subj, from_and_subj_inbox, loaded_labels]
|
191
|
+
[total_num, total_numi, total_numu, total_numd, from_and_subj, from_and_subj_inbox, loaded_labels]
|
168
192
|
end
|
169
193
|
|
170
194
|
## like Source#poll, but yields successive Message objects, which have their
|
171
195
|
## labels and locations set correctly. The Messages are saved to or removed
|
172
196
|
## from the index after being yielded.
|
173
197
|
def poll_from source, opts={}
|
174
|
-
debug "trying to acquire poll lock for: #{source}
|
175
|
-
if source.
|
176
|
-
debug "lock acquired for: #{source}."
|
198
|
+
debug "trying to acquire poll lock for: #{source}..."
|
199
|
+
if source.try_lock
|
177
200
|
begin
|
178
201
|
source.poll do |sym, args|
|
179
202
|
case sym
|
@@ -191,18 +214,40 @@ EOS
|
|
191
214
|
yield :add, m, old_m, args[:progress] if block_given?
|
192
215
|
Index.sync_message m, true
|
193
216
|
|
217
|
+
if Index.message_joining_killed? m
|
218
|
+
m.labels += [:killed]
|
219
|
+
Index.sync_message m, true
|
220
|
+
end
|
221
|
+
|
194
222
|
## We need to add or unhide the message when it either did not exist
|
195
223
|
## before at all or when it was updated. We do *not* add/unhide when
|
196
224
|
## the same message was found at a different location
|
197
|
-
if
|
225
|
+
if old_m
|
226
|
+
UpdateManager.relay self, :updated, m
|
227
|
+
elsif !old_m or not old_m.locations.member? m.location
|
198
228
|
UpdateManager.relay self, :added, m
|
199
229
|
end
|
200
230
|
when :delete
|
201
|
-
Index.each_message
|
231
|
+
Index.each_message({:location => [source.id, args[:info]]}, false) do |m|
|
202
232
|
m.locations.delete Location.new(source, args[:info])
|
203
|
-
yield :delete, m, [source,args[:info]], args[:progress] if block_given?
|
204
233
|
Index.sync_message m, false
|
205
|
-
|
234
|
+
if m.locations.size == 0
|
235
|
+
yield :delete, m, [source,args[:info]], args[:progress] if block_given?
|
236
|
+
Index.delete m.id
|
237
|
+
UpdateManager.relay self, :location_deleted, m
|
238
|
+
end
|
239
|
+
end
|
240
|
+
when :update
|
241
|
+
Index.each_message({:location => [source.id, args[:old_info]]}, false) do |m|
|
242
|
+
old_m = Index.build_message m.id
|
243
|
+
m.locations.delete Location.new(source, args[:old_info])
|
244
|
+
m.locations.push Location.new(source, args[:new_info])
|
245
|
+
## Update labels that might have been modified remotely
|
246
|
+
m.labels -= source.supported_labels?
|
247
|
+
m.labels += args[:labels]
|
248
|
+
yield :update, m, old_m if block_given?
|
249
|
+
Index.sync_message m, true
|
250
|
+
UpdateManager.relay self, :updated, m
|
206
251
|
end
|
207
252
|
end
|
208
253
|
end
|
@@ -212,7 +257,7 @@ EOS
|
|
212
257
|
|
213
258
|
ensure
|
214
259
|
source.go_idle
|
215
|
-
source.
|
260
|
+
source.unlock
|
216
261
|
end
|
217
262
|
else
|
218
263
|
debug "source #{source} is already being polled."
|
@@ -221,7 +266,7 @@ EOS
|
|
221
266
|
|
222
267
|
def handle_idle_update sender, idle_since; @should_clear_running_totals = false; end
|
223
268
|
def handle_unidle_update sender, idle_since; @should_clear_running_totals = true; clear_running_totals; end
|
224
|
-
def clear_running_totals; @running_totals = {:num => 0, :numi => 0, :loaded_labels => Set.new}; end
|
269
|
+
def clear_running_totals; @running_totals = {:num => 0, :numi => 0, :numu => 0, :numd => 0, :loaded_labels => Set.new}; end
|
225
270
|
end
|
226
271
|
|
227
272
|
end
|
data/lib/sup/search.rb
CHANGED
@@ -7,6 +7,8 @@ class SearchManager
|
|
7
7
|
|
8
8
|
class ExpansionError < StandardError; end
|
9
9
|
|
10
|
+
attr_reader :predefined_searches
|
11
|
+
|
10
12
|
def initialize fn
|
11
13
|
@fn = fn
|
12
14
|
@searches = {}
|
@@ -43,24 +45,40 @@ class SearchManager
|
|
43
45
|
|
44
46
|
def add name, search_string
|
45
47
|
return unless valid_name? name
|
48
|
+
if @predefined_searches.has_key? name
|
49
|
+
warn "cannot add search: #{name} is already taken by a predefined search"
|
50
|
+
return
|
51
|
+
end
|
46
52
|
@searches[name] = search_string
|
47
53
|
@modified = true
|
48
54
|
end
|
49
55
|
|
50
56
|
def rename old, new
|
51
57
|
return unless @searches.has_key? old
|
58
|
+
if [old, new].any? { |x| @predefined_searches.has_key? x }
|
59
|
+
warn "cannot rename search: #{old} or #{new} is already taken by a predefined search"
|
60
|
+
return
|
61
|
+
end
|
52
62
|
search_string = @searches[old]
|
53
63
|
delete old if add new, search_string
|
54
64
|
end
|
55
65
|
|
56
66
|
def edit name, search_string
|
57
67
|
return unless @searches.has_key? name
|
68
|
+
if @predefined_searches.has_key? name
|
69
|
+
warn "cannot edit predefined search: #{name}."
|
70
|
+
return
|
71
|
+
end
|
58
72
|
@searches[name] = search_string
|
59
73
|
@modified = true
|
60
74
|
end
|
61
75
|
|
62
76
|
def delete name
|
63
77
|
return unless @searches.has_key? name
|
78
|
+
if @predefined_searches.has_key? name
|
79
|
+
warn "cannot delete predefined search: #{name}."
|
80
|
+
return
|
81
|
+
end
|
64
82
|
@searches.delete name
|
65
83
|
@modified = true
|
66
84
|
end
|