warchat 0.0.1

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