Some code cleanup and clarification in comments.

This commit is contained in:
Griatch 2009-08-28 01:33:15 +00:00
parent 2640bd057a
commit 4bd567386f
12 changed files with 351 additions and 66 deletions

View file

@ -144,3 +144,9 @@ def parse_ansi(string, strip_ansi=False, strip_formatting=False, parser=ANSI_PAR
"""
return parser.parse_ansi(string, strip_ansi=strip_ansi,
strip_formatting=strip_formatting)
def clean_ansi(string):
"""
Cleans all ansi symbols from a string
"""
r= re.compile("\033\[[0-9;]+m")
return r.sub("", string) #replace all matches with empty strings

View file

@ -9,8 +9,10 @@ from src import defines_global
from src import ansi
from src.util import functions_general
from src.cmdtable import GLOBAL_CMD_TABLE
from src.imc2.models import IMC2ChannelMapping
from src.imc2.packets import IMC2PacketIceMsgBroadcasted
#from src.imc2.models import IMC2ChannelMapping
#from src.imc2.packets import IMC2PacketIceMsgBroadcasted
#from src.irc.models import IRCChannelMapping
#from src.irc.connection import IRC_CHANNELS
def cmd_addcom(command):
"""
@ -233,7 +235,7 @@ def cmd_cemit(command):
cname = eq_args[0]
cmessage = eq_args[1]
final_cmessage = cmessage
if len(cname) == 0:
source_object.emit_to("You must provide a channel name to emit to.")
return
@ -247,7 +249,7 @@ def cmd_cemit(command):
else:
source_object.emit_to("Could not find channel %s." % (cname,))
return
# If this is False, don't show the channel header before
# the message. For example: [Public] Woohoo!
show_channel_header = True
@ -274,22 +276,11 @@ def cmd_cemit(command):
if not "quiet" in command.command_switches:
source_object.emit_to("Sent - %s" % (name_matches[0],))
comsys.send_cmessage(cname_parsed, final_cmessage,
show_header=show_channel_header)
show_header=show_channel_header)
if settings.IMC2_ENABLED:
# Look for IMC2 channel maps. If one is found, send an ice-msg-b
# packet to the network.
try:
from src.imc2.connection import IMC2_PROTOCOL_INSTANCE
map = IMC2ChannelMapping.objects.get(channel__name=cname_parsed)
packet = IMC2PacketIceMsgBroadcasted(map.imc2_server_name,
map.imc2_channel_name,
source_object,
cmessage)
IMC2_PROTOCOL_INSTANCE.send_packet(packet)
except IMC2ChannelMapping.DoesNotExist:
# No map found, do nothing.
pass
#pipe to external channels (IRC, IMC) eventually mapped to this channel
comsys.send_cexternal(cname_parsed, "[%s] %s" % (cname_parsed,final_cmessage))
GLOBAL_CMD_TABLE.add_command("@cemit", cmd_cemit),
def cmd_cwho(command):
@ -362,7 +353,7 @@ def cmd_ccreate(command):
new_chan = comsys.create_channel(cname, source_object)
source_object.emit_to("Channel %s created." % (new_chan.get_name(),))
GLOBAL_CMD_TABLE.add_command("@ccreate", cmd_ccreate,
priv_tuple=("objects.add_commchannel")),
priv_tuple=("objects.add_commchannel",))
def cmd_cchown(command):
"""

View file

@ -7,14 +7,17 @@ from src.config.models import ConfigValue
from src.objects.models import Object
from src import defines_global
from src import ansi
from src import comsys
from src.util import functions_general
from src.cmdtable import GLOBAL_CMD_TABLE
from src.ansi import parse_ansi
from src.imc2.imc_ansi import IMCANSIParser
from src.imc2 import connection as imc2_conn
from src.imc2.packets import *
from src.imc2.models import IMC2ChannelMapping
from src.imc2.trackers import IMC2_MUDLIST, IMC2_CHANLIST
from src.channels.models import CommChannel
def cmd_imcwhois(command):
"""
Shows a player's inventory.
@ -114,4 +117,62 @@ def cmd_imcstatus(command):
retval += '-' * 50
source_object.emit_to(retval)
GLOBAL_CMD_TABLE.add_command("imcstatus", cmd_imcstatus)
GLOBAL_CMD_TABLE.add_command("imcstatus", cmd_imcstatus)
def cmd_IMC2chan(command):
"""
@imc2chan IMCchannel channel
Links an IMC channel to an existing
evennia channel. You can link as many existing
evennia channels as you like to the
IMC channel this way. Running the command with an
existing mapping will re-map the channels.
Use 'imcchanlist' to get a list of IMC channels.
"""
source_object = command.source_object
if not settings.IMC2_ENABLED:
s = """IMC is not enabled. You need to activate it in game/settings.py."""
source_object.emit_to(s)
return
args = command.command_argument
if not args or len(args.split()) != 2 :
source_object.emit_to("Usage: @imc2chan IMCchannel channel")
return
imc_channel, channel = args.split()
imclist = IMC2_CHANLIST.get_channel_list()
if imc_channel not in [c.localname for c in imclist]:
source_object.emit_to("IMC channel '%s' not found." % imc_channel)
return
else:
imc_channel = filter(lambda c: c.localname==imc_channel,imclist)
if imc_channel: imc_channel = imc_channel[0]
try:
chanobj = comsys.get_cobj_from_name(channel)
except CommChannel.DoesNotExist:
source_object.emit_to("Local channel '%s' not found (use real name, not alias)." % channel)
return
#create the mapping.
outstring = ""
mapping = IMC2ChannelMapping.objects.filter(channel__name=channel)
if mapping:
mapping = mapping[0]
outstring = "Replacing %s. New " % mapping
else:
mapping = IMC2ChannelMapping()
server,name = imc_channel.name.split(":")
mapping.imc2_server_name = server.strip() #settings.IMC2_SERVER_ADDRESS
mapping.imc2_channel_name = name.strip() #imc_channel.name
mapping.channel = chanobj
mapping.save()
outstring += "Mapping set: %s." % mapping
source_object.emit_to(outstring)
GLOBAL_CMD_TABLE.add_command("@imc2chan",cmd_IMC2chan,auto_help=True,staff_help=True,
priv_tuple=("objects.add_commchannel",))

View file

@ -3,11 +3,16 @@ Comsys functions.
"""
import time
import datetime
from django.conf import settings
from django.utils import simplejson
from src.channels.models import CommChannel, CommChannelMessage, CommChannelMembership
from src import session_mgr
from src import ansi
from src import logger
from src.imc2.packets import IMC2PacketIceMsgBroadcasted
from src.imc2.models import IMC2ChannelMapping
from src.irc.models import IRCChannelMapping
import src.ansi
def plr_get_cdict(session):
"""
@ -226,13 +231,18 @@ def load_object_channels(pobject):
session.channels_subscribed[membership.user_alias] = [membership.channel.name,
membership.is_listening]
def send_cmessage(channel, message, show_header=True):
def send_cmessage(channel, message, show_header=True, from_external=None):
"""
Sends a message to all players on the specified channel.
channel: (string or CommChannel) Name of channel or a CommChannel object.
message: (string) Message to send.
show_header: (bool) If False, don't prefix message with the channel header.
from_external: (string/None)
Can be None, 'IRC' or 'IMC2'. The sending functions of the
respective protocol sets this flag, otherwise it should
be None; it allows for piping messages between protocols
without accidentally also echoing it back to where it came from.
"""
if isinstance(channel, unicode) or isinstance(channel, str):
# If they've passed a string as the channel argument, look up the
@ -258,6 +268,10 @@ def send_cmessage(channel, message, show_header=True):
chan_message.message = message
chan_message.save()
#pipe to external protocols
if from_external:
send_cexternal(channel_obj.name, message, from_external)
def get_all_channels():
"""
Returns all channel objects.
@ -295,3 +309,63 @@ def cname_search(search_text, exact=False):
return CommChannel.objects.filter(name__iexact=search_text)
else:
return CommChannel.objects.filter(name__istartswith=search_text)
def send_cexternal(cname, cmessage, from_external=None):
"""
This allows external protocols like IRC and IMC to send to a channel
while also echoing to each other. This used by channel-emit functions
to transparently distribute channel sends to external protocols.
cname - name of evennia channel sent to
cmessage - message sent (should be pre-formatted already)
from_external - which protocol sent the emit.
Currently supports 'IRC' and 'IMC2' or None
(this avoids emits echoing back to themselves). If
None, it is assumed the message comes from within Evennia
and all mapped external channels will be notified.
"""
if settings.IMC2_ENABLED and not from_external=="IMC":
#map an IRC emit to the IMC network
# Look for IMC2 channel maps. If one is found, send an ice-msg-b
# packet to the network.
#handle lack of user, IMC-way.
try:
from src.imc2.connection import IMC2_PROTOCOL_INSTANCE
map = IMC2ChannelMapping.objects.get(channel__name=cname)
packet = IMC2PacketIceMsgBroadcasted(map.imc2_server_name,
map.imc2_channel_name,
"*",
cmessage)
IMC2_PROTOCOL_INSTANCE.send_packet(packet)
except IMC2ChannelMapping.DoesNotExist:
# No map found, do nothing.
pass
if settings.IRC_ENABLED and not from_external=="IRC":
# Map an IMC emit to IRC channels
# Look for IRC channel maps. If found, echo cmessage to the
# IRC channel.
try:
#this fails with a DoesNotExist if the channel is not mapped.
from src.irc.connection import IRC_CHANNELS
mapping = IRCChannelMapping.objects.filter(channel__name=cname)
#strip the message of ansi characters.
cmessage = ansi.clean_ansi(cmessage)
for mapp in mapping:
mapped_irc = filter(lambda c: c.factory.channel==mapp.irc_channel_name,
IRC_CHANNELS)
for chan in mapped_irc:
chan.send_msg(cmessage.encode("utf-8"))
except IRCChannelMapping.DoesNotExist:
#no mappings. Ignore
pass

View file

@ -66,53 +66,80 @@ DATABASE_HOST = ''
# Empty string defaults to localhost. Not used with sqlite3.
DATABASE_PORT = ''
"""
IMC Configuration
This is static and important enough to put in the server-side settings file.
Copy and paste this section to your game/settings.py file and change the
values to fit your needs.
# Communication channels in-game
Evennia's IMC2 client was developed against MudByte's network. You may
register and join it by going to:
http://www.mudbytes.net/imc2-intermud-join-network
"""
Your names of various default comm channels for emitting
debug- or informative messages.
"""
Choose "Other unsupported IMC2 version" and enter your information there.
You'll want to change the values below to reflect what you entered.
"""
# Make sure this is True in your settings.py.
# CHANGE THIS TO True IF YOU WANT IMC!
IMC2_ENABLED = False
# While True, emit additional debugging info.
IMC2_DEBUG = False
# The hostname/ip address of your IMC2 server of choice.
# CHANGE THIS!
IMC2_SERVER_ADDRESS = None
# The port to connect to on your IMC2 server.
# CHANGE THIS!
IMC2_SERVER_PORT = None
# This is your game's IMC2 name.
# CHANGE THIS TO A SHORT ALPHANUMERIC STRING!
IMC2_MUDNAME = None
# Your IMC2 client-side password. Used to authenticate with your network.
# CHANGE THIS TO A SHORT ALPHANUMERIC STRING!
IMC2_CLIENT_PW = None
# Your IMC2 server-side password. Used to verify your network's identity.
# CHANGE THIS TO A SHORT ALPHANUMERIC STRING!
IMC2_SERVER_PW = None
# This isn't something you should generally change.
IMC2_PROTOCOL_VERSION = '2'
# MudBytes IMC Information
#IMC2_SERVER_ADDRESS = 'server02.mudbytes.net'
#IMC2_SERVER_PORT = 9000
"""
Various comm channels for emitting debug or informative messages.
"""
COMMCHAN_IMC2_INFO = 'MUDInfo'
COMMCHAN_MUD_INFO = 'MUDInfo'
COMMCHAN_MUD_CONNECTIONS = 'MUDConnections'
"""
IMC Configuration
IMC (Inter-MUD communication) allows for an evennia chat channel that connects
to people on other MUDs also using the IMC. Your evennia server do *not* have
to be open to the public to use IMC; it works as a stand-alone chat client.
Copy and paste this section to your game/settings.py file and change the
values to fit your needs.
Evennia's IMC2 client was developed against MudByte's network. You must
register your MUD on the network before you can use it, go to
http://www.mudbytes.net/imc2-intermud-join-network.
Choose 'Other unsupported IMC2 version' from the choices and
and enter your information there. You have to enter the same
'short mud name', 'client password' and 'server password' as you
define in this file.
The Evennia discussion channel is on server02.mudbytes.net:9000.
"""
# Change to True if you want IMC active at all.
IMC2_ENABLED = False
# The hostname/ip address of your IMC2 server of choice.
IMC2_SERVER_ADDRESS = 'server02.mudbytes.net'
#IMC2_SERVER_ADDRESS = None
# The port to connect to on your IMC2 server.
IMC2_SERVER_PORT = 9000
#IMC2_SERVER_PORT = None
# This is your game's IMC2 name on the network (e.g. "MyMUD").
IMC2_MUDNAME = None
# Your IMC2 client-side password. Used to authenticate with your network.
IMC2_CLIENT_PW = None
# Your IMC2 server-side password. Used to verify your network's identity.
IMC2_SERVER_PW = None
# Emit additional debugging info to log.
IMC2_DEBUG = False
# This isn't something you should generally change.
IMC2_PROTOCOL_VERSION = '2'
"""
IRC config. This allows your evennia channels to connect to an external IRC
channel. Evennia will connect under a nickname that then echoes what is
said on the channel to IRC and vice versa.
Obs - make sure the IRC network allows bots.
"""
#Activate the IRC bot.
IRC_ENABLED = True
#Which IRC network (e.g. irc.freenode.net)
IRC_NETWORK = "irc.freenode.net"
#Which IRC port to connect to (e.g. 6667)
IRC_PORT = 6667
#Which channel on the network to connect to (including the #)
IRC_CHANNEL = ""
#Under what nickname should Evennia connect to the channel
IRC_NICKNAME = ""
# Local time zone for this installation. All choices can be found here:
# http://www.postgresql.org/docs/8.0/interactive/datetime-keywords.html#DATETIME-TIMEZONE-SET-TABLE
TIME_ZONE = 'America/New_York'
@ -232,10 +259,11 @@ INSTALLED_APPS = (
'src.objects',
'src.channels',
'src.imc2',
'src.irc',
'src.helpsys',
'src.genperms',
'game.web.apps.news',
'game.web.apps.website',
'game.web.apps.website',
)
"""
@ -270,6 +298,7 @@ COMMAND_MODULES = (
'src.commands.privileged',
'src.commands.search',
'src.commands.imc2',
'src.commands.irc',
)
"""

View file

@ -124,7 +124,8 @@ class IMC2Protocol(StatefulTelnetProtocol):
# Bombs away.
for mapping in mappings:
if mapping.channel:
comsys.send_cmessage(mapping.channel, message)
comsys.send_cmessage(mapping.channel, message,
from_external="IMC2")
except IMC2ChannelMapping.DoesNotExist:
# No channel mapping found for this message, ignore it.
pass

View file

@ -751,4 +751,4 @@ class IMC2PacketCloseNotify(IMC2Packet):
if __name__ == "__main__":
packstr = "Kayle@MW 1234567 MW!Server02!Server01 ice-msg-b *@* channel=Server01:ichat text=\"*they're going woot\" emote=0 echo=1"
packstr = "*@Lythelian 1234567 Lythelian!Server01 is-alive *@* versionid=\"Tim's LPC IMC2 client 30-Jan-05 / Dead Souls integrated\" networkname=Mudbytes url=http://dead-souls.net host=70.32.76.142 port=6666 sha256=0"
print IMC2Packet(packstr)
print IMC2Packet(packstr)

0
src/irc/__init__.py Normal file
View file

11
src/irc/admin.py Normal file
View file

@ -0,0 +1,11 @@
"""
This sets up a few fields in the admin interface for connecting IRC channels
to evennia channels.
"""
from src.irc.models import IRCChannelMapping
from django.contrib import admin
class IRCChannelMappingAdmin(admin.ModelAdmin):
list_display = ('channel', 'irc_server_name',
'irc_channel_name', 'is_enabled')
admin.site.register(IRCChannelMapping, IRCChannelMappingAdmin)

83
src/irc/connection.py Normal file
View file

@ -0,0 +1,83 @@
"""
This connects to an IRC network/channel and launches an 'bot' onto it.
The bot then pipes what is being said between the IRC channel and one or
more Evennia channels.
"""
from twisted.words.protocols import irc
from twisted.internet import protocol
from twisted.internet import reactor
from src.irc.models import IRCChannelMapping
from src import comsys
from src import logger
#store all irc channels
IRC_CHANNELS = []
class IRC_Bot(irc.IRCClient):
def _get_nickname(self):
"required for correct nickname setting"
return self.factory.nickname
nickname = property(_get_nickname)
def signedOn(self):
global IRC_CHANNELS
self.join(self.factory.channel)
# This is the first point the protocol is instantiated.
# add this protocol instance to the global list so we
# can access it later to send data.
IRC_CHANNELS.append(self)
logger.log_infomsg("IRC: Client connecting to %s.'" % (self.factory.channel))
def joined(self, channel):
logger.log_infomsg("Joined %s/%s as '%s'." % (self.factory.network,channel,self.factory.nickname))
def privmsg(self, user, irc_channel, msg):
"Someone has written something in channel. Echo it to the evennia channel"
print "got msg: %s" % msg
try:
#find irc->evennia channel mappings
mappings = IRCChannelMapping.objects.filter(irc_channel_name=irc_channel)
if not mappings:
return
#format message:
user = user.split("!")[0]
if user:
user.strip()
msg = "%s@%s: %s" % (user,irc_channel,msg)
logger.log_infomsg("<IRC: " + msg)
for mapping in mappings:
if mapping.channel:
comsys.send_cmessage(mapping.channel, msg, from_external="IRC")
except IRCChannelMapping.DoesNotExist:
#no mappings found. Ignore.
pass
def send_msg(self,msg):
"Called by evennia when sending something to mapped IRC channel"
self.msg(self.factory.channel, msg)
logger.log_infomsg(">IRC: " + msg)
class IRC_BotFactory(protocol.ClientFactory):
protocol = IRC_Bot
def __init__(self, channel, network, nickname):
self.network = network
self.channel = channel
self.nickname = nickname
def clientConnectionLost(self, connector, reason):
logger.log_errmsg("IRC: Lost connection (%s), reconnecting." % reason)
connector.connect()
def clientConnectionFailed(self, connector, reason):
logger.log_errmsg("IRC: Could not connect: %s" % reason)
def connect_to_IRC(irc_network,irc_port,irc_channel,irc_bot_nick ):
"Create the bot instance and connect to the IRC network and channel."
connect = reactor.connectTCP(irc_network, irc_port,
IRC_BotFactory(irc_channel,irc_network,irc_bot_nick))

20
src/irc/models.py Normal file
View file

@ -0,0 +1,20 @@
from django.db import models
from src.channels.models import CommChannel
class IRCChannelMapping(models.Model):
"""
Each IRCChannelMapping object determines which in-game channel incoming
IRC messages are routed to.
"""
channel = models.ForeignKey(CommChannel)
irc_server_name = models.CharField(max_length=78)
irc_channel_name = models.CharField(max_length=78)
is_enabled = models.BooleanField(default=True)
class Meta:
verbose_name = "IRC Channel mapping"
verbose_name_plural = "IRC Channel mappings"
def __str__(self):
return "%s <-> %s (%s)" % (self.channel, self.irc_channel_name,
self.irc_server_name)

View file

@ -154,6 +154,15 @@ class EvenniaService(service.Service):
svc.setServiceParent(self.service_collection)
imc2_events.add_events()
if settings.IRC_ENABLED:
#Connect to the IRC network.
from src.irc.connection import connect_to_IRC
connect_to_IRC(settings.IRC_NETWORK,
settings.IRC_PORT,
settings.IRC_CHANNEL,
settings.IRC_NICKNAME)
application = service.Application('Evennia')
mud_service = EvenniaService()
mud_service.start_services(application)