I was encouraged to post random bits of code, so I figured I'd whip up a small app and post it here.
Code:
#!/usr/bin/env ruby
# Protocol docs: http://cho.cyan.com/chat/protocol1.html
#
# ToDo:
# - implement ignore
# - convert encodings (assumptions: CC uses Windows-1252; Ruby uses UTF-8)
# - make interactive
# - wrap UI around
#
require 'socket'
Version = "1.0d5"
DefaultHost = 'cho.cyan.com'
DefaultPort = 1812
DebugPort = 1813
C2SNickname = 10
C2SQuit = 15
C2SPrivMsg = 20
C2SRoomMsg = 30
C2SWelcome = 40
C2SIgnore = 70
S2CNickErr = 10
S2CNickSet = 11
S2CPrivMsg = 21
S2CMessage = 31
S2CWhoList = 35
S2CWelcome = 40
S2CIgnore = 70
GroupUser = 0
GroupCyan = 1
GroupServer = 2
GroupGuest = 4
Timestamps = 1
RotateLines = 1
Nickname = "cccccccTest"
class CCConnection < TCPSocket
attr_accessor(:alreadyWelcomed, :connectAutomatically)
attr_reader(:host, :port)
def initialize(host=DefaultHost, port=DefaultPort)
super(host, port)
@alreadyWelcomed = 0
@connectAutomatically = 1
end
def c2sCmd(cmd)
self.send(cmd, 0)
end
def c2sNickname(nick)
self.c2sCmd(C2SNickname.to_s + "|" + nick + "\n")
end
def c2sQuit()
self.c2sCmd(C2SQuit.to_s + "\n")
end
def c2sPrivMsg(userclass, nickname, message)
self.c2sCmd(C2SPrivMsg.to_s + "|" + userclass.to_s + nickname + "|^1" + message + "\n")
# e.g. 21|0chucker|^1foo\n
end
def c2sRoomMsg(message)
self.c2sCmd(C2SRoomMsg.to_s + "|^1" + message + "\n")
end
def c2sWelcome()
self.c2sCmd(C2SWelcome.to_s + "|1\n")
end
def c2sIgnore()
self.c2sCmd(C2SIgnore.to_s) # not implemented
end
end
def printx(output)
if Timestamps == 1
output = Time.now.strftime('%X ') + output + "\n"
end
print output
end
def errorx(output)
if Timestamps == 1
output = Time.now.strftime('%X ERROR: ') + output + "\n"
end
print output
end
def s2cPrivMsg(line)
if line.slice!(0) && (line[0].chr == GroupServer.to_s) && line.slice!(0) && line.include?("|^1")
messageArray = line.split("|^1")
messageSender = messageArray[0]
messageContent = messageArray[1]
printx "["+messageSender+"] "+messageContent
end
end
def s2cWhoList(line)
line.slice!(0)
puts line
whoHash = Hash[*line.split("|").map! {|x| x.split(",")}.flatten]
# this isn't actually useful;
# we need to store the Group as well, which is completely retarded but such is life.
# Two-dimensional array, I suppose.
puts whoHash.class
puts whoHash.to_s
puts whoHash["chucker"]
# when RespWhoList.to_s
# if bufferLines[0][0] == "|"
# while bufferLines[0].length > 0
# bufferLines[0].slice!(0)
# while bufferLines[0][0] != ","
# tmp += bufferLines[0][0]
# end
# puts tmp
# whoList[]
# end
# end
end
def s2cWelcome(line)
printx(line)
end
def handleResponse(connection, line)
case bufferCmd = line.slice!(0,2)
when S2CPrivMsg.to_s
s2cPrivMsg(line)
when S2CWhoList.to_s
if line.length > 1
if line[0].chr == "|"
line.slice!(0)
s2cWhoList(line)
else
errorx("Erroneous who list response! " + line)
exit
end
else
printx("Room is empty")
end
when S2CWelcome.to_s
if line[0..1] == "|1"
line.slice!(0,2)
s2cWelcome(line)
if connection.alreadyWelcomed == 0
connection.alreadyWelcomed = 1
if connection.connectAutomatically == 1
connection.c2sNickname(Nickname)
sleep 3
connection.c2sPrivMsg(GroupUser, "chucker", "PM test")
connection.c2sRoomMsg("Hi!")
connection.c2sQuit()
exit
end
end
else
errorx("Erroneous welcome response!")
exit
end
else
puts "cmd "+bufferCmd+"\n"
end
end
connection = CCConnection.new()
connection.c2sWelcome()
i=1
while # this line / condition needs fixing, i.e. "while connection open"
buffer = connection.recv(1024)
# puts connection.alreadyWelcomed
bufferLines = buffer.split(/\r\n/)
puts bufferLines.length.to_s+" lines"
puts bufferLines[0]
if bufferLines.length > 1
while bufferLines.length > 1
if RotateLines == 1
bufferLines.reverse!
end
handleResponse(connection, bufferLines[0])
bufferLines.slice!(0)
end
else
handleResponse(connection, bufferLines.to_s)
end
i+=1
end
There's various big problems with this code, notably:
- it's severely disorganized
- it's completely non-interactive
- outgoing commands are inside the CCConnection object (as desired); incoming ones are not.
As such, the anticipated improvements are:
- a more useful structure (I've been told by one person I sent this too that it is "actually pretty nicely written" and rather "clean", so I could be expecting too much)
- a means to make it interactive and eventually wrap a GUI around it
- a more logical grouping of commands.
Now, I don't know much about 1). As for 2): I know next to nothing about this. Sure, I can use primitive functions like "gets", but that's not exactly my idea. I experimented with ncurses about a year ago, in C, but didn't really like my results of that either.
Ideally, I'd like this application to run on Windows, using a toolkit such as WxWidgets or FOX, but, again, I don't even know where to begin. Tutorials only make me blink; the extensions of WxRuby or FXRuby seem extremely non-Ruby-like to me.
Finally, 3): is it possible at all to put received commands in the class? After all, class methods are there to send a message to the class, not to receive one from it, so it's somewhat illogical. Am I missing something?
Any pointers whatsoever appreciated.