#
# rica.rb
# -- Ruby Internet relay Chat Agents (based on RFC1459)
# NISHI Takao <zophos@koka-in.org>
#
# $Id: rica.rb,v 1.12 2001/11/11 07:48:57 zophos Exp $
#
require 'socket'
require 'thread'
require 'kconv'
require 'observer'
require 'singleton'
require 'delegate'
$KCODE="euc"
module Rica
RICA_NAME="Rica"
RICA_VERION="0.10"
RICA_FULLNAME="Ruby Internet relay Chat Agents"
RICA_INFO_URL="http://www.koka-in.org/%7Ezophos/SideA/lsnt/rica.html"
RICA_PRIVMSG_MAX_LEN=255
############################################################
#
# Irc events and event processing modules template
#
# In this library, Irc messages are assumed as event.
#
module Event
#
# RFC1459 Commands (include optional)
#
CMND_UNKNOWN=0
CMND_PASS=1
CMND_NICK=2
CMND_USER=3
CMND_SERVER=4
CMND_OPER=5
CMND_QUIT=6
CMND_SQUIT=7
CMND_JOIN=8
CMND_PART=9
CMND_MODE=10
CMND_TOPIC=11
CMND_NAMES=12
CMND_LIST=13
CMND_INVITE=14
CMND_KICK=15
CMND_VERSION=16
CMND_STATAS=17
CMND_LINK=18
CMND_TIME=19
CMND_CONNECT=20
CMND_TRACE=21
CMND_ADMIN=22
CMND_INFO=23
CMND_PRIVMSG=24
CMND_NOTICE=25
CMND_WHO=26
CMND_WHOIS=27
CMND_WHOWAS=28
CMND_KILL=29
CMND_PING=30
CMND_PONG=31
CMND_ERROR=32
CMND_AWAY=33
CMND_REHASH=34
CMND_RESTART=35
CMND_SUMMON=36
CMND_USERS=37
CMND_WALLOPS=38
CMND_USERHOST=39
CMND_ISON=40
#
# CTCP Messages
#
CMND_CTCP_QUERY=100
CMND_CTCP_ANSWER=200
CMND_CTCP_UNKNOWN=0
CMND_CTCP_PING=1
CMND_CTCP_ECHO=2
CMND_CTCP_TIME=3
CMND_CTCP_VERSION=4
CMND_CTCP_CLIENTINFO=5
CMND_CTCP_USERINFO=6
CMND_CTCP_ACTION=7
CMND_CTCP_DCC=8
#
# Socket event
#
LINK_ESTABLISHING=-1
LINK_ESTABLISHED=-2
LINK_FAILED=-3
LINK_CLOSING=-4
LINK_CLOSED=-5
#
# Low level Irc event
#
RECV_MESSAGE=10000
RECV_MESSAGE_BROKEN=10000
RECV_MESSAGE_KILL=10001
RECV_MESSAGE_PING=10002
RECV_MESSAGE_PONG=10003
RECV_MESSAGE_ERROR=10004
RECV_MESSAGE_NOTICE=10005
#
# RFC1459 messages
#
RECV_RPL_INIT=1 # Not listed in RFC1459, but many servers say
RECV_RPL_TRACELINK=200
RECV_RPL_TRACECONNECTING=201
RECV_RPL_TRACEHANDSHAKE=202
RECV_RPL_TRACEUNKNOWN=203
RECV_RPL_TRACEOPERATOR=204
RECV_RPL_TRACEUSER=205
RECV_RPL_TRACESERVER=206
RECV_RPL_TRACENEWTYPE=208
RECV_RPL_STATSLINKINF=211
RECV_RPL_STATSCOMMANDS=212
RECV_RPL_STATSCLINE=213
RECV_RPL_STATSNLINE=214
RECV_RPL_STATSILINE=215
RECV_RPL_STATSKLINE=216
RECV_RPL_STATSYLINE=218
RECV_RPL_ENDOFSTATS=219
RECV_RPL_UMODEIS=221
RECV_RPL_STATSLLINE=241
RECV_RPL_STATSUPTIME=242
RECV_RPL_STATSOLINE=243
RECV_RPL_STATSHLINE=244
RECV_RPL_LUSERCLIENT=251
RECV_RPL_LUSEROP=252
RECV_RPL_LUSERUNKNOWN=253
RECV_RPL_LUSERCHANNELS=254
RECV_RPL_LUSERME=255
RECV_RPL_ADMINME=256
RECV_RPL_ADMINLOC1=257
RECV_RPL_ADMINLOC2=258
RECV_RPL_ADMINEMAIL=259
RECV_RPL_TRACELOG=261
RECV_RPL_NONE=300
RECV_RPL_AWAY=301
RECV_RPL_USERHOST=302
RECV_RPL_ISON=303
RECV_RPL_UNAWAY=305
RECV_RPL_NOWAWAY=306
RECV_RPL_WHOISUSER=311
RECV_RPL_WHOISSERVER=312
RECV_RPL_WHOISOPERATOR=313
RECV_RPL_WHOWASUSER=314
RECV_RPL_ENDOFWHO=315
RECV_RPL_WHOISIDLE=317
RECV_RPL_ENDOFWHOIS=318
RECV_RPL_WHOISCHANNELS=319
RECV_RPL_LISTSTART=321
RECV_RPL_LIST=322
RECV_RPL_LISTEND=323
RECV_RPL_CHANNELMODEIS=324
RECV_RPL_NOTOPIC=331
RECV_RPL_TOPIC=332
RECV_RPL_INVITING=341
RECV_RPL_SUMMONING=342
RECV_RPL_VERSION=351
RECV_RPL_WHOREPLY=352
RECV_RPL_NAMREPLY=353
RECV_RPL_LINKS=364
RECV_RPL_ENDOFLINKS=365
RECV_RPL_ENDOFNAME=366
RECV_RPL_BANLIST=367
RECV_RPL_ENDOFBANLIST=368
RECV_RPL_ENDOFWHOWAS=369
RECV_RPL_INFO=371
RECV_RPL_MOTD=372
RECV_RPL_ENDOFINFO=374
RECV_RPL_MOTDSTART=375
RECV_RPL_ENDOFMOTD=376
RECV_RPL_YOUREOPER=381
RECV_RPL_REHASHING=382
RECV_RPL_TIME=391
RECV_RPL_USERS=393
RECV_RPL_ENDOFUSERS=394
RECV_RPL_NOUSERS=395
RECV_ERR_NOSUCHNICK=401
RECV_ERR_NOSUCHSERVE=402
RECV_ERR_NOSUCHCHANNEL=403
RECV_ERR_CANNOTSENDTOCHAN=404
RECV_ERR_TOOMANYCHANNELS=405
RECV_ERR_WASNOSUCHNICK=406
RECV_ERR_TOOMANYTARGETS=407
RECV_ERR_NOORIGIN=409
RECV_ERR_NORECIPIENT=411
RECV_ERR_NOTEXTTOSEND=412
RECV_ERR_NOTOPLEVE=413
RECV_ERR_WILDTOPLEVEL=414
RECV_ERR_UNKNOWNCOMMAND=421
RECV_ERR_NOMOTD=422
RECV_ERR_NOADMININFO=423
RECV_ERR_FILEERROR=424
RECV_ERR_NONICKNAMEGIVEN=431
RECV_ERR_ERRONEUSNICKNAME=432
RECV_ERR_NICKNAMEINUSE=433
RECV_ERR_NICKCOLLISION=436
RECV_ERR_USERNOTINCHANNEL=441
RECV_ERR_NOTONCHANNE=442
RECV_ERR_USERONCHANNEL=443
RECV_ERR_NOLOGIN=444
RECV_ERR_SUMMONDISABLED=445
RECV_ERR_USERSDISABLED=446
RECV_ERR_NOTREGISTERED=451
RECV_ERR_NEEDMOREPARAM=461
RECV_ERR_ALREADYREGISTRE=462
RECV_ERR_NOPERMFORHOST=463
RECV_ERR_PASSWDMISMATCH=464
RECV_ERR_YOUREBANNEDCREEP=465
RECV_ERR_KEYSET=467
RECV_ERR_CHANNELISFULL=471
RECV_ERR_UNKNOWNMODE=472
RECV_ERR_INVITEONLYCHAN=473
RECV_ERR_BANNEDFROMCHAN=474
RECV_ERR_BADCHANNELKEY=475
RECV_ERR_NOPRIVILEGES=481
RECV_ERR_CHANOPRIVSNEEDED=482
RECV_ERR_CANTKILLSERVER=483
RECV_ERR_NOOPERHOST=491
RECV_ERR_UMODEUNKNOWNFLAG=501
RECV_ERR_USERSDONTMATCH=502
RECV_CMND=1000
RECV_CMND_UNKNOWN=RECV_CMND+CMND_UNKNOWN
RECV_CMND_PASS=RECV_CMND+CMND_PASS
RECV_CMND_NICK=RECV_CMND+CMND_NICK
RECV_CMND_USER=RECV_CMND+CMND_USER
RECV_CMND_SERVER=RECV_CMND+CMND_SERVER
RECV_CMND_OPER=RECV_CMND+CMND_OPER
RECV_CMND_QUIT=RECV_CMND+CMND_QUIT
RECV_CMND_SQUIT=RECV_CMND+CMND_SQUIT
RECV_CMND_JOIN=RECV_CMND+CMND_JOIN
RECV_CMND_PART=RECV_CMND+CMND_PART
RECV_CMND_MODE=RECV_CMND+CMND_MODE
RECV_CMND_TOPIC=RECV_CMND+CMND_TOPIC
RECV_CMND_NAMES=RECV_CMND+CMND_NAMES
RECV_CMND_LIST=RECV_CMND+CMND_LIST
RECV_CMND_INVITE=RECV_CMND+CMND_INVITE
RECV_CMND_KICK=RECV_CMND+CMND_KICK
RECV_CMND_VERSION=RECV_CMND+CMND_VERSION
RECV_CMND_STATAS=RECV_CMND+CMND_STATAS
RECV_CMND_LINK=RECV_CMND+CMND_LINK
RECV_CMND_TIME=RECV_CMND+CMND_TIME
RECV_CMND_CONNECT=RECV_CMND+CMND_CONNECT
RECV_CMND_TRACE=RECV_CMND+CMND_TRACE
RECV_CMND_ADMIN=RECV_CMND+CMND_ADMIN
RECV_CMND_INFO=RECV_CMND+CMND_INFO
RECV_CMND_PRIVMSG=RECV_CMND+CMND_PRIVMSG
RECV_CMND_NOTICE=RECV_CMND+CMND_NOTICE
RECV_CMND_WHO=RECV_CMND+CMND_WHO
RECV_CMND_WHOIS=RECV_CMND+CMND_WHOIS
RECV_CMND_WHOWAS=RECV_CMND+CMND_WHOWAS
RECV_CMND_KILL=RECV_CMND+CMND_KILL
RECV_CMND_PING=RECV_CMND+CMND_PING
RECV_CMND_PONG=RECV_CMND+CMND_PONG
RECV_CMND_ERROR=RECV_CMND+CMND_ERROR
RECV_CMND_AWAY=RECV_CMND+CMND_AWAY
RECV_CMND_REHASH=RECV_CMND+CMND_REHASH
RECV_CMND_RESTART=RECV_CMND+CMND_RESTART
RECV_CMND_SUMMON=RECV_CMND+CMND_SUMMON
RECV_CMND_USERS=RECV_CMND+CMND_USERS
RECV_CMND_WALLOPS=RECV_CMND+CMND_WALLOPS
RECV_CMND_USERHOST=RECV_CMND+CMND_USERHOST
RECV_CMND_ISON=RECV_CMND+CMND_ISON
RECV_CMND_CTCP_QUERY=RECV_CMND+CMND_CTCP_QUERY
RECV_CMND_CTCP_QUERY_UNKNOWN=RECV_CMND_CTCP_QUERY+
CMND_CTCP_UNKNOWN
RECV_CMND_CTCP_QUERY_PING=RECV_CMND_CTCP_QUERY+CMND_CTCP_PING
RECV_CMND_CTCP_QUERY_ECHO=RECV_CMND_CTCP_QUERY+CMND_CTCP_ECHO
RECV_CMND_CTCP_QUERY_TIME=RECV_CMND_CTCP_QUERY+CMND_CTCP_TIME
RECV_CMND_CTCP_QUERY_VERSION=RECV_CMND_CTCP_QUERY+
CMND_CTCP_VERSION
RECV_CMND_CTCP_QUERY_CLIENTINFO=RECV_CMND_CTCP_QUERY+
CMND_CTCP_CLIENTINFO
RECV_CMND_CTCP_QUERY_USERINFO=RECV_CMND_CTCP_QUERY+
CMND_CTCP_USERINFO
RECV_CMND_CTCP_QUERY_ACTION=RECV_CMND_CTCP_QUERY+
CMND_CTCP_ACTION
RECV_CMND_CTCP_QUERY_DCC=RECV_CMND_CTCP_QUERY+
CMND_CTCP_DCC
RECV_CMND_CTCP_ANSWER=RECV_CMND+CMND_CTCP_ANSWER
RECV_CMND_CTCP_ANSWER_UNKNOWN=RECV_CMND_CTCP_ANSWER+
CMND_CTCP_UNKNOWN
RECV_CMND_CTCP_ANSWER_PING=RECV_CMND_CTCP_ANSWER+CMND_CTCP_PING
RECV_CMND_CTCP_ANSWER_ECHO=RECV_CMND_CTCP_ANSWER+CMND_CTCP_ECHO
RECV_CMND_CTCP_ANSWER_TIME=RECV_CMND_CTCP_ANSWER+CMND_CTCP_TIME
RECV_CMND_CTCP_ANSWER_VERSION=RECV_CMND_CTCP_ANSWER+
CMND_CTCP_VERSION
RECV_CMND_CTCP_ANSWER_CLIENTINFO=RECV_CMND_CTCP_ANSWER+
CMND_CTCP_CLIENTINFO
RECV_CMND_CTCP_ANSWER_USERINFO=RECV_CMND_CTCP_ANSWER+
CMND_CTCP_USERINFO
RECV_CMND_CTCP_ANSWER_ACTION=RECV_CMND_CTCP_ANSWER+
CMND_CTCP_ACTION
RECV_CMND_CTCP_ANSWER_DCC=RECV_CMND_CTCP_ANSWER+
CMND_CTCP_DCC
USER_EVENT=10000
########################################################
#
# Message dispatching method
#
# Args:
# Rica::Message msg
#
# Return:
# as you like (default is nil)
#
def dispatch(msg)
case msg.command
when LINK_ESTABLISHING
ret=on_link_establishing(msg)
when LINK_ESTABLISHED
ret=on_link_established(msg)
when LINK_FAILED
ret=on_link_failed(msg)
when LINK_CLOSING
ret=on_link_closing(msg)
when LINK_CLOSED
ret=on_link_closed(msg)
when RECV_MESSAGE
ret=on_recv_message(msg)
when RECV_MESSAGE_BROKEN
ret=on_recv_message_broken(msg)
when RECV_MESSAGE_KILL
ret=on_recv_message_kill(msg)
when RECV_MESSAGE_PING
ret=on_recv_message_ping(msg)
when RECV_MESSAGE_PONG
ret=on_recv_message_pong(msg)
when RECV_MESSAGE_ERROR
ret=on_recv_message_error(msg)
when RECV_MESSAGE_NOTICE
ret=on_recv_message_notice(msg)
when RECV_RPL_INIT
ret=on_recv_rpl_init(msg)
when RECV_RPL_TRACELINK
ret=on_recv_rpl_tracelink(msg)
when RECV_RPL_TRACECONNECTING
ret=on_recv_rpl_traceconnecting(msg)
when RECV_RPL_TRACEHANDSHAKE
ret=on_recv_rpl_tracehandshake(msg)
when RECV_RPL_TRACEUNKNOWN
ret=on_recv_rpl_traceunknown(msg)
when RECV_RPL_TRACEOPERATOR
ret=on_recv_rpl_traceoperator(msg)
when RECV_RPL_TRACEUSER
ret=on_recv_rpl_traceuser(msg)
when RECV_RPL_TRACESERVER
ret=on_recv_rpl_traceserver(msg)
when RECV_RPL_TRACENEWTYPE
ret=on_recv_rpl_tracenewtype(msg)
when RECV_RPL_STATSLINKINF
ret=on_recv_rpl_statslinkinf(msg)
when RECV_RPL_STATSCOMMANDS
ret=on_recv_rpl_statscommands(msg)
when RECV_RPL_STATSCLINE
ret=on_recv_rpl_statscline(msg)
when RECV_RPL_STATSNLINE
ret=on_recv_rpl_statsnline(msg)
when RECV_RPL_STATSILINE
ret=on_recv_rpl_statsiline(msg)
when RECV_RPL_STATSKLINE
ret=on_recv_rpl_statskline(msg)
when RECV_RPL_STATSYLINE
ret=on_recv_rpl_statsyline(msg)
when RECV_RPL_ENDOFSTATS
ret=on_recv_rpl_endofstats(msg)
when RECV_RPL_UMODEIS
ret=on_recv_rpl_umodeis(msg)
when RECV_RPL_STATSLLINE
ret=on_recv_rpl_statslline(msg)
when RECV_RPL_STATSUPTIME
ret=on_recv_rpl_statsuptime(msg)
when RECV_RPL_STATSOLINE
ret=on_recv_rpl_statsoline(msg)
when RECV_RPL_STATSHLINE
ret=on_recv_rpl_statshline(msg)
when RECV_RPL_LUSERCLIENT
ret=on_recv_rpl_luserclient(msg)
when RECV_RPL_LUSEROP
ret=on_recv_rpl_luserop(msg)
when RECV_RPL_LUSERUNKNOWN
ret=on_recv_rpl_luserunknown(msg)
when RECV_RPL_LUSERCHANNELS
ret=on_recv_rpl_luserchannels(msg)
when RECV_RPL_LUSERME
ret=on_recv_rpl_luserme(msg)
when RECV_RPL_ADMINME
ret=on_recv_rpl_adminme(msg)
when RECV_RPL_ADMINLOC1
ret=on_recv_rpl_adminloc1(msg)
when RECV_RPL_ADMINLOC2
ret=on_recv_rpl_adminloc2(msg)
when RECV_RPL_ADMINEMAIL
ret=on_recv_rpl_adminemail(msg)
when RECV_RPL_TRACELOG
ret=on_recv_rpl_tracelog(msg)
when RECV_RPL_NONE
ret=on_recv_rpl_none(msg)
when RECV_RPL_AWAY
ret=on_recv_rpl_away(msg)
when RECV_RPL_USERHOST
ret=on_recv_rpl_userhost(msg)
when RECV_RPL_ISON
ret=on_recv_rpl_ison(msg)
when RECV_RPL_UNAWAY
ret=on_recv_rpl_unaway(msg)
when RECV_RPL_NOWAWAY
ret=on_recv_rpl_nowaway(msg)
when RECV_RPL_WHOISUSER
ret=on_recv_rpl_whoisuser(msg)
when RECV_RPL_WHOISSERVER
ret=on_recv_rpl_whoisserver(msg)
when RECV_RPL_WHOISOPERATOR
ret=on_recv_rpl_whoisoperator(msg)
when RECV_RPL_WHOWASUSER
ret=on_recv_rpl_whowasuser(msg)
when RECV_RPL_ENDOFWHO
ret=on_recv_rpl_endofwho(msg)
when RECV_RPL_WHOISIDLE
ret=on_recv_rpl_whoisidle(msg)
when RECV_RPL_ENDOFWHOIS
ret=on_recv_rpl_endofwhois(msg)
when RECV_RPL_WHOISCHANNELS
ret=on_recv_rpl_whoischannels(msg)
when RECV_RPL_LISTSTART
ret=on_recv_rpl_liststart(msg)
when RECV_RPL_LIST
ret=on_recv_rpl_list(msg)
when RECV_RPL_LISTEND
ret=on_recv_rpl_listend(msg)
when RECV_RPL_CHANNELMODEIS
ret=on_recv_rpl_channelmodeis(msg)
when RECV_RPL_NOTOPIC
ret=on_recv_rpl_notopic(msg)
when RECV_RPL_TOPIC
ret=on_recv_rpl_topic(msg)
when RECV_RPL_INVITING
ret=on_recv_rpl_inviting(msg)
when RECV_RPL_SUMMONING
ret=on_recv_rpl_summoning(msg)
when RECV_RPL_VERSION
ret=on_recv_rpl_version(msg)
when RECV_RPL_WHOREPLY
ret=on_recv_rpl_whoreply(msg)
when RECV_RPL_NAMREPLY
ret=on_recv_rpl_namreply(msg)
when RECV_RPL_LINKS
ret=on_recv_rpl_links(msg)
when RECV_RPL_ENDOFLINKS
ret=on_recv_rpl_endoflinks(msg)
when RECV_RPL_ENDOFNAME
ret=on_recv_rpl_endofname(msg)
when RECV_RPL_BANLIST
ret=on_recv_rpl_banlist(msg)
when RECV_RPL_ENDOFBANLIST
ret=on_recv_rpl_endofbanlist(msg)
when RECV_RPL_ENDOFWHOWAS
ret=on_recv_rpl_endofwhowas(msg)
when RECV_RPL_INFO
ret=on_recv_rpl_info(msg)
when RECV_RPL_MOTD
ret=on_recv_rpl_motd(msg)
when RECV_RPL_ENDOFINFO
ret=on_recv_rpl_endofinfo(msg)
when RECV_RPL_MOTDSTART
ret=on_recv_rpl_motdstart(msg)
when RECV_RPL_ENDOFMOTD
ret=on_recv_rpl_endofmotd(msg)
when RECV_RPL_YOUREOPER
ret=on_recv_rpl_youreoper(msg)
when RECV_RPL_REHASHING
ret=on_recv_rpl_rehashing(msg)
when RECV_RPL_TIME
ret=on_recv_rpl_time(msg)
when RECV_RPL_USERS
ret=on_recv_rpl_users(msg)
when RECV_RPL_ENDOFUSERS
ret=on_recv_rpl_endofusers(msg)
when RECV_RPL_NOUSERS
ret=on_recv_rpl_nousers(msg)
when RECV_ERR_NOSUCHNICK
ret=on_recv_err_nosuchnick(msg)
when RECV_ERR_NOSUCHSERVE
ret=on_recv_err_nosuchserve(msg)
when RECV_ERR_NOSUCHCHANNEL
ret=on_recv_err_nosuchchannel(msg)
when RECV_ERR_CANNOTSENDTOCHAN
ret=on_recv_err_cannotsendtochan(msg)
when RECV_ERR_TOOMANYCHANNELS
ret=on_recv_err_toomanychannels(msg)
when RECV_ERR_WASNOSUCHNICK
ret=on_recv_err_wasnosuchnick(msg)
when RECV_ERR_TOOMANYTARGETS
ret=on_recv_err_toomanytargets(msg)
when RECV_ERR_NOORIGIN
ret=on_recv_err_noorigin(msg)
when RECV_ERR_NORECIPIENT
ret=on_recv_err_norecipient(msg)
when RECV_ERR_NOTEXTTOSEND
ret=on_recv_err_notexttosend(msg)
when RECV_ERR_NOTOPLEVE
ret=on_recv_err_notopleve(msg)
when RECV_ERR_WILDTOPLEVEL
ret=on_recv_err_wildtoplevel(msg)
when RECV_ERR_UNKNOWNCOMMAND
ret=on_recv_err_unknowncommand(msg)
when RECV_ERR_NOMOTD
ret=on_recv_err_nomotd(msg)
when RECV_ERR_NOADMININFO
ret=on_recv_err_noadmininfo(msg)
when RECV_ERR_FILEERROR
ret=on_recv_err_fileerror(msg)
when RECV_ERR_NONICKNAMEGIVEN
ret=on_recv_err_nonicknamegiven(msg)
when RECV_ERR_ERRONEUSNICKNAME
ret=on_recv_err_erroneusnickname(msg)
when RECV_ERR_NICKNAMEINUSE
ret=on_recv_err_nicknameinuse(msg)
when RECV_ERR_NICKCOLLISION
ret=on_recv_err_nickcollision(msg)
when RECV_ERR_USERNOTINCHANNEL
ret=on_recv_err_usernotinchannel(msg)
when RECV_ERR_NOTONCHANNE
ret=on_recv_err_notonchanne(msg)
when RECV_ERR_USERONCHANNEL
ret=on_recv_err_useronchannel(msg)
when RECV_ERR_NOLOGIN
ret=on_recv_err_nologin(msg)
when RECV_ERR_SUMMONDISABLED
ret=on_recv_err_summondisabled(msg)
when RECV_ERR_USERSDISABLED
ret=on_recv_err_usersdisabled(msg)
when RECV_ERR_NOTREGISTERED
ret=on_recv_err_notregistered(msg)
when RECV_ERR_NEEDMOREPARAM
ret=on_recv_err_needmoreparam(msg)
when RECV_ERR_ALREADYREGISTRE
ret=on_recv_err_alreadyregistre(msg)
when RECV_ERR_NOPERMFORHOST
ret=on_recv_err_nopermforhost(msg)
when RECV_ERR_PASSWDMISMATCH
ret=on_recv_err_passwdmismatch(msg)
when RECV_ERR_YOUREBANNEDCREEP
ret=on_recv_err_yourebannedcreep(msg)
when RECV_ERR_KEYSET
ret=on_recv_err_keyset(msg)
when RECV_ERR_CHANNELISFULL
ret=on_recv_err_channelisfull(msg)
when RECV_ERR_UNKNOWNMODE
ret=on_recv_err_unknownmode(msg)
when RECV_ERR_INVITEONLYCHAN
ret=on_recv_err_inviteonlychan(msg)
when RECV_ERR_BANNEDFROMCHAN
ret=on_recv_err_bannedfromchan(msg)
when RECV_ERR_BADCHANNELKEY
ret=on_recv_err_badchannelkey(msg)
when RECV_ERR_NOPRIVILEGES
ret=on_recv_err_noprivileges(msg)
when RECV_ERR_CHANOPRIVSNEEDED
ret=on_recv_err_chanoprivsneeded(msg)
when RECV_ERR_CANTKILLSERVER
ret=on_recv_err_cantkillserver(msg)
when RECV_ERR_NOOPERHOST
ret=on_recv_err_nooperhost(msg)
when RECV_ERR_UMODEUNKNOWNFLAG
ret=on_recv_err_umodeunknownflag(msg)
when RECV_ERR_USERSDONTMATCH
ret=on_recv_err_usersdontmatch(msg)
when RECV_CMND_UNKNOWN
ret=on_recv_cmnd_unknown(msg)
when RECV_CMND_PASS
ret=on_recv_cmnd_pass(msg)
when RECV_CMND_NICK
ret=on_recv_cmnd_nick(msg)
when RECV_CMND_USER
ret=on_recv_cmnd_user(msg)
when RECV_CMND_SERVER
ret=on_recv_cmnd_server(msg)
when RECV_CMND_OPER
ret=on_recv_cmnd_oper(msg)
when RECV_CMND_QUIT
ret=on_recv_cmnd_quit(msg)
when RECV_CMND_SQUIT
ret=on_recv_cmnd_squit(msg)
when RECV_CMND_JOIN
ret=on_recv_cmnd_join(msg)
when RECV_CMND_PART
ret=on_recv_cmnd_part(msg)
when RECV_CMND_MODE
ret=on_recv_cmnd_mode(msg)
when RECV_CMND_TOPIC
ret=on_recv_cmnd_topic(msg)
when RECV_CMND_NAMES
ret=on_recv_cmnd_names(msg)
when RECV_CMND_LIST
ret=on_recv_cmnd_list(msg)
when RECV_CMND_INVITE
ret=on_recv_cmnd_invite(msg)
when RECV_CMND_KICK
ret=on_recv_cmnd_kick(msg)
when RECV_CMND_VERSION
ret=on_recv_cmnd_version(msg)
when RECV_CMND_STATAS
ret=on_recv_cmnd_statas(msg)
when RECV_CMND_LINK
ret=on_recv_cmnd_link(msg)
when RECV_CMND_TIME
ret=on_recv_cmnd_time(msg)
when RECV_CMND_CONNECT
ret=on_recv_cmnd_connect(msg)
when RECV_CMND_TRACE
ret=on_recv_cmnd_trace(msg)
when RECV_CMND_ADMIN
ret=on_recv_cmnd_admin(msg)
when RECV_CMND_INFO
ret=on_recv_cmnd_info(msg)
when RECV_CMND_PRIVMSG
ret=on_recv_cmnd_privmsg(msg)
when RECV_CMND_NOTICE
ret=on_recv_cmnd_notice(msg)
when RECV_CMND_WHO
ret=on_recv_cmnd_who(msg)
when RECV_CMND_WHOIS
ret=on_recv_cmnd_whois(msg)
when RECV_CMND_WHOWAS
ret=on_recv_cmnd_whowas(msg)
when RECV_CMND_KILL
ret=on_recv_cmnd_kill(msg)
when RECV_CMND_PING
ret=on_recv_cmnd_ping(msg)
when RECV_CMND_PONG
ret=on_recv_cmnd_pong(msg)
when RECV_CMND_ERROR
ret=on_recv_cmnd_error(msg)
when RECV_CMND_AWAY
ret=on_recv_cmnd_away(msg)
when RECV_CMND_REHASH
ret=on_recv_cmnd_rehash(msg)
when RECV_CMND_RESTART
ret=on_recv_cmnd_restart(msg)
when RECV_CMND_SUMMON
ret=on_recv_cmnd_summon(msg)
when RECV_CMND_USERS
ret=on_recv_cmnd_users(msg)
when RECV_CMND_WALLOPS
ret=on_recv_cmnd_wallops(msg)
when RECV_CMND_USERHOST
ret=on_recv_cmnd_userhost(msg)
when RECV_CMND_ISON
ret=on_recv_cmnd_ison(msg)
when RECV_CMND_CTCP_QUERY
ret=on_recv_cmnd_ctcp_query(msg)
when RECV_CMND_CTCP_QUERY_UNKNOWN
ret=on_recv_cmnd_ctcp_query_unknown(msg)
when RECV_CMND_CTCP_QUERY_PING
ret=on_recv_cmnd_ctcp_query_ping(msg)
when RECV_CMND_CTCP_QUERY_ECHO
ret=on_recv_cmnd_ctcp_query_echo(msg)
when RECV_CMND_CTCP_QUERY_TIME
ret=on_recv_cmnd_ctcp_query_time(msg)
when RECV_CMND_CTCP_QUERY_VERSION
ret=on_recv_cmnd_ctcp_query_version(msg)
when RECV_CMND_CTCP_QUERY_CLIENTINFO
ret=on_recv_cmnd_ctcp_query_clientinfo(msg)
when RECV_CMND_CTCP_QUERY_USERINFO
ret=on_recv_cmnd_ctcp_query_userinfo(msg)
when RECV_CMND_CTCP_QUERY_ACTION
ret=on_recv_cmnd_ctcp_query_action(msg)
when RECV_CMND_CTCP_QUERY_DCC
ret=on_recv_cmnd_ctcp_query_dcc(msg)
when RECV_CMND_CTCP_ANSWER
ret=on_recv_cmnd_ctcp_answer(msg)
when RECV_CMND_CTCP_ANSWER_UNKNOWN
ret=on_recv_cmnd_ctcp_answer_unknown(msg)
when RECV_CMND_CTCP_ANSWER_PING
ret=on_recv_cmnd_ctcp_answer_ping(msg)
when RECV_CMND_CTCP_ANSWER_ECHO
ret=on_recv_cmnd_ctcp_answer_echo(msg)
when RECV_CMND_CTCP_ANSWER_TIME
ret=on_recv_cmnd_ctcp_answer_time(msg)
when RECV_CMND_CTCP_ANSWER_VERSION
ret=on_recv_cmnd_ctcp_answer_version(msg)
when RECV_CMND_CTCP_ANSWER_CLIENTINFO
ret=on_recv_cmnd_ctcp_answer_clientinfo(msg)
when RECV_CMND_CTCP_ANSWER_USERINFO
ret=on_recv_cmnd_ctcp_answer_userinfo(msg)
when RECV_CMND_CTCP_ANSWER_ACTION
ret=on_recv_cmnd_ctcp_answer_action(msg)
when RECV_CMND_CTCP_ANSWER_DCC
ret=on_recv_cmnd_ctcp_answer_dcc(msg)
else
ret=default_action(msg)
end
return ret
end
########################################################
#
# on event methods
#
# Note that following methods are only template.
# Pls implement nice functions at your classes.
#
#
# default processing method
#
# Methods those you DO NOT override call this method
#
def default_action(msg)
#
# do nothing.
#
end
def on_link(msg)
default_action(msg)
end
alias on_link_establishing on_link
alias on_link_established on_link
alias on_link_failed on_link
alias on_link_closed on_link
def on_recv(msg)
default_action(msg)
end
alias on_recv_message on_recv
alias on_recv_message_broken on_recv_message
alias on_recv_message_kill on_recv_message
alias on_recv_message_ping on_recv_message
alias on_recv_message_pong on_recv_message
alias on_recv_message_error on_recv_message
alias on_recv_message_notice on_recv_message
alias on_recv_rpl on_recv
alias on_recv_rpl_init on_recv_rpl
alias on_recv_rpl_tracelink on_recv_rpl
alias on_recv_rpl_traceconnecting on_recv_rpl
alias on_recv_rpl_tracehandshake on_recv_rpl
alias on_recv_rpl_traceunknown on_recv_rpl
alias on_recv_rpl_traceoperator on_recv_rpl
alias on_recv_rpl_traceuser on_recv_rpl
alias on_recv_rpl_traceserver on_recv_rpl
alias on_recv_rpl_tracenewtype on_recv_rpl
alias on_recv_rpl_statslinkinf on_recv_rpl
alias on_recv_rpl_statscommands on_recv_rpl
alias on_recv_rpl_statscline on_recv_rpl
alias on_recv_rpl_statsnline on_recv_rpl
alias on_recv_rpl_statsiline on_recv_rpl
alias on_recv_rpl_statskline on_recv_rpl
alias on_recv_rpl_statsyline on_recv_rpl
alias on_recv_rpl_endofstats on_recv_rpl
alias on_recv_rpl_umodeis on_recv_rpl
alias on_recv_rpl_statslline on_recv_rpl
alias on_recv_rpl_statsuptime on_recv_rpl
alias on_recv_rpl_statsoline on_recv_rpl
alias on_recv_rpl_statshline on_recv_rpl
alias on_recv_rpl_luserclient on_recv_rpl
alias on_recv_rpl_luserop on_recv_rpl
alias on_recv_rpl_luserunknown on_recv_rpl
alias on_recv_rpl_luserchannels on_recv_rpl
alias on_recv_rpl_luserme on_recv_rpl
alias on_recv_rpl_adminme on_recv_rpl
alias on_recv_rpl_adminloc1 on_recv_rpl
alias on_recv_rpl_adminloc2 on_recv_rpl
alias on_recv_rpl_adminemail on_recv_rpl
alias on_recv_rpl_tracelog on_recv_rpl
alias on_recv_rpl_none on_recv_rpl
alias on_recv_rpl_away on_recv_rpl
alias on_recv_rpl_userhost on_recv_rpl
alias on_recv_rpl_ison on_recv_rpl
alias on_recv_rpl_unaway on_recv_rpl
alias on_recv_rpl_nowaway on_recv_rpl
alias on_recv_rpl_whoisuser on_recv_rpl
alias on_recv_rpl_whoisserver on_recv_rpl
alias on_recv_rpl_whoisoperator on_recv_rpl
alias on_recv_rpl_whowasuser on_recv_rpl
alias on_recv_rpl_endofwho on_recv_rpl
alias on_recv_rpl_whoisidle on_recv_rpl
alias on_recv_rpl_endofwhois on_recv_rpl
alias on_recv_rpl_whoischannels on_recv_rpl
alias on_recv_rpl_liststart on_recv_rpl
alias on_recv_rpl_list on_recv_rpl
alias on_recv_rpl_listend on_recv_rpl
alias on_recv_rpl_channelmodeis on_recv_rpl
alias on_recv_rpl_notopic on_recv_rpl
alias on_recv_rpl_topic on_recv_rpl
alias on_recv_rpl_inviting on_recv_rpl
alias on_recv_rpl_summoning on_recv_rpl
alias on_recv_rpl_version on_recv_rpl
alias on_recv_rpl_whoreply on_recv_rpl
alias on_recv_rpl_namreply on_recv_rpl
alias on_recv_rpl_links on_recv_rpl
alias on_recv_rpl_endoflinks on_recv_rpl
alias on_recv_rpl_endofname on_recv_rpl
alias on_recv_rpl_banlist on_recv_rpl
alias on_recv_rpl_endofbanlist on_recv_rpl
alias on_recv_rpl_endofwhowas on_recv_rpl
alias on_recv_rpl_info on_recv_rpl
alias on_recv_rpl_motd on_recv_rpl
alias on_recv_rpl_endofinfo on_recv_rpl
alias on_recv_rpl_motdstart on_recv_rpl
alias on_recv_rpl_endofmotd on_recv_rpl
alias on_recv_rpl_youreoper on_recv_rpl
alias on_recv_rpl_rehashing on_recv_rpl
alias on_recv_rpl_time on_recv_rpl
alias on_recv_rpl_users on_recv_rpl
alias on_recv_rpl_endofusers on_recv_rpl
alias on_recv_rpl_nousers on_recv_rpl
alias on_recv_err on_recv
alias on_recv_err_nosuchnick on_recv_err
alias on_recv_err_nosuchserve on_recv_err
alias on_recv_err_nosuchchannel on_recv_err
alias on_recv_err_cannotsendtochan on_recv_err
alias on_recv_err_toomanychannels on_recv_err
alias on_recv_err_wasnosuchnick on_recv_err
alias on_recv_err_toomanytargets on_recv_err
alias on_recv_err_noorigin on_recv_err
alias on_recv_err_norecipient on_recv_err
alias on_recv_err_notexttosend on_recv_err
alias on_recv_err_notopleve on_recv_err
alias on_recv_err_wildtoplevel on_recv_err
alias on_recv_err_unknowncommand on_recv_err
alias on_recv_err_nomotd on_recv_err
alias on_recv_err_noadmininfo on_recv_err
alias on_recv_err_fileerror on_recv_err
alias on_recv_err_nonicknamegiven on_recv_err
alias on_recv_err_erroneusnickname on_recv_err
alias on_recv_err_nicknameinuse on_recv_err
alias on_recv_err_nickcollision on_recv_err
alias on_recv_err_usernotinchannel on_recv_err
alias on_recv_err_notonchanne on_recv_err
alias on_recv_err_useronchannel on_recv_err
alias on_recv_err_nologin on_recv_err
alias on_recv_err_summondisabled on_recv_err
alias on_recv_err_usersdisabled on_recv_err
alias on_recv_err_notregistered on_recv_err
alias on_recv_err_needmoreparam on_recv_err
alias on_recv_err_alreadyregistre on_recv_err
alias on_recv_err_nopermforhost on_recv_err
alias on_recv_err_passwdmismatch on_recv_err
alias on_recv_err_yourebannedcreep on_recv_err
alias on_recv_err_keyset on_recv_err
alias on_recv_err_channelisfull on_recv_err
alias on_recv_err_unknownmode on_recv_err
alias on_recv_err_inviteonlychan on_recv_err
alias on_recv_err_bannedfromchan on_recv_err
alias on_recv_err_badchannelkey on_recv_err
alias on_recv_err_noprivileges on_recv_err
alias on_recv_err_chanoprivsneeded on_recv_err
alias on_recv_err_cantkillserver on_recv_err
alias on_recv_err_nooperhost on_recv_err
alias on_recv_err_umodeunknownflag on_recv_err
alias on_recv_err_usersdontmatch on_recv_err
alias on_recv_cmnd on_recv
alias on_recv_cmnd_unknown on_recv_cmnd
alias on_recv_cmnd_pass on_recv_cmnd
alias on_recv_cmnd_nick on_recv_cmnd
alias on_recv_cmnd_user on_recv_cmnd
alias on_recv_cmnd_server on_recv_cmnd
alias on_recv_cmnd_oper on_recv_cmnd
alias on_recv_cmnd_quit on_recv_cmnd
alias on_recv_cmnd_squit on_recv_cmnd
alias on_recv_cmnd_join on_recv_cmnd
alias on_recv_cmnd_part on_recv_cmnd
alias on_recv_cmnd_mode on_recv_cmnd
alias on_recv_cmnd_topic on_recv_cmnd
alias on_recv_cmnd_names on_recv_cmnd
alias on_recv_cmnd_list on_recv_cmnd
alias on_recv_cmnd_invite on_recv_cmnd
alias on_recv_cmnd_kick on_recv_cmnd
alias on_recv_cmnd_version on_recv_cmnd
alias on_recv_cmnd_statas on_recv_cmnd
alias on_recv_cmnd_link on_recv_cmnd
alias on_recv_cmnd_time on_recv_cmnd
alias on_recv_cmnd_connect on_recv_cmnd
alias on_recv_cmnd_trace on_recv_cmnd
alias on_recv_cmnd_admin on_recv_cmnd
alias on_recv_cmnd_info on_recv_cmnd
alias on_recv_cmnd_privmsg on_recv_cmnd
alias on_recv_cmnd_notice on_recv_cmnd
alias on_recv_cmnd_who on_recv_cmnd
alias on_recv_cmnd_whois on_recv_cmnd
alias on_recv_cmnd_whowas on_recv_cmnd
alias on_recv_cmnd_kill on_recv_cmnd
alias on_recv_cmnd_ping on_recv_cmnd
alias on_recv_cmnd_pong on_recv_cmnd
alias on_recv_cmnd_error on_recv_cmnd
alias on_recv_cmnd_away on_recv_cmnd
alias on_recv_cmnd_rehash on_recv_cmnd
alias on_recv_cmnd_restart on_recv_cmnd
alias on_recv_cmnd_summon on_recv_cmnd
alias on_recv_cmnd_users on_recv_cmnd
alias on_recv_cmnd_wallops on_recv_cmnd
alias on_recv_cmnd_userhost on_recv_cmnd
alias on_recv_cmnd_ison on_recv_cmnd
alias on_recv_cmnd_ctcp on_recv_cmnd
alias on_recv_cmnd_ctcp_query on_recv_cmnd_ctcp
alias on_recv_cmnd_ctcp_query_unknown on_recv_cmnd_ctcp_query
alias on_recv_cmnd_ctcp_query_ping on_recv_cmnd_ctcp_query
alias on_recv_cmnd_ctcp_query_echo on_recv_cmnd_ctcp_query
alias on_recv_cmnd_ctcp_query_time on_recv_cmnd_ctcp_query
alias on_recv_cmnd_ctcp_query_version on_recv_cmnd_ctcp_query
alias on_recv_cmnd_ctcp_query_clientinfo on_recv_cmnd_ctcp_query
alias on_recv_cmnd_ctcp_query_userinfo on_recv_cmnd_ctcp_query
alias on_recv_cmnd_ctcp_query_action on_recv_cmnd_ctcp_query
alias on_recv_cmnd_ctcp_query_dcc on_recv_cmnd_ctcp_query
alias on_recv_cmnd_ctcp_answer on_recv_cmnd_ctcp
alias on_recv_cmnd_ctcp_answer_unknown on_recv_cmnd_ctcp_answer
alias on_recv_cmnd_ctcp_answer_ping on_recv_cmnd_ctcp_answer
alias on_recv_cmnd_ctcp_answer_echo on_recv_cmnd_ctcp_answer
alias on_recv_cmnd_ctcp_answer_time on_recv_cmnd_ctcp_answer
alias on_recv_cmnd_ctcp_answer_version on_recv_cmnd_ctcp_answer
alias on_recv_cmnd_ctcp_answer_clientinfo on_recv_cmnd_ctcp_answer
alias on_recv_cmnd_ctcp_answer_userinfo on_recv_cmnd_ctcp_answer
alias on_recv_cmnd_ctcp_answer_action on_recv_cmnd_ctcp_answer
alias on_recv_cmnd_ctcp_answer_dcc on_recv_cmnd_ctcp_answer
end
############################################################
#
# Irc protocol message class
#
class Message
########################################################
#
# constructer
#
# Args:
# message_string,[timestamp,selfNick,server]
#
# If Non-nil message_string is given, purse it.
# or message_string is nil, do nothing.
#
def initialize(msg,*option)
@origin=msg
@timestamp=option[0]
@selfNick=option[1]
@server=option[2]
@from=nil
@fromNick=nil
@command=nil
@cmndstr=nil
@to=nil
@args=Array.new
@ctcpQuery=false
@ctcpAnswer=false
@add_info=nil
parse(msg)
end
########################################################
#
# instance variables
#
attr_reader :timestamp
attr_reader :server
attr_reader :selfNick
attr_reader :from
attr_reader :fromNick
attr_reader :command
attr_reader :cmndstr
attr_reader :to
attr_reader :args
attr_reader :origin
#
# You may use add_info free to put addtional information.
#
attr_accessor :add_info
########################################################
#
# Is this message ctcp?
#
# Return:
# true|false
#
def isCtcp?
return @ctcpQuery|@ctcpAnswer
end
########################################################
#
# Is this message query (ctcp with PRIVMSG)?
#
# Return:
# true|false
#
def isCtcpQuery?
return @ctcpQuery
end
########################################################
#
# Is this message ctcp answer (ctcp with NOTICE)?
#
# Return:
# true|false
#
def isCtcpAnswer?
return @ctcpAnswer
end
########################################################
#
# Did I have published this message?
#
# Return:
# true|false
#
def isSelfMessage?
if(@fromNick==@selfNick)
return true
else
return false
end
end
########################################################
#
# Is this message only for me?
#
# Return:
# true|false
#
def isPriv?
case @command
when Event::RECV_CMND_PRIVMSG,Event::RECV_CMND_NOTICE
#
# Name which starts with '#','&' or '!' is channel name.
#
if(@to=~/^[\#\&\!].+/)
return false
else
return true
end
else
return false
end
end
########################################################
#
# Format as String
#
# Args:
# format_string,timestamp_format_string,kanji_code
#
# format_string:
# %T -> @timestamp : timestamp
# %n -> @selfNick : self nick
# %s -> @server : message published server
# %f -> @fromNick : message from whom(nick)
# %F -> @from : message from whom(full name)
# %c -> @command : command (numeric)
# %C -> @cmndstr : command (alphabetical)
# %t -> @to : message to whom
# %a -> @args : command arguments
# %o -> @origin : original message
# Other charactors : as is
#
# default : "%o"
#
# timestamp_format_string:
# same as Time.strftime()'s format
#
# default : "%H:%M"
#
# kanji_code:
# "jis"|"euc"|"sjis"
#
# default : "euc"
#
# Return:
# String
#
def string(*format)
str=""
tsformat=""
kcode=""
if(format.empty?)
str="%o"
else
str=String(format[0])
tsformat=String(format[1])
kcode=String(format[2]).downcase
end
if(tsformat.empty?)
tsformat="%H:%M"
end
str.gsub!("%T",@timestamp.strftime(tsformat))
str.gsub!("%n",String(@selfNick))
str.gsub!("%s",String(@server))
str.gsub!("%f",String(@fromNick))
str.gsub!("%F",String(@from))
str.gsub!("%c",String(@command))
str.gsub!("%C",String(@cmndstr))
str.gsub!("%t",String(@to))
if(@args.empty?)
str.gsub!("%a","")
else
str.gsub!("%a",@args.join(" "))
end
str.gsub!("%o",@origin.to_s)
case kcode
when "jis"
return Kconv::tojis(str)
when "sjis"
return Kconv::tosjis(str)
else
return str
end
end
########################################################
#
# parse Irc message to internal encoding
#
def parse(msg)
if(String(msg).empty?)
return
end
#
# If there is no timestam, given them
#
if(@timestamp.nil?)
@timestamp=Time.now
end
#
# Socket Event
#
if(msg.instance_of?(Fixnum))
@command=msg
@to=@selfNick
@fromNick=@server
@from=@fromNick
case msg
when Event::LINK_ESTABLISHING
@cmndstr="LINK_ESTABLISHING"
when Event::LINK_ESTABLISHED
@cmndstr="LINK_ESTABLISHED"
when Event::LINK_FAILED
@cmndstr="LINK_FAILED"
when Event::LINK_CLOSING
@cmndstr="LINK_CLOSING"
when Event::LINK_CLOSED
@cmndstr="LINK_CLOSED"
end
return
end
#
# Some spetial messages parse
#
tmp=msg.split(" ",2)
case tmp[0]
when "KILL"
@cmndstr="KILL"
@command=Event::RECV_MESSAGE_KILL
@args=[tmp[1]]
when "PING"
@cmndstr="PING"
@command=Event::RECV_MESSAGE_PING
@args=[tmp[1]]
when "PONG"
@cmndstr="PONG"
@command=Event::RECV_MESSAGE_PONG
@args=[tmp[1]]
when "ERROR"
@cmndstr="ERROR"
@command=Event::RECV_MESSAGE_ERROR
@args=[tmp[1]]
when "NOTICE"
#
# for madoka-parsed CTCP message
#
# She parse unknown ctcp such as
# :hoge!~huga@hoe mohe PRIVMSG ^AGOHAN asa^A
# to
# NOTICE mohe :GOHAN@hoge: asa
#
if(String(tmp[1])=~/([^\s]+) :([^\@\s]+)@([^:]+):(.+)/)
@ctcpQuery=true
@cmndstr="CTCP_QUERY"
@to=String($1)
@channel=@to
@fromNick=String($3)
@from=@fromNick
parseCtcp(Event::RECV_CMND+Event::CMND_CTCP_QUERY,
String($2)+String($4))
else
@cmndstr="NOTICE"
@command=Event::RECV_MESSAGE_NOTICE
@args=[tmp[1]]
end
else
parseMessage(msg)
end
end
private
########################################################
#
# Irc Messages seems
# :from command to arg1 arg2 ... :last arg with space
#
def parseMessage(msg)
#
# get args
#
tmp=msg.sub(/^:/,"").sub(" :","\n").split("\n")
cmdar=tmp[0].split(" ")
if(cmdar.size>3)
@args=cmdar[3..-1]
unless(tmp[1].nil?)
@args.push(tmp[1])
end
else
@args=[tmp[1]]
end
#
# get spoken by whom
#
if(cmdar[0]=~/(.+?)!.*/)
@fromNick=$1
else
@fromNick=cmdar[0]
end
if(@fromNick.nil?)
@command=Event::RECV_MESSAGE_BROKEN
return
end
@fromNick.strip!
@from=cmdar[0].downcase.strip
#
# get command or reply code
#
cmnd=cmdar[1].upcase.strip
@cmndstr=cmnd
@to=cmdar[2]
unless(@to.nil?)
@to.strip!
if(@to.empty?)
@to=nil
end
end
#
# errors or system replys are seem non-0 integer
#
event=cmnd.to_i
if(event==0)
parseCommand(cmnd,@args)
else
@command=event
end
end
########################################################
#
# Irc command parse
# convert String to internal constant
#
def parseCommand(cmnd,arg)
event=Event::RECV_CMND
case(cmnd)
when "PASS"
event+=Event::CMND_PASS
when "NICK"
#
# for madoka feed-back
#
if((@args[0].nil?)&&(!@to.nil?))
@args=[@to]
else
@to=@args[0]
end
event+=Event::CMND_NICK
when "USER"
event+=Event::CMND_USER
when "SERVER"
event+=Event::CMND_SERVER
when "OPER"
event+=Event::CMND_OPER
when "QUIT"
event+=Event::CMND_QUIT
when "SQUIT"
event+=Event::CMND_SQUIT
when "JOIN"
#
# for madoka feed-back
#
if((@args[0].nil?)&&(!@to.nil?))
@args=[@to]
else
@to=@args[0]
end
event+=Event::CMND_JOIN
when "PART"
event+=Event::CMND_PART
when "MODE"
event+=Event::CMND_MODE
when "TOPIC"
event+=Event::CMND_TOPIC
when "NAMES"
event+=Event::CMND_NAMES
when "LIST"
event+=Event::CMND_LIST
when "INVITE"
event+=Event::CMND_INVITE
when "KICK"
event+=Event::CMND_KICK
when "VERSION"
event+=Event::CMND_VERSION
when "STATAS"
event+=Event::CMND_STATAS
when "LINK"
event+=Event::CMND_LINK
when "TIME"
event+=Event::CMND_TIME
when "CONNECT"
event+=Event::CMND_CONNECT
when "TRACE"
event+=Event::CMND_TRACE
when "ADMIN"
event+=Event::CMND_ADMIN
when "INFO"
event+=Event::CMND_INFO
when "PRIVMSG"
begin
if(args[0][0]==1)
@ctcpQuery=true
@cmndstr="CTCP_QUERY"
parseCtcp(event+Event::CMND_CTCP_QUERY,arg.join(" "))
return
end
rescue NameError
end
event+=Event::CMND_PRIVMSG
when "NOTICE"
begin
if(args[0][0]==1)
@ctcpAnswer=true
@cmndstr="CTCP_ANSWER"
parseCtcp(event+Event::CMND_CTCP_ANSWER,args.join(" "))
return
end
rescue NameError
end
event+=Event::CMND_NOTICE
when "WHO"
event+=Event::CMND_WHO
when "WHOIS"
event+=Event::CMND_WHOIS
when "WHOWAS"
event+=Event::CMND_WHOWAS
when "KILL"
event+=Event::CMND_KILL
when "PING"
event+=Event::CMND_PING
when "PONG"
event+=Event::CMND_PONG
when "ERROR"
event+=Event::CMND_ERROR
when "AWAY"
event+=Event::CMND_AWAY
when "REHASH"
event+=Event::CMND_REHASH
when "RESTART"
event+=Event::CMND_RESTART
when "SUMMON"
event+=Event::CMND_SUMMON
when "USERS"
event+=Event::CMND_USERS
when "WALLOPS"
event+=Event::CMND_WALLOPS
when "USERHOST"
event+=Event::CMND_USERHOST
when "ISON"
event+=Event::CMND_ISON
end
@command=event
end
########################################################
#
# Ctcp message parse
#
# Handlabel ctcp commands are follow as:
# PING, ECHO, TIME, VERSION, CLIENTINFO, USERINFO
#
def parseCtcp(event,arg)
if(arg.nil?)
@command=event
return
end
cmnd=nil
arg.gsub!(1.chr,"")
tmp=arg.split(" ",2)
if(tmp[0].nil?)
@command=event
return
else
cmnd=String(tmp[0]).upcase
@args=[String(tmp[1]).strip]
end
@cmndstr+="_"+cmnd
case(cmnd)
when "PING"
event+=Event::CMND_CTCP_PING
when "ECHO"
event+=Event::CMND_CTCP_ECHO
when "TIME"
event+=Event::CMND_CTCP_TIME
when "VERSION"
event+=Event::CMND_CTCP_VERSION
when "CLIENTINFO"
event+=Event::CMND_CTCP_CLIENTINFO
when "USERINFO"
event+=Event::CMND_CTCP_USERINFO
when "ACTION"
event+=Event::CMND_CTCP_ACTION
when "DCC"
event+=Event::CMND_CTCP_DCC
else
#
end
@command=event
end
end
############################################################
#
# TCPSocket wrapper
#
# This class establishs connection to Irc server.
#
# When this class gets event from socket, that will notice
# to observers update() method.
#
# When Observer recieve Event::RECV_MESSAGE, MUST CALL
# this class's read method.
#
# Event format as follow:
# event_code, timestamp, nick, server
#
class Connector
include Observable
WRITE_PRIORITY_HIGH=0
WRITE_PRIORITY_DEFAULT=1
WRITE_PRIORITY_LOW=3
WRITE_PRIORITY_NONE=-1
########################################################
#
# constructer
#
# Args:
# serverinfo,userinfo,nick,kanji_code
#
# serverinfo:
# servername|[servername,port,passwd,serveralias]
#
# default:
# port : 6667
# passwd : ""
# serveralias : same as servername
#
# userinfo:
# username|[username,realname]
#
# default:
# realname=username
#
# kanji_code:
# "euc"|"jis"|"sjis"|"none"
#
# default="jis"
#
def initialize(serverinfo,userinfo,nick,kcode="jis")
#
# set server information
#
if(serverinfo.instance_of?(Array))
@server=String(serverinfo[0])
@port=serverinfo[1].to_i
if(@port==0)
@port=6667
end
@passwd=serverinfo[2]
@serveralias=serverinfo[3]
if(@serveralias.to_s.empty?)
@serveralias=@server
end
else
@server=String(serverinfo)
@port=6667
@passwd=""
@serveralias=@server
end
#
# set user information
#
if(userinfo.instance_of?(Array))
@user=String(userinfo[0])
@realname=String(userinfo[1])
else
@user=String(userinfo)
@realname=@user
end
@nick=nick
#
# set output kanji code
#
@kcode=kcode.to_s.downcase
@mutex=Mutex.new
@socket=nil
@recvthread=nil
@recvmsg=Queue.new
@sendthreads=Hash.new
@sendqueue={WRITE_PRIORITY_HIGH => Queue.new,
WRITE_PRIORITY_DEFAULT => Queue.new,
WRITE_PRIORITY_LOW => Queue.new}
@stat=nil
end
public
attr_reader :server
attr_reader :port
attr_reader :passwd
attr_reader :serveralias
attr_reader :user
attr_reader :realname
attr_accessor :nick
attr_reader :stat
attr_accessor :kcode
########################################################
#
# socket open and start reading, writing threads
#
# Return:
# true (succeed)|false (failed)
#
# Event:
# Event::LINK_ESTABLISHED (successed)
# Event::LINK_FAILED (failed)
#
def open
if(self.alive?)
return false
end
@stat=Event::LINK_ESTABLISHING
begin
@socket=TCPsocket::open(@server,@port)
rescue StandardError,SocketError
@stat=Event::LINK_FAILED
notify(@stat)
return false
end
#
# start thread for reading
#
@recvthread=Thread.start do
readfromsocket
end
#
# start three threads for writing
# (for pong message, for normal message, for ctcp message)
#
for i in [WRITE_PRIORITY_HIGH,
WRITE_PRIORITY_DEFAULT,
WRITE_PRIORITY_LOW]
@sendthreads[i]=Thread.start do
writetosocket(i)
end
end
@stat=Event::LINK_ESTABLISHED
notify(@stat)
return true
end
########################################################
#
# socket close and stop all threads
#
# Event:
# Event::LINK_CLOSED
#
def close
@stat=Event::LINK_CLOSING
#
# stop thread for reading
#
unless(@recvthread.nil?)
if(@recvthread.alive?)
@recvthread.exit
end
end
#
# stop threads for writing
#
@sendthreads.each_value{|t|
unless(t.nil?)
if(t.alive?)
t.exit
end
end
}
#
# close socket
#
unless(@socket.closed?)
@socket.close
end
@stat=Event::LINK_CLOSED
notify(@stat)
end
########################################################
#
# Am I alive?
#
# Return:
# true (alive)|false (dead)
#
# Any threads are dead or socket is closed, asumed dead
#
def alive?
unless(@recvthread.instance_of?(Thread))
return false
end
ret=@recvthread.alive?
@sendthreads.each_value{|t|
ret&=t
}
ret&=(!@socket.closed?)
return ret
end
########################################################
#
# write message to server
#
# Args
# msg: message to write
# options: [priority,echoback]
# priority:
# WRITE_PRIORITY_HIGH|WRITE_PRIORITY_LOW
# |WRITE_PRIORITY_DEFAULT|WRITE_PRIORITY_NONE
# echoback:
# true|false
#
# default options value
# priority: WRITE_PRIORITY_DEFAULT
# echoback: false
#
def write(msg,*option)
#
# remove cr/lf from string and add cr to end of string
#
msg=msg.gsub(/[\r\n]/,"")+"\n"
#
# kanji code conversion
#
case @kcode
when "euc"
msg=Kconv::toeuc(msg)
when "jis"
msg=Kconv::tojis(msg)
when "sjis"
msg=Kconv::tosjis(msg)
else
#
end
#
# parse options
#
priority=WRITE_PRIORITY_DEFAULT
echoback=false
option.each{|opt|
if(opt.instance_of?(TrueClass))
echoback=true
else
case opt
when WRITE_PRIORITY_HIGH
priority=WRITE_PRIORITY_HIGH
when WRITE_PRIORITY_LOW
priority=WRITE_PRIORITY_LOW
when WRITE_PRIORITY_NONE
priority=WRITE_PRIORITY_NONE
end
end
}
#
# write string to queue
#
case priority
when WRITE_PRIORITY_NONE
# nop
when WRITE_PRIORITY_HIGH
@sendqueue[WRITE_PRIORITY_HIGH].push(msg)
when WRITE_PRIORITY_LOW
@sendqueue[WRITE_PRIORITY_LOW].push(msg)
else
@sendqueue[WRITE_PRIORITY_DEFAULT].push(msg)
end
#
# Follow echoback method lacks elegant,
# but I have no idea about other way.
#
if(echoback)
queueingWithNotify(":"+@nick+" "+msg)
end
end
########################################################
#
# read from queue
#
# Return:
# String
#
def read
return Kconv::toeuc(@recvmsg.pop)
end
private
########################################################
#
# notify_observers wrapper
#
def notify(event)
changed
notify_observers(event,Time.now,@nick,@serveralias)
end
########################################################
#
# TCPSocket.read wrapper
#
# Event:
# RECV_MESSAGE
#
# Strings which get form socket is put to queue.
#
def readfromsocket
loop do
if(@socket.eof?)
break
else
begin
queueingWithNotify(@socket.gets)
rescue StandardError,SocketError,IOError
break
end
end
end
@recvthread=nil
self.close
Thread.current.exit
end
########################################################
#
# TCPSocket.write wrapper
#
# read one message from queue, and write to socket
#
def writetosocket(priority)
loop do
mes=@sendqueue[priority].pop
begin
@socket.write(mes)
rescue StandardError,SocketError,IOError
break
end
sleep(priority)
end
@sendthreads[priority]=nil
self.close
Thread.current.exit
end
########################################################
#
# queueing and notifing
#
def queueingWithNotify(str)
unless(str.nil?)
str.gsub!("[\r\n]+","")
@recvmsg.push(str)
changed
notify(Event::RECV_MESSAGE)
end
end
end
############################################################
#
# Irc connection management class
#
# This class is relaying between each Connectors to
# the Message Distributer.
#
class ConnectionManager
include Observable
include Singleton
########################################################
#
# constructer
#
def initialize
@connectors=Hash.new
@quited=Array.new
@msgQueue=Queue.new
@eventQueue=Queue.new
@mutex=Mutex.new
@thread=Thread.start do
issueEvent
end
end
attr_reader :connectors
########################################################
#
# event reciever
#
# all events are forwarded to the Message Distributer.
#
def update(event,timestamp,nick,server)
@mutex.lock
case event
when Event::LINK_CLOSED,Event::LINK_FAILED
#
# When link close or failed, remove server from table
#
if(@quited.include?(server))
@connectors.delete(server)
@connectors.rehash
@quited.delete(server)
end
when Event::RECV_MESSAGE
#
# get one message from server and forward
#
if(@connectors.has_key?(server))
msg=@connectors[server].read
unless(msg.nil?)
@msgQueue.push(msg)
end
end
end
#
# call MessageDistributer#update NOT directory,
# but gather to one thread.
#
@eventQueue.push([event,timestamp,nick,server])
@mutex.unlock
end
########################################################
#
# Connector::open() wrapper
#
# Return:
# true(succeed)|failse(falied)|nil(already open)
#
def open(serverinfo,userinfo,nick,kcode="jis")
#
# get server name
#
unless(serverinfo.instance_of?(Array))
serverinfo=[String(serverinfo),6667,"",String(serverinfo)]
end
server=serverinfo[3]
if(server.to_s.empty?)
server=serverinfo[0]
end
unless(@connectors.has_key?(server))
#
# create Connector, regist to table of connector's,
# and be Connector's observer.
#
@connectors[server]=
Connector.new(serverinfo,userinfo,nick,kcode)
@connectors[server].add_observer(self)
end
return @connectors[server].open
end
########################################################
#
# Connector::close() wrapper
#
# Args:
# server
#
# If server is nil, close all connections.
#
def close(server,purge=false)
if(server.nil?)
if(purge)
@connectors.each_key{|s|
@quited.push(s)
}
end
@connectors.each_value{|conn|
conn.close
}
else
unless(server.instance_of?(Array))
server=[String(server)]
end
if(purge)
server.each{|s|
@quited.push(s)
}
end
server.each{|s|
if(@connectors.has_key?(s))
@connectors[s].close
end
}
end
end
########################################################
#
# Reopen connections
#
# Return:
# true(succeed)|failse(falied)|nil(already open or purged)
#
def reopen(server)
unless(@connectors.has_key?(server))
return nil
end
return @connectors[server].open
end
########################################################
#
# Close all connections
#
def closeAll(purge=false)
self.close(nil,purge)
end
########################################################
#
# Iterator
#
def eachConnector
for i in @connector
yield(i)
end
end
########################################################
#
# Delegator
#
def [](server)
return @connectors[server]
end
########################################################
#
# Is connection alive?
#
def alive?(server)
if(@connectors.has_key?(server))
return @connectors[server].alive?
else
return false
end
end
########################################################
#
# Listing connection
#
# Return:
# Array of server name
#
def connections
return @connectors.keys
end
########################################################
#
# Set server's nick
#
# Return:
# Array of server name
#
def setNick(server,nick)
if(@connectors.has_key?(server))
@connectors[server].nick=nick
end
end
########################################################
#
# Connector::write() wrapper
#
# Args:
# server,message,[priority,echoback]
#
# If server is nil, write to all connections.
#
def write(server,msg,*option)
if(server.nil?)
@connectors.each_value{|conn|
conn.write(msg,*option)
}
else
unless(server.instance_of?(Array))
server=[String(server)]
end
server.each{|s|
if(@connectors.has_key?(s))
@connectors[s].write(msg,*option)
end
}
end
end
########################################################
#
# write to all connections
#
def writeAll(msg,*option)
self.write(nil,msg,*option)
end
########################################################
#
# IrcConnection.read() wrapper
#
def read
return @msgQueue.pop
end
private
########################################################
#
# event messages are gathered and issued only from here.
#
def issueEvent
loop do
event=@eventQueue.pop
changed
notify_observers(event[0],event[1],event[2],event[3])
end
end
end
############################################################
#
# Message Distributior class
#
# This class makes Irc message capcellized, distribute that from
# the connection manager to each Message processors, and command
# which is published by each Message processor to the connection
# manager.
#
# And more, server login process, PING-PONG process and server
# nick management process are handled at here.
#
#
class MessageDistributor
include Observable
include Singleton
########################################################
#
# constructer
#
# be ConnectionManager's observer
#
def initialize
@connector=ConnectionManager.instance
@connector.add_observer(self)
end
########################################################
#
# event recievor
#
# All evetns are forward to each Message Processors with
# Message.
#
def update(event,timestamp,nick,server)
case event
when Event::LINK_ESTABLISHED
#
# when connect to server, do login
#
login(server)
changed
notify_observers(Message.new(event,
timestamp,nick,server))
when Event::LINK_CLOSED,Event::LINK_FAILED
changed
notify_observers(Message.new(event,
timestamp,nick,server))
when Event::RECV_MESSAGE
#
# message capcellized
#
msg=Message.new(@connector.read,
timestamp,nick,server)
#
# handle some message
#
if(process(msg))
changed
notify_observers(msg)
end
end
end
########################################################
#
# ConnectionManager::open() wrapper
#
def open(serverinfo,userinfo,nick,kcode="jis")
@connector.open(serverinfo,userinfo,nick,kcode)
end
########################################################
#
# ConnectionManager::reopen() wrapper
#
def reopen(server)
@connector.reopen(server)
end
########################################################
#
# ConnectionManager::close() wrapper
#
# The connection information are purged.
#
def close(server,purge=true)
if(purge)
#
# If connention is active, do logout before close.
#
if(@connector.alive?(server))
self.cmnd_quit(server)
end
end
@connector.close(server,purge)
end
########################################################
#
# close all connection
#
def closeAll(purge=true)
@connector.connections.each{|conn|
self.close(conn,purge)
}
end
########################################################
#
# ConnectionManager::connection wrapper
#
def connections
return @connector.connections
end
########################################################
#
# command publish helpers
#
def cmnd_pass(server,passwd)
@connector.write(server,"pass "+passwd,
Connector::WRITE_PRIORITY_HIGH)
end
def cmnd_nick(server,nickname)
@connector.write(server,"nick "+nickname)
end
def cmnd_user(server,username,realname)
@connector.write(server,
"user "+username.downcase+" * * :"+realname,
Connector::WRITE_PRIORITY_HIGH)
end
def cmnd_server(server)
#not impriment
end
def cmnd_oper(server)
#not impriment
end
def cmnd_quit(server,*msg)
if(msg.empty?)
@connector.write(server,"quit",true)
else
@connector.write(server,"quit :"+String(msg[0]),true)
end
end
def cmnd_squit(server)
#not impriment
end
def cmnd_join(server,chnl,*key)
if(key.empty?)
@connector.write(server,"join "+chnl)
else
@connector.write(server,"join "+chnl+" "+key.join(","))
end
end
def cmnd_part(server,chnl,*msg)
if(msg.empty?)
@connector.write(server,"part "+chnl)
else
@connector.write(server,"part "+chnl+" :"+String(msg[0]))
end
end
def cmnd_mode(server,chnl,*arg)
if(arg.empty?)
@connector.write(server,"mode "+chnl)
else
@connector.write(server,"mode "+chnl+" :"+arg.join(" "))
end
end
def cmnd_topic(server,chnl,*arg)
if(arg.empty?)
@connector.write(server,"topic "+chnl)
else
@connector.write(server,"topic "+chnl+" :"+String(arg[0]))
end
end
def cmnd_names(server,*chnl)
if(chnl.empty?)
@connector.write(server,"names")
else
@connector.write(server,"names "+String(chnl[0]))
end
end
def cmnd_list(server)
#not impriment
end
def cmnd_invite(server,chnl,nickname)
@connector.write(server,"invite "+nickname+" "+chnl)
end
def cmnd_kick(server,chnl,nickname,*reason)
if(reason.empty?)
@connector.write(server,"kick "+chnl+" "+nickname)
else
@connector.write(server,
"kick "+chnl+" "+nickname+" :"+
String(reason[0]))
end
end
def cmnd_version(server)
#not impriment
end
def cmnd_statas(server)
#not impriment
end
def cmnd_link(server)
#not impriment
end
def cmnd_time(server)
#not impriment
end
def cmnd_connect(server)
#not impriment
end
def cmnd_trace(server)
#not impriment
end
def cmnd_admin(server)
#not impriment
end
def cmnd_info(server)
#not impriment
end
def cmnd_privmsg(server,to,msg)
limit=RICA_PRIVMSG_MAX_LEN-(to.size+10)
autofill(msg,limit).each{|str|
@connector.write(server,"privmsg "+to+" :"+str,true)
}
end
def cmnd_notice(server,to,msg)
limit=RICA_PRIVMSG_MAX_LEN-(to.size+9)
autofill(msg,limit).each{|str|
@connector.write(server,"notice "+to+" :"+str,true)
}
end
def cmnd_who(server,nickname)
@connector.write(server,"who "+nickname)
end
def cmnd_whois(server,nickname)
@connector.write(server,"whois "+nickname)
end
def cmnd_whowas(server,nickname)
@connector.write(server,"whowas "+nickname)
end
def cmnd_kill(server)
#not impriment
end
def cmnd_ping(server,arg)
@connector.write(server,"ping "+arg,
Connector::WRITE_PRIORITY_HIGH)
end
def cmnd_pong(server,arg)
@connector.write(server,"pong "+arg,
Connector::WRITE_PRIORITY_HIGH)
end
def cmnd_error(server)
#not impriment
end
def cmnd_away(server,*msg)
if(msg.empty?)
@connector.write(server,"away")
else
@connector.write(server,"away :"+String(msg[0]))
end
end
def cmnd_rehash(server)
#not impriment
end
def cmnd_restart(server)
#not impriment
end
def cmnd_summon(server)
#not impriment
end
def cmnd_users(server)
#not impriment
end
def cmnd_wallops(server)
#not impriment
end
def cmnd_userhost(server)
#not impriment
end
def cmnd_ison(server,nickname)
@connector.write(server,"ison "+nickname)
end
def ctcp_query(server,to,msg)
@connector.write(server,"privmsg "+to+" :"+1.chr+msg+1.chr,
Connector::WRITE_PRIORITY_LOW)
end
def ctcp_answer(server,to,msg)
@connector.write(server,"notice "+to+" :"+1.chr+msg+1.chr,
Connector::WRITE_PRIORITY_LOW)
end
def ctcp_query_ping(server,to)
ctcp_query(server,to,"PING "+String(Time.now.tv_sec))
end
def ctcp_query_echo(server,to,str)
ctcp_query(server,to,"ECHO "+str)
end
def ctcp_query_time(server,to)
ctcp_query(server,to,"TIME")
end
def ctcp_query_version(server,to)
ctcp_query(server,to,"VERSION")
end
def ctcp_query_clientinfo(server,to,*option)
if(option.empty?)
ctcp_query(server,to,"CLIENTINFO")
else
ctcp_query(server,to,"CLIENTINFO "+String(option[0]))
end
end
def ctcp_query_userinfo(server,to)
ctcp_query(server,to,"USERINFO")
end
def ctcp_answer_ping(server,to,arg)
ctcp_answer(server,to,"PING "+arg)
end
def ctcp_answer_echo(server,to,arg)
ctcp_answer(server,to,"ECHO "+arg)
end
def ctcp_answer_time(server,to)
ctcp_answer(server,to,"TIME "+String(Time.now.localtime))
end
def ctcp_answer_version(server,to,arg)
ctcp_answer(server,to,"VERSION "+arg)
end
def ctcp_answer_clientinfo(server,to,msg)
ctcp_answer(server,to,"CLIENTINFO "+msg)
end
def ctcp_answer_userinfo(server,to,msg)
if(msg.instance_of?(String))
msg=msg.split("\n")
end
if(msg.instance_of?(Array))
msg.each{|m|
ctcp_answer(server,to,"USERINFO :"+m)
}
end
end
########################################################
#
# direct command publish
#
# If command is "QUIT", "PRIVMSG" or "NOTICE", and it's not
# CTCP published message is been echoback.
#
def directcommand(server,msg)
tmp=nil
if(msg[0]==":")
tmp=Message.new(msg)
else
tmp=Message.new(":* "+msg)
end
case tmp.command
when Event::RECV_CMND_QUIT,
Event::RECV_CMND_PRIVMSG,Event::RECV_CMND_NOTICE
@connector.write(server,msg,true)
else
@connector.write(server,msg)
end
end
########################################################
#
# talkback
#
# Message does NOT send to server, but only distributes
# to each Message processor.
#
def talkback(server,msg)
@connector.write(server,msg,true,
Connector::WRITE_PRIORITY_NONE)
end
########################################################
#
# some procs
#
def login(server)
conn=nil
if(@connector.alive?(server))
conn=@connector[server]
else
return
end
unless(conn.passwd.empty?)
self.cmnd_pass(server,conn.passwd)
end
self.cmnd_user(server,conn.user.downcase,conn.realname)
self.cmnd_nick(server,conn.nick)
end
def setAway(server,msg)
self.cmnd_away(server,msg)
end
def unsetAway(server)
self.cmnd_away(server)
end
def getTopic(server,chnl)
self.cmnd_topic(server,chnl)
end
def setTopic(server,chnl,str)
self.cmnd_topic(server,chnl,str)
end
def getMode(server,chnl)
self.cmnd_mode(server,chnl)
end
def setMode(server,chnl,str)
self.cmnd_mode(server,chnl,str)
end
########################################################
#
# Override Observerable Module to apply Thread
#
def add_observer(observer)
super
@observer_queues = {} unless defined? @observer_queues
@observer_queues[observer]=Queue.new
@observer_threads = {} unless defined? @observer_threads
@observer_threads[observer]=Thread.new(observer){
loop do
arg=@observer_queues[observer].pop
observer.update(*arg)
end
}
end
def delete_observer(observer)
if defined? @observer_threads
if(@observer_threads.has_key?(observer))
@observer_threads[observer].kill
@observer_threads.delete(observer)
end
end
@observer_queues.delete(observer) if defined? @observer_queues
super
end
def delete_observers
if(@observer_threads.defined?)
@observer_threads.each_value{|t|
t.kill
}
@observer_threads[observer].clear
end
@observer_queues.clear if defined? @observer_queues
super
end
def notify_observers(*arg)
if defined? @observer_state and @observer_state
if defined? @observer_peers
for i in @observer_peers.dup
@observer_queues[i].push(arg.to_a)
end
end
@observer_state = false
end
end
def observer_thread(observer)
if defined? @observer_threads
return @observer_threads[observer]
else
return nil
end
end
private
########################################################
#
# Error handling, PING-PONG, server nick management
#
# Return:
# true (event is forwarded)|false (event is NOT forwarded)
#
def process(msg)
ret=true
case msg.command
when Event::RECV_MESSAGE_KILL
@connector.close(msg.server)
when Event::RECV_MESSAGE_PING
self.cmnd_pong(msg.server,msg.args[0])
ret=false
when Event::RECV_MESSAGE_PONG
ret=false
when Event::RECV_MESSAGE_ERROR
@connector.close(msg.server)
when Event::RECV_RPL_INIT,Event::RECV_RPL_MOTDSTART
@connector.setNick(msg.server,msg.to)
when Event::RECV_CMND_NICK
if(msg.isSelfMessage?)
@connector.setNick(msg.server,msg.args[0].strip)
end
when Event::RECV_CMND_QUIT
if(msg.isSelfMessage?)
@connector.close(msg.server,true)
end
else
#
end
return ret
end
########################################################
#
# strings auto-fill
#
# Args:
# str : strings
# limit : fill length
#
# Return:
# lines : matrix of each line
#
def autofill(str,limit)
lines=[]
thisline=str.dup.to_s
until(thisline.empty?) do
#
# line break with multi-byte charactor supporting
#
while(thisline.size>limit)
thisline.chop!
end
if(thisline==str)
str=""
else
str=str[thisline.size..-1].to_s
end
if(str.empty?)
lines.push(thisline)
thisline=str.dup.to_s
else
#
# If there is a white space, break at there.
#
tmp=thisline.reverse.split(/\s/,2)
unless(tmp[1].to_s.empty?)
lines.push(tmp[1].reverse)
thisline=" "+tmp[0].reverse+str.dup.to_s
else
lines.push(tmp[0].reverse)
thisline=str.dup.to_s
end
end
end
return lines
end
end
############################################################
#
# message process class template.
#
# This class is forwarded methods and Message from
# MessageDistributor.
# So, you can access his all methods as those were at this
# class.
#
# To create your original front-end or agents(eg. bot), it's
# easy way that you create sub-class inheriting this class.
#
class MessageProcessor<SimpleDelegator
include Event
########################################################
#
# constructor
#
# be MessageDistributor's observor and delegetor
#
def initialize
@conn=MessageDistributor.instance
@conn.add_observer(self)
super(@conn)
end
########################################################
#
# get self thread
#
# Return:
# Thread
#
def thread
return @conn.observer_thread(self)
end
def update(msg)
dispatch(msg)
end
def dispatch(msg)
super
end
end
end
syntax highlighted by Code2HTML, v. 0.9.1