ruby_gntp 0.1.1 → 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.
data/ChangeLog CHANGED
@@ -16,3 +16,15 @@
16
16
  == Version 0.1.1 - 2009/4/17
17
17
  * Add NOTE to example directory.
18
18
 
19
+ == Version 0.1.2 - 2009/08/15
20
+ * Enabled password authentication mainly for sending notifications to a network machine.
21
+
22
+ == Version 0.1.3 - 2009/08/19
23
+ * Added notification icon sending.
24
+ * Now sends out Origin-X headers.
25
+ * Use \r\n instead of \n in the header lines.
26
+
27
+ == Version 0.2.0 - 2009/11/03
28
+ * Merge spidahman's commits. Lot of thanks, spidahman!
29
+ * Add some test(spec).
30
+
data/lib/ruby_gntp.rb CHANGED
@@ -29,6 +29,7 @@
29
29
  #
30
30
  #}}}
31
31
  require 'socket'
32
+ require 'digest/md5'
32
33
 
33
34
  #$DEBUG = true
34
35
 
@@ -36,13 +37,17 @@ class TooFewParametersError < Exception
36
37
  end
37
38
 
38
39
  class GNTP
39
- attr_reader :app_name, :target_host, :target_port
40
+ attr_reader :app_name, :target_host, :target_port, :password
40
41
  attr_reader :message if $DEBUG
41
42
 
42
- def initialize(app_name = 'Ruby/GNTP', host = 'localhost', port = 23053)
43
+ RUBY_GNTP_NAME = 'ruby_gntp'
44
+ RUBY_GNTP_VERSION = '0.1.3.1'
45
+
46
+ def initialize(app_name = 'Ruby/GNTP', host = 'localhost', password = '', port = 23053)
43
47
  @app_name = app_name
44
48
  @target_host = host
45
49
  @target_port = port
50
+ @password = password
46
51
  end
47
52
 
48
53
  #
@@ -53,36 +58,37 @@ class GNTP
53
58
  raise TooFewParametersError, "Need least one 'notification' for register" unless @notifications
54
59
 
55
60
  @app_icon = params[:app_icon]
61
+ @binaries = []
62
+
63
+ @message = register_header(@app_name, @app_icon)
64
+ @message << output_origin_headers
56
65
 
57
- @message = <<EOF
58
- GNTP/1.0 REGISTER NONE
59
- Application-Name: #{@app_name}
60
- Notifications-Count: #{@notifications.size}
61
- EOF
62
- @message << "Application-Icon: #{@app_icon}\n" if @app_icon
63
- @message << "\n"
66
+ @message << "Notifications-Count: #{@notifications.size}\r\n"
67
+ @message << "\r\n"
64
68
 
65
69
  @notifications.each do |notification|
66
70
  name = notification[:name]
67
- disp_name = notification[:disp_name]
71
+ disp_name = notification[:disp_name] || name
68
72
  enabled = notification[:enabled] || true
69
73
  icon = notification[:icon]
70
74
 
71
- @message += <<EOF
72
- Notification-Name: #{name}
73
- EOF
74
- @message << "Notification-Display-Name: #{disp_name}\n" if disp_name
75
- @message << "Notification-Enabled: #{enabled}\n" if enabled
76
- @message << "Notification-Icon: #{icon}\n" if icon
77
- @message << "\n"
75
+ @message << "Notification-Name: #{name}\r\n"
76
+ @message << "Notification-Enabled: #{enabled ? 'True' : 'False'}\r\n"
77
+ @message << "Notification-Display-Name: #{disp_name}\r\n"
78
+ @message << "#{handle_icon(icon, 'Notification')}\r\n" if icon
78
79
  end
79
80
 
81
+ @binaries.each {|binary|
82
+ @message << output_binary(binary)
83
+ }
84
+
85
+ @message << "\r\n"
86
+
80
87
  unless (ret = send_and_recieve(@message))
81
88
  raise "Register failed"
82
89
  end
83
90
  end
84
91
 
85
-
86
92
  #
87
93
  # notify
88
94
  #
@@ -95,16 +101,16 @@ EOF
95
101
  icon = params[:icon] || get_notification_icon(name)
96
102
  sticky = params[:sticky]
97
103
 
98
- @message = <<EOF
99
- GNTP/1.0 NOTIFY NONE
100
- Application-Name: #{@app_name}
101
- Notification-Name: #{name}
102
- Notification-Title: #{title}
103
- EOF
104
- @message << "Notification-Text: #{text}\n" if text
105
- @message << "Notification-Sticky: #{sticky}\n" if sticky
106
- @message << "Notification-Icon: #{icon}\n" if icon
107
- @message << "\n"
104
+ @binaries = []
105
+
106
+ @message = notify_header(app_name, name, title, text, sticky, icon)
107
+ @message << output_origin_headers
108
+
109
+ @binaries.each {|binary|
110
+ @message << output_binary(binary)
111
+ }
112
+
113
+ @message << "\r\n"
108
114
 
109
115
  unless (ret = send_and_recieve(@message))
110
116
  raise "Notify failed"
@@ -116,7 +122,11 @@ EOF
116
122
  # instant notification
117
123
  #
118
124
  def self.notify(params)
119
- growl = GNTP.new(params[:app_name])
125
+ host = params[:host]
126
+ passwd = params[:passwd]
127
+
128
+ growl = GNTP.new(params[:app_name], host, passwd)
129
+
120
130
  notification = params
121
131
  notification[:name] = params[:app_name] || "Ruby/GNTP notification"
122
132
  growl.register(:notifications => [
@@ -131,7 +141,6 @@ EOF
131
141
  # send and recieve
132
142
  #
133
143
  def send_and_recieve msg
134
- msg.gsub!(/\n/, "\r\n")
135
144
  print msg if $DEBUG
136
145
 
137
146
  sock = TCPSocket.open(@target_host, @target_port)
@@ -156,29 +165,132 @@ EOF
156
165
  return nil unless notification
157
166
  return notification[:icon]
158
167
  end
168
+
169
+ #
170
+ # outputs the registration header
171
+ #
172
+ def register_header(app_name, app_icon)
173
+ message = "#{get_gntp_header_start('REGISTER')}\r\n"
174
+ message << "Application-Name: #{app_name}\r\n"
175
+ message << "#{handle_icon(@app_icon, 'Application')}\r\n" if app_icon
176
+ message
177
+ end
178
+
179
+ #
180
+ # outputs the notification header
181
+ #
182
+ def notify_header(app_name, name, title, text, sticky, icon)
183
+ message = "#{get_gntp_header_start('NOTIFY')}\r\n"
184
+ message << "Application-Name: #{@app_name}\r\n"
185
+ message << "Notification-Name: #{name}\r\n"
186
+ message << "Notification-Title: #{title}\r\n"
187
+ message << "Notification-Text: #{text}\r\n" if text
188
+ message << "Notification-Sticky: #{sticky}\r\n" if sticky
189
+ message << "#{handle_icon(icon, 'Notification')}\r\n" if icon
190
+ message
191
+ end
192
+
193
+ def output_origin_headers
194
+ message = "Origin-Machine-Name: #{Socket.gethostname}\r\n"
195
+ message << "Origin-Software-Name: #{RUBY_GNTP_NAME}\r\n"
196
+ message << "Origin-Software-Version: #{RUBY_GNTP_VERSION}\r\n"
197
+
198
+ platformname, platformversion = '', ''
199
+
200
+ if ENV['OS']
201
+ ver = `ver`
202
+ if ver.index('[')
203
+ matches = ver.scan(/(.*)\[+(.*)\]+/)[0]
204
+ platformname, platformversion = matches[0], matches[1]
205
+ else
206
+ platformname, platformversion = 'Microsoft Windows', ver
207
+ end
208
+ else
209
+ platformname, platformversion = `uname -s`, `uname -r`
210
+ end
211
+
212
+ message << "Origin-Platform-Name: #{platformname.strip}\r\n"
213
+ message << "Origin-Platform-Version: #{platformversion.strip}\r\n"
214
+ end
215
+
216
+ #
217
+ # get start of the GNTP header
218
+ #
219
+ def get_gntp_header_start(type)
220
+ if @password.empty?
221
+ "GNTP/1.0 #{type} NONE"
222
+ else
223
+ saltvar = Time.now.to_s
224
+ salt = Digest::MD5.digest(saltvar)
225
+ salthash = Digest::MD5.hexdigest(saltvar)
226
+ key = Digest::MD5.digest("#{@password}#{salt}")
227
+ keyhash = Digest::MD5.hexdigest(key)
228
+ "GNTP/1.0 #{type} NONE MD5:#{keyhash}.#{salthash}"
229
+ end
230
+ end
231
+
232
+ #
233
+ # figure out how to handle the icon
234
+ # a URL icon just gets put into the header
235
+ # a file icon gets read and stored, ready to be appended to the end of the request
236
+ #
237
+ def handle_icon(icon, type)
238
+ if File.exists?(icon) && @target_host != 'localhost'
239
+ file = File.new(icon)
240
+ data = file.read
241
+ size = data.length
242
+ if size > 0
243
+ binary = {
244
+ :size => size,
245
+ :data => data,
246
+ :uniqueid => Digest::MD5.hexdigest(data)
247
+ }
248
+ @binaries << binary
249
+ "#{type}-Icon: x-growl-resource://#{binary[:uniqueid]}"
250
+ end
251
+ else
252
+ "#{type}-Icon: #{icon}"
253
+ end
254
+ end
255
+
256
+ #
257
+ # outputs any binary data to be sent
258
+ #
259
+ def output_binary(binary)
260
+ message = "\r\n"
261
+ message << "Identifier: #{binary[:uniqueid]}\r\n"
262
+ message << "Length: #{binary[:size]}\r\n"
263
+ message << "\r\n"
264
+ message << "#{binary[:data]}\r\n"
265
+ end
159
266
  end
160
267
 
161
268
  #----------------------------
162
269
  # self test code
163
270
  if __FILE__ == $0
271
+ host = ARGV[0] || 'loaclhost'
272
+ passwd = host && ARGV[1]
273
+
164
274
  #--- Use standard notification method ('register' first then 'notify')
165
- growl = GNTP.new("Ruby/GNTP self test")
166
- growl.register({:notifications => [{
275
+ growl = GNTP.new("Ruby/GNTP self test", host, passwd)
276
+ growl.register(:notifications => [{
167
277
  :name => "notify",
168
- :enabled => true,
169
- }]})
278
+ :enabled => true
279
+ }])
170
280
 
171
- growl.notify({
281
+ growl.notify(
172
282
  :name => "notify",
173
283
  :title => "Congraturation",
174
284
  :text => "Congraturation! You are successful install ruby_gntp.",
175
285
  :icon => "http://www.hatena.ne.jp/users/sn/snaka72/profile.gif",
176
- :sticky=> true,
177
- })
286
+ :sticky=> true
287
+ )
178
288
 
179
289
  #--- Use instant notification method (just 'notify')
180
290
  GNTP.notify({
181
291
  :app_name => "Instant notify",
292
+ :host => host,
293
+ :passwd => passwd,
182
294
  :title => "Instant notification",
183
295
  :text => "Instant notification available now.",
184
296
  :icon => "http://www.hatena.ne.jp/users/sn/snaka72/profile.gif",
@@ -0,0 +1,74 @@
1
+ require '../lib/ruby_gntp'
2
+ require 'ruby_gntp_spec_helper'
3
+
4
+ # use Double Ruby for mock/stub framework.
5
+ Spec::Runner.configure do |conf|
6
+ conf.mock_with :rr
7
+ end
8
+
9
+ # describe GNTP behavior
10
+ describe GNTP do
11
+ include GNTPExampleHelperMethods
12
+
13
+ DEFAULT_APP_NAME = "Ruby/GNTP"
14
+ NOTIFICATION_NAME = "TestApp"
15
+
16
+ before do
17
+ @sended_messages = []
18
+ @ok_response = StringIO.new(["GNTP/1.0 -OK NONE\r\n", "\r\n"].join)
19
+ @opened_socket = create_stub_socket(@ok_response, @sended_messages)
20
+ end
21
+
22
+ it "can register notifications with minimum params" do
23
+ @gntp = GNTP.new
24
+ @gntp.register :notifications => [{:name => NOTIFICATION_NAME}]
25
+
26
+ [
27
+ "GNTP/1.0 REGISTER NONE\r\n",
28
+ "Application-Name: #{DEFAULT_APP_NAME}\r\n",
29
+ "Notifications-Count: 1\r\n",
30
+ "\r\n",
31
+ "Notification-Name: #{NOTIFICATION_NAME}\r\n",
32
+ "Notification-Display-Name: #{NOTIFICATION_NAME}\r\n",
33
+ "Notification-Enabled: True\r\n"
34
+ ].each {|expected_text|
35
+ @sended_messages.last.should include(expected_text)
36
+ }
37
+ end
38
+
39
+ it "can register notifications to remote host" do
40
+ @gntp = GNTP.new "TestApp", "1.2.3.4", "password", 12345
41
+ @gntp.register :notifications => [{:name => NOTIFICATION_NAME}]
42
+
43
+ @opened_socket[:host].should == "1.2.3.4"
44
+ @opened_socket[:port].should == 12345
45
+
46
+ @sended_messages.last.first.should match(/GNTP\/1\.0 REGISTER NONE MD5:\S+\r\n/)
47
+ [
48
+ "Application-Name: TestApp\r\n",
49
+ "Notifications-Count: 1\r\n",
50
+ "\r\n",
51
+ "Notification-Name: #{NOTIFICATION_NAME}\r\n",
52
+ "Notification-Display-Name: #{NOTIFICATION_NAME}\r\n",
53
+ "Notification-Enabled: True\r\n"
54
+ ].each {|expected_text|
55
+ @sended_messages.last.should include(expected_text)
56
+ }
57
+ end
58
+
59
+ it "can notify with minimum params" do
60
+ @gntp = GNTP.new
61
+ @gntp.register :notifications => [{:name => NOTIFICATION_NAME}]
62
+ @gntp.notify :name => NOTIFICATION_NAME
63
+
64
+ [
65
+ "GNTP/1.0 NOTIFY NONE\r\n",
66
+ "Application-Name: #{DEFAULT_APP_NAME}\r\n",
67
+ "Notification-Name: #{NOTIFICATION_NAME}\r\n",
68
+ "Notification-Title: \r\n"
69
+ ].each {|expected_text|
70
+ @sended_messages.last.should include(expected_text)
71
+ }
72
+ end
73
+
74
+ end
@@ -0,0 +1,34 @@
1
+ module GNTPExampleHelperMethods
2
+
3
+ def create_stub_socket(ok_response, sended_messages)
4
+
5
+ sock = {}
6
+
7
+ stub(sock).write do |string|
8
+ lines = []
9
+ buf = StringIO.new(string)
10
+
11
+ while line = buf.gets
12
+ lines << line
13
+ end
14
+
15
+ sended_messages << lines
16
+ ok_response.rewind
17
+ end
18
+
19
+ stub(sock).gets do
20
+ ok_response.gets
21
+ end
22
+
23
+ stub(sock).close
24
+
25
+ stub(TCPSocket).open do |host, port|
26
+ sock[:host] = host
27
+ sock[:port] = port
28
+ sock
29
+ end
30
+
31
+ sock
32
+ end
33
+
34
+ end
metadata CHANGED
@@ -1,20 +1,23 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_gntp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - snaka
8
+ - David Hayward (spidah)
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
12
 
12
- date: 2009-04-20 00:00:00 +09:00
13
+ date: 2009-11-04 00:00:00 +09:00
13
14
  default_executable:
14
15
  dependencies: []
15
16
 
16
17
  description:
17
- email: snaka.gml@gmail.com
18
+ email:
19
+ - snaka.gml@gmail.com
20
+ - spidahman@gmail.com
18
21
  executables: []
19
22
 
20
23
  extensions: []
@@ -25,10 +28,12 @@ files:
25
28
  - lib/ruby_gntp.rb
26
29
  - example/twitter_notifier.rb
27
30
  - example/gntp-notify
31
+ - test/ruby_gntp_spec.rb
32
+ - test/ruby_gntp_spec_helper.rb
28
33
  - README
29
34
  - TODO
30
35
  - ChangeLog
31
- has_rdoc: false
36
+ has_rdoc: true
32
37
  homepage: http://snaka.github.com/ruby_gntp/
33
38
  licenses: []
34
39
 
@@ -52,7 +57,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
52
57
  requirements: []
53
58
 
54
59
  rubyforge_project:
55
- rubygems_version: 1.3.2
60
+ rubygems_version: 1.3.4
56
61
  signing_key:
57
62
  specification_version: 3
58
63
  summary: Ruby library for GNTP(Growl Notification Transport Protocol) client