bmf 0.2.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 +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
|
+
|