ruggby 0.3.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.
Files changed (40) hide show
  1. data/CHANGELOG.rdoc +2 -0
  2. data/Gemfile +2 -0
  3. data/MIT-LICENSE +20 -0
  4. data/Manifest +38 -0
  5. data/README.md +187 -0
  6. data/Rakefile +12 -0
  7. data/init.rb +1 -0
  8. data/lib/ruggby.rb +72 -0
  9. data/lib/ruggby/action/base.rb +16 -0
  10. data/lib/ruggby/action/change_status.rb +30 -0
  11. data/lib/ruggby/action/create_message.rb +27 -0
  12. data/lib/ruggby/action/login.rb +40 -0
  13. data/lib/ruggby/action/mark.rb +27 -0
  14. data/lib/ruggby/action/new_message.rb +28 -0
  15. data/lib/ruggby/action/ping.rb +40 -0
  16. data/lib/ruggby/action/read.rb +49 -0
  17. data/lib/ruggby/callback.rb +22 -0
  18. data/lib/ruggby/client.rb +95 -0
  19. data/lib/ruggby/converter.rb +57 -0
  20. data/lib/ruggby/logger.rb +67 -0
  21. data/lib/ruggby/packet/factory.rb +39 -0
  22. data/lib/ruggby/packet/incoming/base.rb +31 -0
  23. data/lib/ruggby/packet/incoming/login_status.rb +28 -0
  24. data/lib/ruggby/packet/incoming/message.rb +35 -0
  25. data/lib/ruggby/packet/incoming/welcome.rb +33 -0
  26. data/lib/ruggby/packet/outgoing/base.rb +67 -0
  27. data/lib/ruggby/packet/outgoing/change_status.rb +57 -0
  28. data/lib/ruggby/packet/outgoing/login.rb +75 -0
  29. data/lib/ruggby/packet/outgoing/mark.rb +28 -0
  30. data/lib/ruggby/packet/outgoing/message.rb +47 -0
  31. data/lib/ruggby/packet/outgoing/ping.rb +27 -0
  32. data/lib/ruggby/password.rb +19 -0
  33. data/lib/ruggby/socket.rb +67 -0
  34. data/lib/ruggby/string_encoder.rb +42 -0
  35. data/lib/ruggby/threader.rb +21 -0
  36. data/lib/ruggby/version.rb +5 -0
  37. data/ruggby.gemspec +35 -0
  38. data/spec/callback_spec.rb +40 -0
  39. data/spec/spec_helper.rb +7 -0
  40. metadata +142 -0
data/CHANGELOG.rdoc ADDED
@@ -0,0 +1,2 @@
1
+ = Version 0.1.0
2
+ * Basic functionality: login, change status, send messages, receive messages
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "http://rubygems.org"
2
+ gemspec
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Maciej Mensfeld
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Manifest ADDED
@@ -0,0 +1,38 @@
1
+ CHANGELOG.rdoc
2
+ Gemfile
3
+ MIT-LICENSE
4
+ README.md
5
+ Rakefile
6
+ init.rb
7
+ lib/ruggby.rb
8
+ lib/ruggby/action/base.rb
9
+ lib/ruggby/action/change_status.rb
10
+ lib/ruggby/action/create_message.rb
11
+ lib/ruggby/action/login.rb
12
+ lib/ruggby/action/mark.rb
13
+ lib/ruggby/action/new_message.rb
14
+ lib/ruggby/action/ping.rb
15
+ lib/ruggby/action/read.rb
16
+ lib/ruggby/callback.rb
17
+ lib/ruggby/client.rb
18
+ lib/ruggby/converter.rb
19
+ lib/ruggby/logger.rb
20
+ lib/ruggby/packet/factory.rb
21
+ lib/ruggby/packet/incoming/base.rb
22
+ lib/ruggby/packet/incoming/login_status.rb
23
+ lib/ruggby/packet/incoming/message.rb
24
+ lib/ruggby/packet/incoming/welcome.rb
25
+ lib/ruggby/packet/outgoing/base.rb
26
+ lib/ruggby/packet/outgoing/change_status.rb
27
+ lib/ruggby/packet/outgoing/login.rb
28
+ lib/ruggby/packet/outgoing/mark.rb
29
+ lib/ruggby/packet/outgoing/message.rb
30
+ lib/ruggby/packet/outgoing/ping.rb
31
+ lib/ruggby/password.rb
32
+ lib/ruggby/socket.rb
33
+ lib/ruggby/string_encoder.rb
34
+ lib/ruggby/threader.rb
35
+ lib/ruggby/version.rb
36
+ spec/callback_spec.rb
37
+ spec/spec_helper.rb
38
+ Manifest
data/README.md ADDED
@@ -0,0 +1,187 @@
1
+ # ruGGby - Gadu Gadu protocol client implementation in pure Ruby language
2
+
3
+ ## Install
4
+
5
+ ```ruby
6
+ gem install ruggby
7
+ ```
8
+
9
+ and in your Gemfile:
10
+
11
+ ```ruby
12
+ gem 'ruggby'
13
+ ```
14
+
15
+ ## About
16
+
17
+ ruGGby is a Gadu-Gadu (Polish messenger similar to ICQ) protocol client, which allows you to:
18
+
19
+ * Login to your Gadu-Gadu account
20
+ * Set and change status and description
21
+ * Receive messages
22
+ * Send messages
23
+ * Perform callbacks on almost every event connected to GG handling
24
+ * Works with big GG numbers
25
+ * Works with polish letters and other UTF-8 characters
26
+
27
+ ## Usage
28
+
29
+ Let's start with a simple example:
30
+
31
+ ### Simple example
32
+ ```ruby
33
+ gg = RuGGby::Client.new
34
+
35
+ gg.login!(LOGIN, PASSWORD)
36
+ gg.message(RECEIVER_GG, 'this is a message')
37
+ gg.logout!
38
+ ```
39
+
40
+ So, what have we done? We've created an Gadu-Gadu instance client, logged in, sent a message and logged out. Easy enough ;)
41
+
42
+ ### Login in and login out
43
+
44
+ Log in/out process is fairly simple:
45
+
46
+ ```ruby
47
+ gg = RuGGby::Client.new
48
+
49
+ gg.login!(LOGIN, PASSWORD)
50
+ gg.logout!
51
+ ```
52
+
53
+ We can also pass two additional parameters to *login!* method:
54
+
55
+ * :status - initial GG status
56
+ * :description - initial GG description
57
+
58
+ So the "full" login would look like:
59
+
60
+ ```ruby
61
+ gg = RuGGby::Client.new
62
+
63
+ gg.login!(LOGIN, PASSWORD, :status => :busy, :description => '2Busy')
64
+ ```
65
+
66
+ ### Updating status and description
67
+
68
+ Sometimes we want to update our status. In order to do so, invoke a *change_status* method with two parameters:
69
+
70
+ * status - status symbol
71
+ * description (optional) - optional description for status
72
+
73
+ The allowed statuses are:
74
+
75
+ * :available
76
+ * :busy
77
+ * :invisible
78
+
79
+ ```ruby
80
+ gg.change_status(:busy, 'I\'m so busy right now!')
81
+ ```
82
+
83
+ ### Keeping ruGGby bot alive
84
+
85
+ To keep the bot working, just invoke the *wait* method and it will exit:
86
+
87
+ ```ruby
88
+ gg = RuGGby::Client.new
89
+
90
+ gg.on_new_message do |uid, time, message|
91
+ gg.message(uid, message)
92
+ end
93
+
94
+ gg.login!(LOGIN, PASSWORD)
95
+ gg.wait
96
+ ```
97
+
98
+ ### Logger
99
+
100
+ By default RuGGby uses a *RuGGby::Logger* logger, which only prints output to console. However, you can replace it with any logger that support following methods:
101
+
102
+ * *debug*(message)
103
+ * *info*(message)
104
+ * *error*(message)
105
+ * *fatal*(message)
106
+
107
+ To do so, create an *RuGGby::Client* instance and assign your own logger:
108
+
109
+ ```ruby
110
+ require 'logger'
111
+
112
+ gg = RuGGby::Client.new
113
+ gg.logger = Logger.new('gg.log', :weekly)
114
+ ```
115
+
116
+ In order to change log level, just assing a new one like this:
117
+
118
+ ```ruby
119
+ RuGGby::Client.log_level = :error
120
+ ```
121
+
122
+ ### Events
123
+
124
+ RuGGby supports events, so you can assign your own events on demand. Events list:
125
+
126
+ * :read - event triggered on each read from RuGGby::Socket
127
+ * :ping - event triggered on each GG Server Ping
128
+ * :new_message - event triggered on new message receive
129
+ * :mark - event triggered when we send mark packet to GG Server
130
+ * :login - event triggered after login
131
+ * :create_message - event triggered after message has been send
132
+ * :change_status - event triggered after our status/description change
133
+
134
+ Each event block is triggered with parameters:
135
+
136
+ * :read(packet) - *RuGGby::Packet* instance (build using *RuGGby::Packet::Factory*)
137
+ * :ping - no parameters
138
+ * :new_message(uin, timestamp, message)
139
+ * :mark - no parameters
140
+ * :login - no parameters
141
+ * :create_message(uin, message)
142
+ * :change_status(status, description)
143
+
144
+ In order to assign an action to an event, pass a block into events hash:
145
+
146
+ ```ruby
147
+ gg = RuGGby::Client.new
148
+
149
+ gg.actions[:new_message] = proc do |uin, created_at, msg|
150
+ # uin is a sender GG number (Integer)
151
+ # created_at - Time.at when message has been sent
152
+ # msg - String containing message
153
+ print "#{uin}-#{created_at}: #{msg}\n"
154
+ end
155
+ ```
156
+
157
+ However most of the events don't need an action so you can use *on_new_message* method to assign a block:
158
+
159
+ ```ruby
160
+ gg = RuGGby::Client.new
161
+
162
+ gg.on_new_message do |uid, time, message|
163
+ gg.message(uid, message)
164
+ end
165
+ ```
166
+
167
+ The *:new_message* event is triggered in a separate thread so the socket read process is still going. The above code will (after login!) return a message to it's sender.
168
+
169
+ ## TODO
170
+
171
+ * Tests (currently there is no :()
172
+ * More sophisticated GG actions (friends, etc)
173
+
174
+ ## Note on Patches/Pull Requests
175
+
176
+ * Fork the project.
177
+ * Make your feature addition or bug fix.
178
+ * Add tests for it. This is important so I don't break it in a future version unintentionally.
179
+ * Commit, do not mess with Rakefile, version, or history.
180
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
181
+ * Send me a pull request. Bonus points for topic branches.
182
+
183
+ ## Copyright
184
+
185
+ Copyright (c) 2012 Maciej Mensfeld. See LICENSE for details.
186
+
187
+ Based on http://toxygen.net/libgadu/protocol
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'echoe'
4
+
5
+ Echoe.new('ruggby', '0.3.0') do |p|
6
+ p.description = 'Gadu Gadu protocol client implementation in Ruby language'
7
+ p.url = 'https://github.com/mensfeld/ruGGby'
8
+ p.author = 'Maciej Mensfeld'
9
+ p.email = 'maciej@mensfeld.pl'
10
+ p.ignore_pattern = ['tmp/*', 'script/*']
11
+ p.development_dependencies = ['rspec >=2.0.0', 'mocha']
12
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'ruggby'
data/lib/ruggby.rb ADDED
@@ -0,0 +1,72 @@
1
+ # RuGGby is a simple (not completed) implementation of a GG written in Ruby
2
+ # It allows us to login to our account and receive/send messages
3
+
4
+ # Currently due to lack of time this are the only actions that are available
5
+
6
+ # Usage example:
7
+
8
+ # gg = RuGGby::Client.new
9
+ #
10
+ # gg.on_new_message do |uid, message|
11
+ # gg.message(uid, message)
12
+ # end
13
+ #
14
+ # gg.login!(gg_nr, Pass)
15
+ # gg.wait
16
+ # gg.logout!
17
+
18
+ $:.unshift File.dirname(__FILE__)
19
+
20
+ module RuGGby
21
+
22
+ autoload :Version, 'ruggby/version.rb'
23
+
24
+ module Packet
25
+ # Factory used to build incoming packets out of raw socket messages
26
+ autoload :Factory, 'ruggby/packet/factory.rb'
27
+
28
+ # Incoming packets used to wrap the raw socket messages send by GG server
29
+ module Incoming
30
+ path = 'ruggby/packet/incoming'
31
+ autoload :Base, "#{path}/base.rb"
32
+ autoload :LoginStatus, "#{path}/login_status.rb"
33
+ autoload :Message, "#{path}/message.rb"
34
+ autoload :Welcome, "#{path}/welcome.rb"
35
+ end
36
+
37
+ # Outgoing packets send to GG server
38
+ module Outgoing
39
+ path = 'ruggby/packet/outgoing'
40
+ autoload :Base, "#{path}/base.rb"
41
+ autoload :Login, "#{path}/login.rb"
42
+ autoload :Mark, "#{path}/mark.rb"
43
+ autoload :Message, "#{path}/message.rb"
44
+ autoload :Ping, "#{path}/ping.rb"
45
+ autoload :ChangeStatus, "#{path}/change_status.rb"
46
+ end
47
+ end
48
+
49
+ # Available actions (we can hookup to all of them)
50
+ module Action
51
+ path = 'ruggby/action'
52
+ autoload :Base, "#{path}/base.rb"
53
+ autoload :CreateMessage, "#{path}/create_message.rb"
54
+ autoload :Login, "#{path}/login.rb"
55
+ autoload :Mark, "#{path}/mark.rb"
56
+ autoload :NewMessage, "#{path}/new_message.rb"
57
+ autoload :Ping, "#{path}/ping.rb"
58
+ autoload :Read, "#{path}/read.rb"
59
+ autoload :ChangeStatus, "#{path}/change_status.rb"
60
+ end
61
+
62
+ # Other stuff that is needed
63
+ autoload :Socket, 'ruggby/socket'
64
+ autoload :Logger, 'ruggby/logger'
65
+ autoload :Callback, 'ruggby/callback'
66
+ autoload :Converter, 'ruggby/converter'
67
+ autoload :Password, 'ruggby/password'
68
+ autoload :Threader, 'ruggby/threader'
69
+ autoload :StringEncoder, 'ruggby/string_encoder'
70
+ autoload :Client, 'ruggby/client'
71
+
72
+ end
@@ -0,0 +1,16 @@
1
+ module RuGGby
2
+
3
+ module Action
4
+
5
+ # Base class for all the event actions
6
+ class Base
7
+
8
+ def initialize(client)
9
+ @block = client.actions[:base]
10
+ end
11
+
12
+ end
13
+
14
+ end
15
+
16
+ end
@@ -0,0 +1,30 @@
1
+ module RuGGby
2
+
3
+ module Action
4
+
5
+ # Action invoken when we want to change status
6
+ class ChangeStatus < Base
7
+
8
+ attr_reader :status, :description
9
+
10
+ def initialize(client, status, description)
11
+ @client = client
12
+ @block = client.actions[:change_status]
13
+ @status = status
14
+ @description = description
15
+ end
16
+
17
+ def run!
18
+ @client.logger.debug('RuGGby::Action::ChangeStatus')
19
+
20
+ msg = Packet::Outgoing::ChangeStatus.new(@status, @description)
21
+ @client.socket.write(msg)
22
+
23
+ @block.call(@status, @description) if @block
24
+ end
25
+
26
+ end
27
+
28
+ end
29
+
30
+ end
@@ -0,0 +1,27 @@
1
+ module RuGGby
2
+
3
+ module Action
4
+
5
+ # Sending message action
6
+ class CreateMessage < Base
7
+
8
+ def initialize(client, uin, message)
9
+ @client = client
10
+ @block = client.actions[:create_message]
11
+ @uin = uin
12
+ @message = message
13
+ end
14
+
15
+ def run!
16
+ @client.logger.debug('RuGGby::Action::CreateMessage')
17
+
18
+ msg = Packet::Outgoing::Message.new(@uin, @message)
19
+ @client.socket.write(msg)
20
+ @block.call(@uin, @message) if @block
21
+ end
22
+
23
+ end
24
+
25
+ end
26
+
27
+ end
@@ -0,0 +1,40 @@
1
+ module RuGGby
2
+
3
+ module Action
4
+
5
+ # Login action - will log user in to a GG account
6
+ class Login < Base
7
+
8
+ def initialize(client)
9
+ @client = client
10
+ @block = client.actions[:login]
11
+ end
12
+
13
+ def run!
14
+ @client.logger.debug('RuGGby::Action::Login')
15
+
16
+ welcome = RuGGby::Packet::Factory.new(@client.socket).build
17
+
18
+ login = Packet::Outgoing::Login.new(
19
+ :uin => @client.login,
20
+ :hash => Password.hash(@client.password, welcome.seed),
21
+ :status => @client.status,
22
+ :description => @client.description
23
+ )
24
+
25
+ @client.logger.debug('RuGGby::Action::Login sending Login packet')
26
+ @client.socket.write(login)
27
+
28
+ login_status = RuGGby::Packet::Factory.new(@client.socket).build
29
+
30
+ @client.logger.debug("RuGGby::Action::Login #{login_status.class}")
31
+
32
+ @client.logged = login_status.successful?
33
+ @block.call if @block
34
+ end
35
+
36
+ end
37
+
38
+ end
39
+
40
+ end