ruggby 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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