bmf 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- checksums.yaml.gz.asc +11 -0
- data.tar.gz.asc +11 -0
- data/bin/bmf +8 -0
- data/lib/bmf.rb +70 -0
- data/lib/bmf/lib/address_store.rb +45 -0
- data/lib/bmf/lib/alert.rb +53 -0
- data/lib/bmf/lib/bmf.rb +364 -0
- data/lib/bmf/lib/folder.rb +76 -0
- data/lib/bmf/lib/message.rb +27 -0
- data/lib/bmf/lib/message_store.rb +250 -0
- data/lib/bmf/lib/settings.rb +74 -0
- data/lib/bmf/lib/thread_status.rb +98 -0
- data/lib/bmf/lib/xmlrpc_client.rb +27 -0
- data/lib/bmf/public/bitbrowser.css~ +15 -0
- data/lib/bmf/public/bitmessageforum.css +50 -0
- data/lib/bmf/public/css/bootstrap.min.css +9 -0
- data/lib/bmf/public/images/apple-touch-icon-114x114.png +0 -0
- data/lib/bmf/public/images/apple-touch-icon-144x144.png +0 -0
- data/lib/bmf/public/images/apple-touch-icon-57x57.png +0 -0
- data/lib/bmf/public/images/apple-touch-icon-72x72.png +0 -0
- data/lib/bmf/public/images/apple-touch-icon.png +0 -0
- data/lib/bmf/public/images/favicon.ico +0 -0
- data/lib/bmf/public/js/bootstrap.min.js +6 -0
- data/lib/bmf/public/js/html5.js +9 -0
- data/lib/bmf/public/js/jquery-1.10.1.min.js +6 -0
- data/lib/bmf/public/js/messagePoll.js +24 -0
- data/lib/bmf/views/addresses.haml +23 -0
- data/lib/bmf/views/compose.haml +38 -0
- data/lib/bmf/views/couldnt_reach_pybitmessage.haml +24 -0
- data/lib/bmf/views/home.haml +12 -0
- data/lib/bmf/views/https_quick_start.haml +71 -0
- data/lib/bmf/views/identities.haml +32 -0
- data/lib/bmf/views/layout.haml +128 -0
- data/lib/bmf/views/messages.haml +55 -0
- data/lib/bmf/views/settings.haml +18 -0
- data/lib/bmf/views/subscriptions.haml +40 -0
- data/lib/bmf/views/threads.haml +46 -0
- metadata +163 -0
- metadata.gz.asc +11 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f13d3e878a9392d5370d20f56ee5a3c27b94ea87
|
4
|
+
data.tar.gz: a67eb7df8c3c5673466d674e03e5b6a5fee54a73
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 32ff7dd7a9a1709d4b72a05f1d2fc28f6d1f231d133d4cd02e3aec073fb721036f2d92b4c0b809af764dee91c85c3fb8755a761a29bef7e67b5a0f5dec25084d
|
7
|
+
data.tar.gz: 3e892adcbe3ed2feddf347fa10dfa1a2c1b5b115a6e5c999cd58b1ff8b059cefce8f8906af90f25e7dd22fe199bf32512ef31101053854a0824c0a40ed4ec6a2
|
checksums.yaml.gz.asc
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
-----BEGIN PGP SIGNATURE-----
|
2
|
+
Version: GnuPG v1.4.12 (GNU/Linux)
|
3
|
+
|
4
|
+
iQEcBAABAgAGBQJR/lROAAoJEP5F5V2hilTWpm0H/32VyCSsOmBMr9UWs4Szcn+a
|
5
|
+
qjWp2oo0ROmVQnE2XWuPcljbMHw8jn05CsXM8b0pwkfPbJgnMNogQL/rOTGLWY1k
|
6
|
+
Qu5EDagZNJ2mxJuHjmMoOpQRZVf/ZiDImhpHKmMZbB9OmBousEB6XbR81dxDtwl/
|
7
|
+
VqltLS9RHWGW9mCbmjWsa6vqxsZ+YAEuRj2cmYcsHki0H6nhsQDoyeOgutai3p8a
|
8
|
+
C8alQdZQ4GS76145+yHp8uzaxT+VkoIamRTbwa5p5C6KEzXIvqfQ/XXnxOS2FlT4
|
9
|
+
gSm+578mG4T3dW9jNYWo5f7cX/5U2EoOoudMcyjQQO6fjjXL6QSsA0vKfohiipE=
|
10
|
+
=5m05
|
11
|
+
-----END PGP SIGNATURE-----
|
data.tar.gz.asc
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
-----BEGIN PGP SIGNATURE-----
|
2
|
+
Version: GnuPG v1.4.12 (GNU/Linux)
|
3
|
+
|
4
|
+
iQEcBAABAgAGBQJR/lRKAAoJEP5F5V2hilTWs2UH/j3lmnImIScuI9GY9cuz1Kj0
|
5
|
+
RJtRXtrwhx+7Ydmvn/gq7A24/YL7lRnWTfH8C0jT5UDk9bIxkzOJ3poxbOMnI+uf
|
6
|
+
pmpEF5xDkLQEzkjq+nr+ZMhwclZNiAZ2fdUO3urLOjq+HGQdXpRZhLazAQvYBYj3
|
7
|
+
5RH5d1g2QbZpRtPn93QvNSf4ZuEKS4Jagc7hmf6IY3AKHUs8pD7ESwQiGuv3Yqn4
|
8
|
+
nLU3Bct0G9qYPuxa+sMgoThhNFOoXFQm6CcSPfYlIb9OYp8ajhEwpuZ8WqJFvwuG
|
9
|
+
VpXdq8SkIaIowhsiCE22rgtWjsvJ7rQhxFRARvQVDLTiUZs9pPkM6gT0HLoCb+A=
|
10
|
+
=Mk+e
|
11
|
+
-----END PGP SIGNATURE-----
|
data/bin/bmf
ADDED
data/lib/bmf.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
3
|
+
module BMF
|
4
|
+
|
5
|
+
require_relative "bmf/lib/bmf.rb"
|
6
|
+
require_relative "bmf/lib/alert.rb"
|
7
|
+
|
8
|
+
def self.puts_and_alert msg
|
9
|
+
puts msg
|
10
|
+
Alert.instance << msg
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.sync
|
14
|
+
new_messages = MessageStore.instance.update
|
15
|
+
Alert.instance.add_new_messages(new_messages)
|
16
|
+
AddressStore.instance.update
|
17
|
+
|
18
|
+
rescue Errno::ECONNREFUSED => ex
|
19
|
+
puts_and_alert "Background sync. Couldn't connect to PyBitmessage server. Is it running with the API enabled? "
|
20
|
+
rescue JSON::ParserError => ex
|
21
|
+
puts_and_alert "Couldn't background sync. It seems like PyBitmessage is running but refused access. Do you have the correct info in config/settings.yml? "
|
22
|
+
rescue Exception => ex
|
23
|
+
puts_and_alert "Background Sync failed with #{ex.message}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.boot
|
27
|
+
puts "Doing initial sync before starting..."
|
28
|
+
sync
|
29
|
+
Alert.instance.pop_new_messages # don't show new message alert on bood.
|
30
|
+
|
31
|
+
Thread.new do
|
32
|
+
|
33
|
+
while(1) do
|
34
|
+
sync_interval = Settings.instance.sync_interval.to_i
|
35
|
+
sync_interval = 60 if sync_interval == 0
|
36
|
+
sleep(sync_interval)
|
37
|
+
begin
|
38
|
+
sync
|
39
|
+
rescue Exception => ex
|
40
|
+
msg = "Background sync faild with #{ex.message}"
|
41
|
+
Alert.instance << msg
|
42
|
+
puts msg
|
43
|
+
puts ex.backtrace.join("\n")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
BMF.run! do |server|
|
50
|
+
settings = Settings.instance
|
51
|
+
|
52
|
+
if (settings.https_server_key_file && settings.https_server_key_file != "") &&
|
53
|
+
(settings.https_server_certificate_file && settings.https_server_certificate_file != "")
|
54
|
+
|
55
|
+
puts "Requiring https..."
|
56
|
+
ssl_options = {
|
57
|
+
:cert_chain_file => settings.https_server_certificate_file,
|
58
|
+
:private_key_file => settings.https_server_key_file,
|
59
|
+
:verify_peer => false
|
60
|
+
}
|
61
|
+
server.ssl = true
|
62
|
+
server.ssl_options = ssl_options
|
63
|
+
else
|
64
|
+
puts "NOT requiring https. Traffic is unencrypted..."
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
require 'base64'
|
3
|
+
require 'json'
|
4
|
+
require 'thread'
|
5
|
+
|
6
|
+
require_relative 'xmlrpc_client.rb'
|
7
|
+
|
8
|
+
class BMF::AddressStore
|
9
|
+
include Singleton
|
10
|
+
|
11
|
+
# attr_reader :addresses
|
12
|
+
|
13
|
+
def addresses
|
14
|
+
Mutex.new.synchronize { @addresses.dup.freeze }
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@addresses = {}
|
19
|
+
# update
|
20
|
+
end
|
21
|
+
|
22
|
+
def log x
|
23
|
+
puts x
|
24
|
+
end
|
25
|
+
|
26
|
+
def update
|
27
|
+
address_infos = JSON.parse(BMF::XmlrpcClient.instance.listAddresses)['addresses']
|
28
|
+
|
29
|
+
lock = Mutex.new
|
30
|
+
|
31
|
+
lock.synchronize do
|
32
|
+
new_addresses = 0
|
33
|
+
|
34
|
+
address_infos.each do |address_info|
|
35
|
+
address = address_info['address']
|
36
|
+
if !@addresses.has_key? address
|
37
|
+
new_addresses += 1
|
38
|
+
@addresses[address] = address_info
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
log "Added #{new_addresses} addresses..." if new_addresses > 0
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
require 'thread'
|
3
|
+
|
4
|
+
class BMF::Alert
|
5
|
+
include Singleton
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@alerts = []
|
9
|
+
@new_messages = 0
|
10
|
+
end
|
11
|
+
|
12
|
+
def << alert
|
13
|
+
Mutex.new.synchronize do
|
14
|
+
if !@alerts.include? alert
|
15
|
+
@alerts << alert
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def peek
|
21
|
+
Mutex.new.synchronize do
|
22
|
+
@alerts.dup.freeze
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def pop
|
27
|
+
Mutex.new.synchronize do
|
28
|
+
alerts = @alerts.dup.freeze
|
29
|
+
@alerts = []
|
30
|
+
alerts
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def add_new_messages i
|
35
|
+
Mutex.new.synchronize do
|
36
|
+
@new_messages += i
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def peek_new_messages
|
41
|
+
Mutex.new.synchronize do
|
42
|
+
@new_messages
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def pop_new_messages
|
47
|
+
Mutex.new.synchronize do
|
48
|
+
i = @new_messages
|
49
|
+
@new_messages = 0
|
50
|
+
i
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lib/bmf/lib/bmf.rb
ADDED
@@ -0,0 +1,364 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'sinatra/reloader'
|
3
|
+
require 'sinatra/cookies'
|
4
|
+
|
5
|
+
require 'haml'
|
6
|
+
require 'rdiscount'
|
7
|
+
|
8
|
+
require_relative 'message_store.rb'
|
9
|
+
require_relative 'address_store.rb'
|
10
|
+
require_relative 'thread_status.rb'
|
11
|
+
require_relative 'message.rb'
|
12
|
+
require_relative 'settings.rb'
|
13
|
+
require_relative 'folder.rb'
|
14
|
+
|
15
|
+
require 'sanitize'
|
16
|
+
|
17
|
+
class BMF::BMF < Sinatra::Base
|
18
|
+
helpers Sinatra::Cookies
|
19
|
+
|
20
|
+
helpers do
|
21
|
+
|
22
|
+
def safe_html html
|
23
|
+
local_images_only = Sanitize::Config::RELAXED.dup
|
24
|
+
local_images_only[:protocols]["img"]["src"] = ["data"]
|
25
|
+
|
26
|
+
Sanitize.clean(html.force_encoding("UTF-8"), local_images_only)
|
27
|
+
end
|
28
|
+
|
29
|
+
# If we've got some html, make it safe
|
30
|
+
def safe_text text
|
31
|
+
markdown_content_type = "# Content-Type: text/markdown"
|
32
|
+
starts_with_markdown = text.strip.start_with? markdown_content_type
|
33
|
+
if !text.include?("<") && !starts_with_markdown
|
34
|
+
return "<blockquote>" + text.gsub("\n","<br />\n") + "</blockquote>"
|
35
|
+
end
|
36
|
+
|
37
|
+
if BMF::Settings.instance.display_sanitized_html != 'yes'
|
38
|
+
return "<blockquote>" + CGI::escape_html(text).gsub("\n", "<br />\n") + "</blockqoute>"
|
39
|
+
end
|
40
|
+
|
41
|
+
if text.strip.start_with? markdown_content_type
|
42
|
+
text = RDiscount.new(text.sub(markdown_content_type, "")).to_html
|
43
|
+
end
|
44
|
+
|
45
|
+
safe_html(text)
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
set :server, 'thin'
|
53
|
+
set :root, File.expand_path("../../", __FILE__)
|
54
|
+
set :layout, :layout
|
55
|
+
|
56
|
+
settings = BMF::Settings.instance
|
57
|
+
set :bind, settings.server_interface if settings.server_interface
|
58
|
+
set :port, settings.server_port if settings.server_port
|
59
|
+
|
60
|
+
configure :development do
|
61
|
+
register Sinatra::Reloader
|
62
|
+
end
|
63
|
+
|
64
|
+
if (settings.user && settings.user != "")
|
65
|
+
if (settings.password && settings.password != "")
|
66
|
+
puts "Requiring http basic authentication..."
|
67
|
+
use Rack::Auth::Basic, "Current BMF settings require authentication" do |username, password|
|
68
|
+
username == settings.user and password == settings.password
|
69
|
+
end
|
70
|
+
else
|
71
|
+
puts "You specified a username but no password! Refusing to use http basic authentication..."
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
get "/", :provides => :html do
|
76
|
+
haml :home
|
77
|
+
end
|
78
|
+
|
79
|
+
def load_settings
|
80
|
+
@settings = {}
|
81
|
+
|
82
|
+
BMF::Settings::VALID_SETTINGS.each do |key|
|
83
|
+
@settings[key] = BMF::Settings.instance.send(key)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
get "/configuring-pybitmessage/", :provides => :html do
|
88
|
+
haml :couldnt_reach_pybitmessage
|
89
|
+
end
|
90
|
+
|
91
|
+
get "/https-quick-start/", :provides => :html do
|
92
|
+
haml :https_quick_start
|
93
|
+
end
|
94
|
+
|
95
|
+
get "/json/new_messages/", :provides => :json do
|
96
|
+
{:new_messages => BMF::Alert.instance.peek_new_messages}.to_json
|
97
|
+
end
|
98
|
+
|
99
|
+
get "/identities/", :provides => :html do
|
100
|
+
BMF::AddressStore.instance.update
|
101
|
+
@addresses = BMF::AddressStore.instance.addresses
|
102
|
+
|
103
|
+
haml :identities
|
104
|
+
end
|
105
|
+
|
106
|
+
post "/identities/new/", :provides => :html do
|
107
|
+
if params[:label]
|
108
|
+
label = Base64.encode64(params[:label])
|
109
|
+
response = BMF::XmlrpcClient.instance.createRandomAddress label
|
110
|
+
if BMF::XmlrpcClient.is_error? response
|
111
|
+
halt(500, "Couldn't create address: #{response}")
|
112
|
+
else
|
113
|
+
haml("Created random address #{response} with label #{params[:label]}")
|
114
|
+
end
|
115
|
+
elsif params[:passphrase]
|
116
|
+
passphrase = Base64.encode64(params[:passphrase])
|
117
|
+
response = BMF::XmlrpcClient.instance.createDeterministicAddresses passphrase
|
118
|
+
if BMF::XmlrpcClient.is_error? response
|
119
|
+
halt(500, "Couldn't create address: #{response}")
|
120
|
+
else
|
121
|
+
addresses = JSON.parse(response)['addresses']
|
122
|
+
if addresses.empty?
|
123
|
+
haml("Address already exists")
|
124
|
+
else
|
125
|
+
haml("Created address #{addresses.join(', ')}")
|
126
|
+
end
|
127
|
+
end
|
128
|
+
else
|
129
|
+
raise "Bad submission"
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
get "/settings/", :provides => :html do
|
135
|
+
load_settings
|
136
|
+
haml :settings
|
137
|
+
end
|
138
|
+
|
139
|
+
post "/settings/update", :provides => :html do
|
140
|
+
params.each_pair do |key, value|
|
141
|
+
BMF::Settings.instance.update(key,value)
|
142
|
+
end
|
143
|
+
BMF::Settings.instance.persist
|
144
|
+
|
145
|
+
@flash = "BMF::Settings updated!"
|
146
|
+
|
147
|
+
load_settings
|
148
|
+
haml :settings
|
149
|
+
end
|
150
|
+
|
151
|
+
get "/messages/compose/", :provides => :html do
|
152
|
+
@to = params[:to]
|
153
|
+
@from = params[:from]
|
154
|
+
@subject = params[:subject]
|
155
|
+
|
156
|
+
if (@from.nil? || @from == "") && BMF::Settings.instance.default_send_address
|
157
|
+
@from = BMF::Settings.instance.default_send_address
|
158
|
+
end
|
159
|
+
|
160
|
+
if params[:reply_to]
|
161
|
+
@message = " \n------------------------------------------------------\n" + BMF::MessageStore.instance.messages[params[:reply_to]]['message']
|
162
|
+
else
|
163
|
+
@message = params[:message]
|
164
|
+
end
|
165
|
+
|
166
|
+
@message = "" if @message.nil?
|
167
|
+
if BMF::Settings.instance.sig
|
168
|
+
@message = " \n" + BMF::Settings.instance.sig + "\n" + @message
|
169
|
+
end
|
170
|
+
|
171
|
+
haml :compose
|
172
|
+
end
|
173
|
+
|
174
|
+
post "/messages/send/", :provides => :html do
|
175
|
+
to = params[:to]
|
176
|
+
from = params[:from]
|
177
|
+
subject = Base64.encode64(params[:subject])
|
178
|
+
message = Base64.encode64(params[:message])
|
179
|
+
broadcast = params[:broadcast]
|
180
|
+
|
181
|
+
|
182
|
+
res = "Sending message in background..."
|
183
|
+
|
184
|
+
Thread.new do
|
185
|
+
begin
|
186
|
+
if broadcast
|
187
|
+
res = BMF::XmlrpcClient.instance.sendBroadcast(from, subject, message)
|
188
|
+
else
|
189
|
+
res = BMF::XmlrpcClient.instance.sendMessage(to, from, subject, message)
|
190
|
+
end
|
191
|
+
|
192
|
+
if BMF::XmlrpcClient.is_error? res
|
193
|
+
BMF::Alert.instance << "BACKGROUND SEND FAILED! #{res}"
|
194
|
+
else
|
195
|
+
BMF::Alert.instance << "Background send seemed to finish successfully"
|
196
|
+
end
|
197
|
+
rescue Exception => ex
|
198
|
+
BMF::Alert.instance << "BACKGROUND SEND FAILED! #{ex.message}"
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
confirm_message = "Sending in background..."
|
203
|
+
if params[:goto] && params[:goto] != ""
|
204
|
+
BMF::Alert.instance << confirm_message
|
205
|
+
redirect params[:goto]
|
206
|
+
else
|
207
|
+
haml confirm_message
|
208
|
+
end
|
209
|
+
|
210
|
+
end
|
211
|
+
|
212
|
+
post "/messages/delete/", :provides => :html do
|
213
|
+
msgid = params[:msgid]
|
214
|
+
|
215
|
+
res = BMF::XmlrpcClient.instance.trashSentMessage(msgid)
|
216
|
+
if BMF::XmlrpcClient.is_error? res
|
217
|
+
halt(500, haml("Delete failed. #{res}"))
|
218
|
+
end
|
219
|
+
|
220
|
+
res = BMF::XmlrpcClient.instance.trashMessage(msgid)
|
221
|
+
if BMF::XmlrpcClient.is_error? res
|
222
|
+
halt(500, haml("Delete failed. #{res}"))
|
223
|
+
end
|
224
|
+
|
225
|
+
if request.referrer and request.referrer != ""
|
226
|
+
cookies[:flash] = res
|
227
|
+
redirect request.referrer
|
228
|
+
else
|
229
|
+
haml("#{res} [#{msgid}]")
|
230
|
+
end
|
231
|
+
|
232
|
+
end
|
233
|
+
|
234
|
+
get "/subscriptions/", :provides => :html do
|
235
|
+
|
236
|
+
res = BMF::XmlrpcClient.instance.listSubscriptions
|
237
|
+
|
238
|
+
if BMF::XmlrpcClient.is_error? res
|
239
|
+
@subscriptions = []
|
240
|
+
else
|
241
|
+
@subscriptions = JSON.parse(res)['subscriptions']
|
242
|
+
end
|
243
|
+
|
244
|
+
haml :subscriptions
|
245
|
+
end
|
246
|
+
|
247
|
+
post "/subscriptions/create/", :provides => :html do
|
248
|
+
res = BMF::XmlrpcClient.instance.addSubscription params[:address], Base64.encode64(params[:label])
|
249
|
+
|
250
|
+
if BMF::XmlrpcClient.is_error? res
|
251
|
+
halt(500, haml("Error subscribing. #{res}"))
|
252
|
+
else
|
253
|
+
haml("Subscribed. #{res}")
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
post "/subscriptions/delete/", :provides => :html do
|
258
|
+
res = BMF::XmlrpcClient.instance.deleteSubscription params[:address]
|
259
|
+
if BMF::XmlrpcClient.is_error? res
|
260
|
+
halt(500, haml("Error deleting subscrition. #{res}"))
|
261
|
+
else
|
262
|
+
haml("Subscription Deleted. #{res}")
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
|
267
|
+
get "/:folder/", :provides => :html do
|
268
|
+
folder = BMF::Folder.new(params[:folder])
|
269
|
+
@messages = folder.messages(:sort => :new)
|
270
|
+
@addresses = BMF::AddressStore.instance.addresses
|
271
|
+
haml :addresses
|
272
|
+
end
|
273
|
+
|
274
|
+
get "/:folder/:address/", :provides => :html do
|
275
|
+
@addresses = BMF::AddressStore.instance.addresses
|
276
|
+
folder = BMF::Folder.new(params[:folder])
|
277
|
+
@address = params[:address]
|
278
|
+
@threads = folder.threads_for_address(@address, :sort => :new)
|
279
|
+
|
280
|
+
halt(404, haml("Couldn't find any threads matching #{params[:address]}. Maybe you trashed them all.")) if @threads.nil?
|
281
|
+
|
282
|
+
haml :threads
|
283
|
+
end
|
284
|
+
|
285
|
+
get "/:folder/:address/:thread", :provides => :html do
|
286
|
+
@folder = BMF::Folder.new(params[:folder])
|
287
|
+
|
288
|
+
@address = params[:address]
|
289
|
+
|
290
|
+
@thread = CGI.unescape(params[:thread])
|
291
|
+
@messages = @folder.thread_messages(@address, @thread, :sort => :old)
|
292
|
+
|
293
|
+
halt(404, haml("Couldn't find any messages for thread #{params[:thread].inspect} for address #{params[:address].inspect}. Maybe you trashed the messages.")) if @messages.nil?
|
294
|
+
|
295
|
+
@addresses = BMF::AddressStore.instance.addresses
|
296
|
+
|
297
|
+
# Get the last time we visited thread, and update to now
|
298
|
+
@thread_last_visited = BMF::ThreadStatus.instance.thread_last_visited(@address,@thread)
|
299
|
+
BMF::ThreadStatus.instance.thread_visited(@address, @thread, BMF::Message.time(@messages.last)) if @messages.last
|
300
|
+
|
301
|
+
haml :messages
|
302
|
+
end
|
303
|
+
|
304
|
+
post "/:folder/thread/delete", :provides => :html do
|
305
|
+
folder = BMF::Folder.new params[:folder]
|
306
|
+
address = params[:address]
|
307
|
+
thread = params[:thread]
|
308
|
+
|
309
|
+
delete_statuses = folder.delete_thread(address, thread)
|
310
|
+
|
311
|
+
if !delete_statuses.empty?
|
312
|
+
delete_status_lines = delete_statuses.map { |x| "<li>#{x}</li>"}.join
|
313
|
+
haml ("Deleted:<ol>#{delete_status_lines}</ol>")
|
314
|
+
else
|
315
|
+
halt(500, haml("No messages found for this thread!"))
|
316
|
+
end
|
317
|
+
|
318
|
+
end
|
319
|
+
|
320
|
+
post "/:folder/thread/bulk_modify", :provides => :html do
|
321
|
+
folder = BMF::Folder.new(params[:folder])
|
322
|
+
address = params[:address]
|
323
|
+
|
324
|
+
update_action = params[:update_action]
|
325
|
+
threads_to_update = params.select { |key, value| key =~ /^thread__/}.values
|
326
|
+
|
327
|
+
updates_list = threads_to_update.map{|t| "<li>#{CGI.escape_html(t)}</li>"}.join
|
328
|
+
updates_list = "<ul>" + updates_list + "</ul>"
|
329
|
+
|
330
|
+
case update_action
|
331
|
+
when "noop"
|
332
|
+
status = "Noop. Did nothing to:"
|
333
|
+
when "delete"
|
334
|
+
address = params[:address]
|
335
|
+
threads_to_update.each do |thread|
|
336
|
+
folder.delete_thread(address, thread)
|
337
|
+
end
|
338
|
+
|
339
|
+
status = "Deleted the following threads:"
|
340
|
+
when "mark_read"
|
341
|
+
threads_to_update.each do |thread|
|
342
|
+
BMF::ThreadStatus.instance.thread_visited(address, thread, Time.now.to_i)
|
343
|
+
end
|
344
|
+
|
345
|
+
status = "Marked the following threads as read."
|
346
|
+
when "mark_all_read"
|
347
|
+
|
348
|
+
folder.threads_for_address(address).each do |thread, thread_info|
|
349
|
+
BMF::ThreadStatus.instance.thread_visited(address, thread, Time.now.to_i)
|
350
|
+
end
|
351
|
+
|
352
|
+
status = "Marked all threads as read."
|
353
|
+
else
|
354
|
+
raise "Unknown Action #{update_action}"
|
355
|
+
end
|
356
|
+
|
357
|
+
cookies[:flash] = "<div>#{status}#{updates_list}</div>"
|
358
|
+
redirect "/#{folder.name}/#{address}/"
|
359
|
+
end
|
360
|
+
|
361
|
+
run! if app_file == $0
|
362
|
+
|
363
|
+
end
|
364
|
+
|