warchat 0.0.1

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/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ *.DS_Store
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in warchat.gemspec
4
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,8 @@
1
+ module Warchat
2
+ class ByteString < String
3
+
4
+ def to_s
5
+ self
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,20 @@
1
+ module Warchat module Chat
2
+ module ChatResponse
3
+ def presence?
4
+ chat_type == 'wow_presence'
5
+ end
6
+
7
+ def ack?
8
+ chat_type == 'message_ack'
9
+ end
10
+
11
+ def message?
12
+ chat_type == 'wow_message'
13
+ end
14
+
15
+ def chat_type
16
+ self['chatType']
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,98 @@
1
+ module Warchat
2
+ module Chat
3
+ class Warchat::Chat::Client
4
+ attr_accessor :on_message,:on_presence,:on_logout,:on_fail,:on_establish
5
+ attr_accessor :on_message_afk,:on_message_dnd,:on_message_guild_chat,:on_message_motd,:on_message_officer_chat,:on_message_whisper,:on_chat_logout
6
+ attr_accessor :character_name,:character_realm
7
+
8
+ attr_reader :session
9
+
10
+ def initialize
11
+ @session = Warchat::Network::Session.new
12
+
13
+ [:receive,:establish,:error].each do |m|
14
+ session.send("on_#{m}=".to_sym, method("session_#{m}".to_sym))
15
+ end
16
+ end
17
+
18
+ def start username, password
19
+ self.session.start(username,password)
20
+ end
21
+
22
+ def session_error response
23
+ on_fail.andand.call(response["body"]) if response.target == "/chat-login"
24
+ end
25
+
26
+ def session_establish response
27
+ puts 'Session Established'
28
+ on_establish.andand.call(response)
29
+ end
30
+
31
+ def session_receive response
32
+ send(response.target.gsub('/','').underscore.to_sym,response)
33
+ end
34
+
35
+ def login
36
+ request = Warchat::Network::Request.new("/chat-login",:options=>{:mature_filter=>'false'},:n=>character_name,:r=>character_realm)
37
+ session.send_request(request)
38
+ @timer = Warchat::Timer.new(120,&method(:keep_alive))
39
+ end
40
+
41
+ def logout
42
+ request = Warchat::Network::Request.new('/chat-logout',:chatSessionId=>@chat_session_id)
43
+ end
44
+
45
+ def chat_logout response
46
+ puts 'Logged out of chat'
47
+ @timer.andand.stop
48
+ on_chat_logout.andand.call response
49
+ session.close
50
+ end
51
+
52
+ def chat_login response
53
+ puts "Logged into chat"
54
+ @chat_session_id = response["chatSessionId"]
55
+ end
56
+
57
+ def chat response
58
+ response.extend(ChatResponse)
59
+ if response.ack?
60
+ puts("chat ack")
61
+ elsif response.message?
62
+ message = Message.new(response)
63
+ on_message.andand.call(message)
64
+ send("on_message_#{message.type}".to_sym).andand.call(message)
65
+ elsif response.presence?
66
+ puts
67
+ on_presence.andand.call(Presence.new(response))
68
+ else
69
+ puts "unhandled chat type: #{response.chat_type}"
70
+ end
71
+ end
72
+
73
+ def close
74
+ request = Warchat::Network::Request.new("/chat-logout",:chatSessionId=>@chat_session_id)
75
+ session.send_request(request)
76
+ end
77
+
78
+ def keep_alive
79
+ puts "Sending 'keep-alive'"
80
+
81
+ request = Warchat::Network::Request("/ah-mail")
82
+ request["r"] = realm
83
+ request["cn"] = name
84
+ session.send_request(request)
85
+ end
86
+
87
+ def message(msg, chat_type = Message.CHAT_MSG_TYPE_GUILD_CHAT)
88
+ request = Warchat::Network::Request.new("/chat-guild",:type=>chat_type,:body=>msg,:chatSessionId=>@chat_session_id)
89
+ session.send_request(request)
90
+ end
91
+
92
+ def whisper(msg, char_id)
93
+ request = Warchat::Network::Request.new("/chat-whisper",:to=>char_id,:body=>msg,:chatSessionId=>@chat_session_id)
94
+ session.send_request(request)
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,35 @@
1
+ module Warchat
2
+ module Chat
3
+ class Message
4
+ CHAT_ID_TYPE_CHARACTER = "character"
5
+ CHAT_ID_TYPE_GUILD = "guild"
6
+ CHAT_ID_TYPE_GUILD_MEMBER = "guild_member"
7
+
8
+ CHAT_MSG_TYPE_AFK = "afk"
9
+ CHAT_MSG_TYPE_DND = "dnd"
10
+ CHAT_MSG_TYPE_GUILD_CHAT = "guild_chat"
11
+ CHAT_MSG_TYPE_GUILD_MOTD = "motd"
12
+ CHAT_MSG_TYPE_OFFICER_CHAT = "officer_chat"
13
+ CHAT_MSG_TYPE_WHISPER = "whisper"
14
+
15
+ attr_reader :type,:body,:from_type,:character_id,:from
16
+
17
+ def initialize response
18
+ @type = response["messageType"]
19
+ @body = response['body']
20
+ @from = response["from"]
21
+ @from_type = from["chatIdType"]
22
+
23
+ @character_id = from["characterId"]
24
+ end
25
+
26
+ def character_name
27
+ @character_id.andand.split(':')[-2]
28
+ end
29
+
30
+ def realm_id
31
+ @character_id.andand.split(':').last
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,22 @@
1
+ module Warchat
2
+ module Chat
3
+ class Presence
4
+ attr_reader :name,:character
5
+
6
+ def initialize response
7
+ @type = response["presenceType"];
8
+ @character = response["character"];
9
+ @name = character["n"];
10
+ end
11
+
12
+ def offline?
13
+ @type.andand.include? 'offline'
14
+ end
15
+
16
+ def type
17
+ return 'unknown' unless @type
18
+ @type.split('_')[1..-1].join '_'
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,46 @@
1
+ module Warchat
2
+ module Network
3
+ class BinaryReader
4
+ def initialize socket
5
+ @socket = socket
6
+ end
7
+
8
+ TYPES = [:hash,:array,:int_32,:string,:string,:boolean,:int_64]
9
+ def parse_next *args
10
+ send TYPES[byte.unpack('C').first-1]
11
+ end
12
+
13
+ def substream l
14
+ @socket.read l
15
+ end
16
+
17
+ def byte
18
+ substream 1
19
+ end
20
+
21
+ def string
22
+ substream(int_32)
23
+ end
24
+
25
+ def array
26
+ (1..(int_32)).map &method(:parse_next)
27
+ end
28
+
29
+ def hash
30
+ Hash[*(1..(int_32)).map do
31
+ [string,parse_next]
32
+ end.flatten(1)]
33
+ end
34
+
35
+ {16=>'n',32=>'N',64=>'L_'}.each do |size,directive|
36
+ define_method "int_#{size}".to_sym do
37
+ substream(size/8).unpack(directive).first
38
+ end
39
+ end
40
+
41
+ def boolean
42
+ byte == "\001"
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,86 @@
1
+ module Warchat
2
+ module Network
3
+ class BinaryWriter
4
+
5
+ attr_reader :stream
6
+
7
+ def initialize stream
8
+ @stream = stream
9
+ end
10
+
11
+ def write obj
12
+ m = (obj.class.ancestors.map do |c|
13
+ "write_#{File.basename c.name.underscore}".to_sym
14
+ end.find(&method(:respond_to?)) or :write_string)
15
+ send(m,obj)
16
+ end
17
+
18
+ def write_string obj
19
+ byte 5
20
+ string obj.to_s
21
+ end
22
+
23
+ def write_integer obj
24
+ if obj < 2**32
25
+ byte 3
26
+ int_32 obj
27
+ else
28
+ byte 7
29
+ int_64 obj
30
+ end
31
+ end
32
+
33
+ def write_hash obj
34
+ byte 1
35
+ int_32 obj.size
36
+ obj.each do |k,v|
37
+ string(k.to_s)
38
+ write(v)
39
+ end
40
+ end
41
+
42
+ def write_array obj
43
+ byte 2
44
+ int_32 obj.size
45
+ obj.each do |v|
46
+ write(v)
47
+ end
48
+ end
49
+
50
+ def write_byte_string obj
51
+ byte 4
52
+ int_32 obj.length
53
+ bytes obj
54
+ end
55
+
56
+ def write_bool obj
57
+ byte 6
58
+ byte(obj ? 1 : 0)
59
+ end
60
+ alias_method :write_true_class,:write_bool
61
+ alias_method :write_false_class,:write_bool
62
+
63
+
64
+ {16=>'n',32=>'N',64=>'L_'}.each do |size,directive|
65
+ define_method "int_#{size}".to_sym do |obj|
66
+ @stream.print [obj].pack(directive)
67
+ end
68
+ end
69
+
70
+ def string obj
71
+ obj = obj.to_s
72
+ int_32 obj.length
73
+ @stream.print obj
74
+ end
75
+
76
+ def byte obj
77
+ obj = (obj.is_a? Integer and [obj].pack('C') or obj.to_s[0..0])
78
+ @stream.print obj
79
+ end
80
+
81
+ def bytes obj
82
+ @stream.print obj.to_s
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,85 @@
1
+ require 'socket'
2
+ require 'thread'
3
+
4
+ module Warchat
5
+ module Network
6
+ class Connection
7
+
8
+ attr_accessor :host,:port,:on_send,:on_receive,:on_close
9
+
10
+ def initialize *args
11
+ options = args.pop if args.last.is_a? Hash
12
+
13
+ self.host = (args.shift or "m.us.wowarmory.com")
14
+ self.port = (args.shift or 8780)
15
+ @closed = true
16
+ @queue = []
17
+ @mutex = Mutex.new
18
+ end
19
+
20
+ def start
21
+ close
22
+
23
+ @closed = false;
24
+ @socket = TCPSocket.open(host,port)
25
+ @socket.sync = false
26
+ @request_thread = Thread.new &method(:handle_requests)
27
+ @response_thread = Thread.new &method(:handle_responses)
28
+ @request_thread['name'] = 'Request Thead'
29
+ @response_thread['name'] = 'Response Thread'
30
+ end
31
+
32
+ def close reason = ""
33
+ return if is_closed?
34
+
35
+ on_close.andand.call(reason)
36
+
37
+ @mutex.synchronize do
38
+ @closed = true
39
+ @socket.close
40
+ end
41
+ end
42
+
43
+ def is_closed?
44
+ @closed or @socket.nil?
45
+ end
46
+
47
+ def send_request request
48
+ @mutex.synchronize do
49
+ @queue << request
50
+ end
51
+ end
52
+
53
+ def handle_responses
54
+ until is_closed?
55
+ response = Response.new(@socket)
56
+ on_receive.andand.call(response) unless is_closed?
57
+ sleep 0.01
58
+ end
59
+ rescue Exception => e
60
+ puts e.message
61
+ puts e.backtrace unless e.is_a? IOError
62
+ end
63
+
64
+ def handle_requests
65
+ until is_closed?
66
+ @mutex.synchronize do
67
+ until @queue.empty?
68
+
69
+ request = @queue.shift
70
+ unless is_closed?
71
+ request.stream @socket
72
+ @socket.flush
73
+ on_send.andand.call(request)
74
+ end
75
+ end
76
+ end
77
+ sleep 0.01
78
+ end
79
+ rescue Exception => e
80
+ puts e.message
81
+ puts e.backtrace
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,60 @@
1
+ module Warchat
2
+ module Network
3
+ class Request < Hash
4
+ class StringSocket
5
+ def initialize
6
+ @stream = ""
7
+ end
8
+
9
+ def print obj
10
+ @stream << obj.to_s
11
+ end
12
+
13
+ def length
14
+ @stream.length
15
+ end
16
+
17
+ def value
18
+ @stream
19
+ end
20
+ end
21
+ attr_reader :id,:target
22
+
23
+ def initialize target,*args
24
+ @target = target
25
+ @@request_count ||= -1
26
+ @@request_count += 1
27
+ @id = @@request_count
28
+ merge! args.shift if args.first.is_a? Hash
29
+ super *args
30
+ end
31
+
32
+ def stream socket
33
+ writer = BinaryWriter.new socket
34
+ writer.string(target)
35
+ writer.int_32(@id)
36
+ each do |k,v|
37
+ if [Hash,Array,Warchat::ByteString].none? &v.method(:is_a?)
38
+ writer.byte 5
39
+ writer.string k
40
+ writer.string v.to_s
41
+ else
42
+ writer.byte 4
43
+ writer.string k
44
+ tmp_socket = StringSocket.new
45
+ tmp = BinaryWriter.new(tmp_socket)
46
+ tmp.write v
47
+ writer.int_32(tmp_socket.length)
48
+ writer.bytes(tmp_socket.value)
49
+ end
50
+ writer.byte 0xFF
51
+ end
52
+ writer.byte 0xFF
53
+ end
54
+
55
+ def inspect
56
+ "<#{self.class.name} id:#{id.inspect} target:#{target.inspect} #{super}>"
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,25 @@
1
+ module Warchat
2
+ module Network
3
+ class Response < Hash
4
+ attr_accessor :length,:status,:target,:id
5
+ def initialize socket,*args
6
+ super *args
7
+ reader = BinaryReader.new socket
8
+ self.length = reader.int_32
9
+ self.status = reader.int_16
10
+ self.target = reader.string
11
+ self.id = reader.int_32
12
+
13
+ merge! reader.parse_next
14
+ end
15
+
16
+ def ok?
17
+ status == 200
18
+ end
19
+
20
+ def inspect
21
+ "<#{self.class.name} id:#{id.inspect} target:#{target.inspect} status:#{status.inspect} #{super}>"
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,85 @@
1
+ module Warchat
2
+ module Network
3
+ class Session
4
+
5
+ attr_accessor :on_close,:on_receive,:on_establish,:on_error
6
+
7
+
8
+ def initialize
9
+ @connection = Warchat::Network::Connection.new
10
+
11
+ @connection.on_close = method(:connection_close)
12
+ @connection.on_receive = method(:connection_receive)
13
+ end
14
+
15
+ def start account_name, password
16
+ @account_name = account_name
17
+ @password = password
18
+
19
+ @connection.start
20
+
21
+ @srp = Warchat::Srp::Client.new
22
+
23
+ send_request Request.new('/authenticate1',
24
+ :screenRes => "PHONE_HIGH",
25
+ :device => "iPhone",
26
+ :deviceSystemVersion => "4.2.1",
27
+ :deviceModel => "iPhone3,1",
28
+ :appV => "3.0.0",
29
+ :deviceTime => Time.now.to_i,
30
+ :deviceTimeZoneId => "America/New_York",
31
+ :clientA => @srp.a_bytes,
32
+ :appId => "Armory",
33
+ :deviceId => '50862581c5dc46072050d51886cbae3149b3473c',
34
+ :emailAddress => account_name,
35
+ :deviceTimeZone => "-14400000",
36
+ :locale => "en_US"
37
+ )
38
+ end
39
+
40
+ def established?
41
+ @established
42
+ end
43
+
44
+ def close reason=''
45
+ @connection.andand.close reason
46
+ end
47
+
48
+ def send_request request
49
+ @connection.andand.send_request(request)
50
+ end
51
+
52
+ def stage_1 response
53
+ proof = @srp.auth1_proof(response["user"], @password[0..15].upcase, response["salt"], response["B"])
54
+ puts("sending client proof: 0x#{@srp.unpack_int(proof).to_s(16)} length: #{proof.length}")
55
+ send_request(Request.new("/authenticate2",:clientProof=>proof))
56
+ end
57
+
58
+ def stage_2 response
59
+ puts("sending client proof2")
60
+ send_request(Request.new("/authenticate2",:clientProof=>Warchat::ByteString.new("\000")))
61
+ end
62
+
63
+ def stage_3 response
64
+ @established = true
65
+ on_establish.andand.call(response)
66
+ end
67
+
68
+ def connection_receive response
69
+ puts response.inspect
70
+ m = "stage_#{response['stage']}".to_sym
71
+ if response.ok?
72
+ respond_to? m and send(m,response) or on_receive.andand.call(response)
73
+ else
74
+ error = response["body"]
75
+ puts("error: " + error)
76
+ close(error) if respond_to? m
77
+ end
78
+ end
79
+
80
+ def connection_close reason
81
+ on_close.andand.call(reason)
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,138 @@
1
+ require 'digest'
2
+ require 'openssl'
3
+
4
+ module Warchat
5
+ module Srp
6
+ class Client
7
+ G = 2
8
+
9
+ MODULUS_SIZE = 128
10
+ MODULUS = 0x86a7f6deeb306ce519770fe37d556f29944132554ded0bd68205e27f3231fef5a10108238a3150c59caf7b0b6478691c13a6acf5e1b5adafd4a943d4a21a142b800e8a55f8bfbac700eb77a7235ee5a609e350ea9fc19f10d921c2fa832e4461b7125d38d254a0be873dfc27858acb3f8b9f258461e4373bc3a6c2a9634324ab
11
+
12
+ SALT_SIZE = 32
13
+ HASH_SIZE = 32
14
+ SESSION_KEY_SIZE = HASH_SIZE * 2
15
+
16
+ attr_reader :b,:b_bytes
17
+
18
+ def modpow(a, n, m)
19
+ r = 1
20
+ while true
21
+ r = r * a % m if n[0] == 1
22
+ n >>= 1
23
+ return r if n == 0
24
+ a = a * a % m
25
+ end
26
+ end
27
+
28
+ def pack_int int
29
+ Warchat::ByteString.new [int.to_s(16).reverse].pack('h*')
30
+ end
31
+
32
+ def unpack_int str
33
+ str.unpack('h*').first.reverse.hex
34
+ end
35
+
36
+ def digest_int s
37
+ unpack_int(Digest::SHA2.digest(s))
38
+ end
39
+
40
+ def adjust_size str,length
41
+ str[0..(length-1)].ljust(length,"\000")
42
+ end
43
+
44
+ def random_crypt
45
+ unpack_int(OpenSSL::Random.random_bytes(MODULUS_SIZE*2)) % MODULUS
46
+ end
47
+
48
+ def hN_xor_hG
49
+ # xor H(N) and H(G)
50
+ return @hN_xor_hG if @hN_xor_hG
51
+ hN = Digest::SHA2.digest(pack_int(MODULUS))
52
+ hG = Digest::SHA2.digest(pack_int(G))
53
+
54
+ @hN_xor_hG = "\000" * HASH_SIZE
55
+
56
+ HASH_SIZE.times do |i| @hN_xor_hG[i] = (hN[i] ^ hG[i]) end
57
+
58
+ @hN_xor_hG
59
+ end
60
+
61
+ def a
62
+ @a ||= random_crypt
63
+ end
64
+
65
+ def a_bytes
66
+ @a_bytes ||= adjust_size(pack_int(modpow(G,a,MODULUS)),MODULUS_SIZE)
67
+ end
68
+
69
+ def k
70
+ @k ||= digest_int(pack_int(MODULUS)+pack_int(G))
71
+ end
72
+
73
+ def u
74
+ # H(A | B)
75
+ @u ||= digest_int(a_bytes+b_bytes)
76
+ end
77
+
78
+ def x
79
+ # H(salt | H(userHash | : | sessionPassword))
80
+ @x ||= digest_int(@salt+Digest::SHA2.digest(@user+":"+@password))
81
+ end
82
+
83
+ def s
84
+ # (B - k * G^x) ^ (a + u * x)
85
+ return modpow(b - k * modpow(G, x, MODULUS), a + u * x, MODULUS)
86
+ end
87
+
88
+ def s_bytes
89
+ @s_bytes ||= adjust_size(pack_int(s),(MODULUS_SIZE))
90
+ end
91
+
92
+
93
+ def auth1_proof user, password, salt, b_bytes
94
+ @b = unpack_int b_bytes
95
+ @b_bytes = adjust_size(b_bytes,MODULUS_SIZE)
96
+ @salt = adjust_size(salt,SALT_SIZE)
97
+ @user = user
98
+ @password = password
99
+
100
+ # hash this to generate client proof, H(H(N) xor H(G) | H(userHash) | salt | A | B | K)
101
+ Warchat::ByteString.new Digest::SHA2.digest(hN_xor_hG+Digest::SHA2.digest(@user)+salt+a_bytes+@b_bytes+session_key)
102
+ end
103
+
104
+ def session_key
105
+ return @session_key if @session_key
106
+ @session_key = "\000" * SESSION_KEY_SIZE
107
+
108
+ l = s_bytes.length
109
+ offset = (l.odd? and 1 or 0)
110
+ l -= offset
111
+
112
+ l = [l/2,MODULUS_SIZE].min
113
+
114
+ temp = ''
115
+ l.times do |i|
116
+ temp << s_bytes[i*2+offset]
117
+ end
118
+
119
+ hash = Digest::SHA2.digest(temp)
120
+ HASH_SIZE.times do |i|
121
+ @session_key[i*2] = hash[i]
122
+ end
123
+
124
+ temp = ''
125
+ l.times do |i|
126
+ temp << s_bytes[i*2+offset+1]
127
+ end
128
+
129
+ hash = Digest::SHA2.digest(temp)
130
+ HASH_SIZE.times do |i|
131
+ @session_key[i*2+1] = hash[i]
132
+ end
133
+
134
+ @session_key
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,45 @@
1
+ require 'monitor'
2
+
3
+ module Warchat class Timer
4
+ def initialize(interval, &handler)
5
+
6
+ raise ArgumentError, "Illegal interval" if interval < 0
7
+ @interval = interval
8
+ extend MonitorMixin
9
+ @run = true
10
+ @th = Thread.new do
11
+ while run?
12
+ do_sleep and handler.call rescue nil
13
+ end
14
+ end
15
+ @th['name'] = 'Timer'
16
+ end
17
+
18
+ def stop
19
+ synchronize do
20
+ @run = false
21
+ end
22
+ sleeping? and @th.kill or @th.join
23
+ end
24
+
25
+ private
26
+
27
+ def sleeping?
28
+ synchronize do @sleeping end
29
+ end
30
+
31
+ def do_sleep
32
+ synchronize do @sleeping = true end
33
+ sleep(@interval)
34
+ synchronize do @sleeping = false end
35
+ rescue
36
+ nil
37
+ end
38
+
39
+ def run?
40
+ synchronize do
41
+ @run
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,3 @@
1
+ module Warchat
2
+ VERSION = "0.0.1"
3
+ end
data/lib/warchat.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'active_support/inflector'
2
+ require 'andand'
3
+
4
+ module Warchat
5
+ end
6
+
7
+ [['*.rb'],['network','*.rb'],['srp','*.rb'],['chat','*.rb']].each do |p| Dir.glob(File.join(File.expand_path('../wow_chat',__FILE__)),*p)).each &method(:require) end
data/warchat.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "warchat/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "warchat"
7
+ s.version = Warchat::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Zachary Gavin"]
10
+ s.email = ["zgavin@gmail.com"]
11
+ s.homepage = "http://www.github.com/zgavin/warchat"
12
+ s.summary = %q{A simple interface to World of Warcraft Remote Guild Chat based off Eike Siewertsen's C# implementation}
13
+ s.description = %q{A simple interface to World of Warcraft Remote Guild Chat in Ruby. Supports whispers, guild chat, officer chat, and presence notifications. Many thanks to Eike Siewertsen (https://github.com/fry) for his work deciphering the protocol. }
14
+
15
+ s.rubyforge_project = "warchat"
16
+
17
+ s.add_dependency('activesupport','>= 3.0.0')
18
+ s.add_dependency('andand')
19
+
20
+ s.files = `git ls-files`.split("\n")
21
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
22
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
23
+ s.require_paths = ["lib"]
24
+ end
metadata ADDED
@@ -0,0 +1,115 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: warchat
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Zachary Gavin
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-05-16 00:00:00 -04:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: activesupport
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 7
30
+ segments:
31
+ - 3
32
+ - 0
33
+ - 0
34
+ version: 3.0.0
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: andand
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 3
46
+ segments:
47
+ - 0
48
+ version: "0"
49
+ type: :runtime
50
+ version_requirements: *id002
51
+ description: "A simple interface to World of Warcraft Remote Guild Chat in Ruby. Supports whispers, guild chat, officer chat, and presence notifications. Many thanks to Eike Siewertsen (https://github.com/fry) for his work deciphering the protocol. "
52
+ email:
53
+ - zgavin@gmail.com
54
+ executables: []
55
+
56
+ extensions: []
57
+
58
+ extra_rdoc_files: []
59
+
60
+ files:
61
+ - .gitignore
62
+ - Gemfile
63
+ - Rakefile
64
+ - lib/warchat.rb
65
+ - lib/warchat/byte_string.rb
66
+ - lib/warchat/chat/chat_response.rb
67
+ - lib/warchat/chat/client.rb
68
+ - lib/warchat/chat/message.rb
69
+ - lib/warchat/chat/presence.rb
70
+ - lib/warchat/network/binary_reader.rb
71
+ - lib/warchat/network/binary_writer.rb
72
+ - lib/warchat/network/connection.rb
73
+ - lib/warchat/network/request.rb
74
+ - lib/warchat/network/response.rb
75
+ - lib/warchat/network/session.rb
76
+ - lib/warchat/srp/client.rb
77
+ - lib/warchat/timer.rb
78
+ - lib/warchat/version.rb
79
+ - warchat.gemspec
80
+ has_rdoc: true
81
+ homepage: http://www.github.com/zgavin/warchat
82
+ licenses: []
83
+
84
+ post_install_message:
85
+ rdoc_options: []
86
+
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ hash: 3
95
+ segments:
96
+ - 0
97
+ version: "0"
98
+ required_rubygems_version: !ruby/object:Gem::Requirement
99
+ none: false
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ hash: 3
104
+ segments:
105
+ - 0
106
+ version: "0"
107
+ requirements: []
108
+
109
+ rubyforge_project: warchat
110
+ rubygems_version: 1.5.0
111
+ signing_key:
112
+ specification_version: 3
113
+ summary: A simple interface to World of Warcraft Remote Guild Chat based off Eike Siewertsen's C# implementation
114
+ test_files: []
115
+