Rough first version that works as component

This commit is contained in:
Travis Burtrum 2015-11-26 23:38:30 -05:00
parent c323cccdf6
commit 2198df71f5

View File

@ -60,6 +60,7 @@ class JabberThread(Thread):
def run(self): def run(self):
"""When xmpp client is connected runs the client process """ """When xmpp client is connected runs the client process """
#return
time.sleep(5) time.sleep(5)
while self.client.Process(1) and self.connected: while self.client.Process(1) and self.connected:
pass pass
@ -68,7 +69,7 @@ class JabberThread(Thread):
class ClientThread(Thread): class ClientThread(Thread):
""" ClientThread class for handling IRC and Jabber connections.""" """ ClientThread class for handling IRC and Jabber connections."""
def __init__(self,socket, port, server, muc_server): def __init__(self,socket, port, server, muc_server, client, main_logger):
"""Constructor for ClientThread class """Constructor for ClientThread class
@type socket: socket @type socket: socket
@ -78,11 +79,12 @@ class ClientThread(Thread):
@param port: port of the connection @param port: port of the connection
""" """
Thread.__init__(self) Thread.__init__(self)
self.client = client
self.socket = socket self.socket = socket
self.port = port self.port = port
self.server = server self.server = server
self.muc_server = muc_server self.muc_server = muc_server
self.client = None #self.client = None
self.JID = None self.JID = None
self.passwd= None self.passwd= None
@ -91,13 +93,9 @@ class ClientThread(Thread):
self.newnick = '' self.newnick = ''
self.mucs = {} self.mucs = {}
self.mucs['roster'] = {}
self.joinedRoster = False
self.connected = True self.connected = True
self.JIDtoUID = {}
self.UIDtoJID = {} self.UIDtoJID = {}
self.nickChangeInMucs = {} self.nickChangeInMucs = {}
@ -110,8 +108,11 @@ class ClientThread(Thread):
self.xmppSem = BoundedSemaphore(value=1) self.xmppSem = BoundedSemaphore(value=1)
self.logger = logging.getLogger("logger") #self.logger = logging.getLogger("logger")
self.logger.addHandler(logging.handlers.SysLogHandler(address = '/var/run/log')) #self.logger.addHandler(logging.handlers.SysLogHandler(address = '/var/run/log'))
#self.logger.addHandler(logging.StreamHandler())
#self.logger.setLevel(10)
self.logger = main_logger
self.startup_time = datetime.datetime.now().strftime("%c") self.startup_time = datetime.datetime.now().strftime("%c")
@ -137,9 +138,7 @@ class ClientThread(Thread):
@rtype: list @rtype: list
@return: list of mucs joined (without roster) @return: list of mucs joined (without roster)
""" """
mucs = self.mucs.keys() return self.mucs
mucs.remove('roster')
return mucs
def fixNick(self, nick): def fixNick(self, nick):
"""Fixes strange character nicknames that don't work nicely with """Fixes strange character nicknames that don't work nicely with
@ -190,18 +189,12 @@ class ClientThread(Thread):
else: else:
jid_string = unicode(jid) jid_string = unicode(jid)
uid = 0
if self.JIDtoUID.has_key(jid_string):
uid = self.JIDtoUID[jid_string]
else:
uid = len(self.JIDtoUID)
self.JIDtoUID[jid_string] = uid
self.UIDtoJID[uid] = JID(jid_string)
if not is_muc_jid: if not is_muc_jid:
nick = "%s|%s" % (self.fixNick(jid.getNode()), uid) nick = self.fixNick(jid.getNode())
else: else:
nick = "%s|%s" % (self.fixNick(jid.getResource()), uid) nick = self.fixNick(jid.getResource())
self.UIDtoJID[nick] = JID(jid_string)
return nick return nick
@ -214,11 +207,8 @@ class ClientThread(Thread):
@return: JID corresponding to nick @return: JID corresponding to nick
""" """
split_nick = nick.rsplit('|', 1) if self.UIDtoJID.has_key(nick):
if len(split_nick) == 2: return self.UIDtoJID[nick]
uid = int(split_nick[1])
if self.UIDtoJID.has_key(uid):
return self.UIDtoJID[uid]
if nick.find('@') != -1: if nick.find('@') != -1:
return JID(nick) return JID(nick)
@ -257,6 +247,7 @@ class ClientThread(Thread):
@param msg: message to send @param msg: message to send
""" """
self.xmppSem.acquire() self.xmppSem.acquire()
msg.setFrom(self.JID)
self.client.send(msg) self.client.send(msg)
self.xmppSem.release() self.xmppSem.release()
@ -363,98 +354,6 @@ class ClientThread(Thread):
self.makeNickFromJID(new_jid, True)) self.makeNickFromJID(new_jid, True))
self.sendToIRC(msg) self.sendToIRC(msg)
def ircCommandROSTERPART(self):
"""Part roster channel"""
self.joinedRoster = False
msg = ':%s!%s PART #roster : ' % (self.nickname, self.makeHostFromJID(self.JID))
self.sendToIRC(msg)
def ircCommandROSTERPRIVMSGMUC(self, msg):
"""Handles messages in roster channel. For example if user types HELP
in roster channel (s)he gets list of available commands
@type msg: string
@param msg: message to roster channel
"""
if msg.upper().startswith('HELP'):
msg = ':%s PRIVMSG #%s :%s' % \
('Telepaatti',
'roster',
'Awailable commands !subscribe, !unsubscribe, !subscribed, !unsubscribed')
self.sendToIRC(msg)
elif msg.startswith('!'):
msglist = msg[1:].split()
msglist[0] = msglist[0].upper()
if len(msglist) == 2:
if msglist[0] == 'SUBSCRIBE':
self.xmppCommandSUBSCRIBE(msglist[1])
elif msglist[0] == 'UNSUBSCRIBE':
self.xmppCommandUNSUBSCRIBE(msglist[1])
elif msglist[0] == 'SUBSCRIBED':
self.xmppCommandSUBSCRIBED(msglist[1])
elif msglist[0] == 'UNSUBSCRIBED':
self.xmppCommandUNSUBSCRIBED(msglist[1])
return
def ircCommandROSTERSELFJOIN(self):
"""Join roster channel. This handles cases when user self joins to
roster channel"""
snick = self.nickname
lines = list()
room = 'roster'
lines.append(':%s JOIN :#%s'% (snick, room))
lines.append(':%s 332 %s #%s :Roster Channel. Telepaatti is tracking here your roster changes. Type Help for help!' %
(self.server, snick, room))
lines.append(':%s 333 %s #%s telepaatti 000000001' % (self.server, snick, room))
lines.append(':%s MODE #%s +n' % (self.server, room))
lines.append(':%s 353 %s = #%s :%s' % (self.server, snick, room, snick))
for jid in self.mucs[room].iterkeys():
nick = self.makeNickFromJID(jid, False)
if not (jid.getResource() == self.nickname):
lines.append(':%s 353 %s = #%s :%s' % (self.server, snick, room, nick))
lines.append(':%s 366 %s #%s :End of /NAMES list.'% (self.server, snick, room))
while lines:
msg = lines.pop(0)
self.sendToIRC(msg)
self.joinedRoster = True
def ircCommandROSTERMSG(self, pres):
"""Roster channel messages. Here is traced roster users statas
@type pres: Presence
@param pres: Presence of the roster user
"""
jid = pres.getFrom()
nick = self.makeNickFromJID(jid, False)
message = ''
dt = "%s" % datetime.datetime.now()
dt = dt[:-7]
if jid != self.JID and pres.getType() == 'unavailable': # left
if self.mucs['roster'].has_key(jid):
message = ':%s!%s PART #roster :[%s] Offline' % (nick,self.makeHostFromJID(jid),dt)
try: # remove
del (self.mucs['roster'][jid])
except:
self.printError('Tried to remove nickname %s from #roster' % jid)
elif jid != str(self.JID) and not self.mucs['roster'].has_key(jid):
message = ':%s!%s JOIN :#roster' % (nick, self.makeHostFromJID(jid))
self.mucs['roster'][jid] = { 'role': 'participant',
'affiliation': 'member'}
else:
action = self.makeIRCACTION('[%s] %s - %s' % (
dt,
pres.getShow(),
pres.getStatus()))
message = ':%s!%s PRIVMSG #roster :%s' % (
nick,
self.makeHostFromJID(jid),
action)
if self.joinedRoster and message != '':
self.sendToIRC(message)
def ircCommandPRIVMSG(self, jid, is_muc, is_private, text, timestamp=''): def ircCommandPRIVMSG(self, jid, is_muc, is_private, text, timestamp=''):
"""Converts private messages to IRC client """Converts private messages to IRC client
@ -687,85 +586,12 @@ class ClientThread(Thread):
msg = 'NOTICE %s :%s' % (nick, text) msg = 'NOTICE %s :%s' % (nick, text)
self.sendToIRC(msg) self.sendToIRC(msg)
def ircCommandSUBSCRIBE(self, pres):
"""Convert XMPP subscribe message to IRC message
@type pres: presence
@param pres: presence of which to subscribe
"""
text = "is making subsciption request to you with message: \"%s\" You MUST either approve the request or refuse the request. You can approve it by joinin #roster channel andthen type \"!subscribed %s\" if you wish to subscibe to contact or \"!unsubscribed %s\" if you wish not to subscibe to contact" % (pres.getStatus(), pres.getFrom(), pres.getFrom())
text = self.makeIRCACTION(text)
self.printDebug(str(pres))
self.ircCommandPRIVMSG(pres.getFrom(), False, True, text)
def ircCommandUNSUBSCRIBE(self, pres):
"""Convert XMPP unsubscribe message to IRC message. Unfinished.
@type pres: presence
@param pres: presence of which to unsubscribe
"""
self.printDebug(str(pres))
def ircCommandSUBSCRIBED(self, pres):
"""Convert XMPP subscribed message to IRC message. Unfinished.
@type pres: presence
@param pres: presence of which to subscribed
"""
self.printDebug(str(pres))
def ircCommandUNSUBSCRIBED(self, pres):
"""Convert XMPP unsubscribed message to IRC message. Unfinished.
@type pres: presence
@param pres: presence of which to unsubscribed
"""
self.printDebug(str(pres))
def xmppCommandSUBSCRIBE(self, jid):
"""Send XMPP subscribe message.
@type jid: string
@param jid: Jabber ID to subscribe
"""
self.sendToXMPP(Presence(to='%s' % jid,
typ = 'subscribe'))
def xmppCommandUNSUBSCRIBE(self, jid):
"""Send XMPP unsubscribe message.
@type jid: string
@param jid: Jabber ID to unsubscribe
"""
self.sendToXMPP(Presence(to='%s' % jid,
typ = 'unsubscribe'))
def xmppCommandSUBSCRIBED(self, jid):
"""Send XMPP subscribed message.
@type jid: string
@param jid: Jabber ID to subscribed
"""
self.sendToXMPP(Presence(to='%s' % jid,
typ = 'subscribed'))
def xmppCommandUNSUBSCRIBED(self, jid):
"""Send XMPP unsubscribed message.
@type jid: string
@param jid: Jabber ID to unsubscribed
"""
self.sendToXMPP(Presence(to='%s' % jid,
typ = 'unsubscribed'))
def xmppCommandMUCMODE(self, jid): def xmppCommandMUCMODE(self, jid):
"""Send XMPP MUC mode change """Send XMPP MUC mode change
@type jid: string @type jid: string
@param jid: Jabber id of the MUC @param jid: Jabber id of the MUC
""" """
if jid == 'roster': # no query for roster
return
iq = protocol.Iq(to=jid, iq = protocol.Iq(to=jid,
queryNS=NS_DISCO_INFO, queryNS=NS_DISCO_INFO,
typ = 'get') typ = 'get')
@ -778,9 +604,7 @@ class ClientThread(Thread):
@type jid: string @type jid: string
@param jid: Jabber id of the MUC @param jid: Jabber id of the MUC
""" """
if jid == 'roster': # no query for roster iq = protocol.Iq(frm=self.JID,
return
iq = protocol.Iq(frm=unicode(self.JID),
to=jid, to=jid,
queryNS=NS_DISCO_ITEMS, queryNS=NS_DISCO_ITEMS,
typ = 'get') typ = 'get')
@ -796,7 +620,6 @@ class ClientThread(Thread):
@param status: status @param status: status
""" """
for muc in self.mucs.keys(): for muc in self.mucs.keys():
if muc != 'roster':
p=Presence(to='%s/%s' % ( p=Presence(to='%s/%s' % (
muc, muc,
self.nickname)) self.nickname))
@ -864,6 +687,7 @@ class ClientThread(Thread):
self.sendToXMPP(iq) self.sendToXMPP(iq)
# software version # software version
# todo: looks at roster which doesn't exist, fix this
if not jid.getResource(): if not jid.getResource():
# try to find match in roster # try to find match in roster
rosternicks = self.mucs['roster'].keys() rosternicks = self.mucs['roster'].keys()
@ -890,7 +714,7 @@ class ClientThread(Thread):
pass pass
def run(self): def run(self):
while self.connected and self.client is None: while self.connected and self.nickname is None:
try: try:
data = self.socket.recv(4096) data = self.socket.recv(4096)
except: except:
@ -899,30 +723,6 @@ class ClientThread(Thread):
if data: if data:
for line in data.splitlines(): for line in data.splitlines():
self.commandHandler(line) self.commandHandler(line)
if (self.JID is not None and self.passwd is not None):
client=Client(self.JID.getDomain(),debug=[])
client.connect(proxy={})
client.RegisterHandler('message',self.messageHandler)
client.RegisterHandler('presence',self.presenceHandler)
client.RegisterHandler('iq' ,self.iqHandler)
self.printDebug("Logging in as %s, with password %s" % (self.JID, self.passwd))
if not client.auth(self.JID.getNode(), self.passwd, self.JID.getResource()):
self.ircCommandERROR('', 464)
try:
self.socket.shutdown(socket.SHUT_RDWR)
except socket.error:
self.printError('Socket shutdown client')
self.socket.close()
return
client.sendInitPresence()
self.client = client
else: else:
self.connected = False self.connected = False
@ -952,8 +752,6 @@ class ClientThread(Thread):
jt = JabberThread(self.client) jt = JabberThread(self.client)
jt.start() jt.start()
self.ircCommandROSTERSELFJOIN()
while self.connected and jt.connected: while self.connected and jt.connected:
try: try:
data = self.socket.recv(4096) data = self.socket.recv(4096)
@ -965,7 +763,6 @@ class ClientThread(Thread):
if self.pingCounter == 5: if self.pingCounter == 5:
self.pingCounter = 0 self.pingCounter = 0
for muc in self.mucs.keys(): for muc in self.mucs.keys():
if muc != 'roster':
if self.disconnectedMucs.has_key(muc): if self.disconnectedMucs.has_key(muc):
if self.disconnectedMucs[muc] < 5: if self.disconnectedMucs[muc] < 5:
self.disconnectedMucs[muc] = self.disconnectedMucs[muc] + 1 self.disconnectedMucs[muc] = self.disconnectedMucs[muc] + 1
@ -1321,6 +1118,11 @@ class ClientThread(Thread):
if ns.startswith(NS_MUC): if ns.startswith(NS_MUC):
MUC = True MUC = True
# todo: remove all the non-muc code
if not MUC:
self.printDebug('non-muc presence somehow? investigate...')
return
role = pres.getRole() role = pres.getRole()
affiliation = pres.getAffiliation() affiliation = pres.getAffiliation()
show = pres.getShow() show = pres.getShow()
@ -1329,8 +1131,7 @@ class ClientThread(Thread):
room = JID(pres.getFrom().getStripped()) room = JID(pres.getFrom().getStripped())
# for affiliation and role changes # for affiliation and role changes
if MUC and \ if self.mucs.has_key(room) and \
self.mucs.has_key(room) and \
nick in self.mucs[room].keys(): nick in self.mucs[room].keys():
xrole = self.mucs[room][nick]['role'] xrole = self.mucs[room][nick]['role']
xaffiliation = self.mucs[room][nick]['affiliation'] xaffiliation = self.mucs[room][nick]['affiliation']
@ -1390,44 +1191,6 @@ class ClientThread(Thread):
self.newnick = '' self.newnick = ''
return return
if not MUC and ptype == 'error':
erc = pres.getErrorCode()
if erc == '409' and self.mucs.has_key(nick.getStripped()):
self.nickChangeInMucs[room] = {'checked': True,
'changed': False}
# all must have come
self.printDebug(str(self.nickChangeInMucs))
for muc in self.nickChangeInMucs.keys():
if not self.nickChangeInMucs[muc]['checked']:
return
changedMucs = list()
for gei in self.nickChangeInMucs.keys():
if self.nickChangeInMucs[gei]['changed']:
changedMucs.append(gei)
self.nickChangeInMucs = {}
for muc2 in changedMucs:
self.nickChangeInMucs[muc2] = {'checked': False,
'changed': False}
self.xmppCommandMUCPRESENCE(muc2, self.nickname)
self.ircCommandERROR('Nick conflicts in some MUC wont change')
else:
self.ircCommandERROR('Got some error %s' % unicode(pres))
return
if not MUC: # normal presence
if ptype in ['subscribe']:
self.ircCommandSUBSCRIBE(pres)
elif ptype in ['unsubscribe']:
self.ircCommandUNSUBSCRIBE(pres)
elif ptype in ['subscribed']:
self.ircCommandSUBSCRIBED(pres)
elif ptype in ['unsubscribed']:
self.ircCommandUNSUBSCRIBED(pres)
else:
self.ircCommandROSTERMSG(pres)
elif MUC:
if ptype == 'error': if ptype == 'error':
er = pres.getError() er = pres.getError()
erc = pres.getErrorCode() erc = pres.getErrorCode()
@ -1550,14 +1313,25 @@ class ClientThread(Thread):
if (MUC): if (MUC):
arguments = arguments[1:] arguments = arguments[1:]
if self.client is None : if self.JID is None:
if command == 'NICK': if command == 'NICK':
nick = '' nick = ''
if arguments[0] == ':': if arguments[0] == ':':
nick = arguments[1:] nick = arguments[1:]
else: else:
nick = arguments nick = arguments
self.JID = JID("%s@%s/%s" %(nick, self.server, 'telepaatti')) bare_jid = "%s@%s" %(nick, self.server)
full_jid = "%s@%s/%s" %(nick, self.server, 'telepaatti')
self.JID = JID(full_jid)
# todo: handle changing jids
self.printDebug("adding jid to clients: (full: %s) (bare: %s)" % (full_jid, bare_jid))
clients[full_jid] = self
clients[bare_jid] = self
#self.client.RegisterHandler('message',self.messageHandler)
#self.client.RegisterHandler('presence',self.presenceHandler)
#self.client.RegisterHandler('iq',self.iqHandler)
self.nickname = self.fixNick(nick) self.nickname = self.fixNick(nick)
elif command == 'PASS': elif command == 'PASS':
@ -1576,11 +1350,6 @@ class ClientThread(Thread):
if len(arguments) == 2: if len(arguments) == 2:
password = arguments[1] password = arguments[1]
if room == 'roster':
if self.joinedRoster: # already in #roster
return
self.ircCommandROSTERSELFJOIN()
else:
if room.find('@') < 1: if room.find('@') < 1:
self.printDebug("Joining a room without full jid") self.printDebug("Joining a room without full jid")
if (self.muc_server is None): if (self.muc_server is None):
@ -1600,7 +1369,6 @@ class ClientThread(Thread):
p.getTag('x').addChild('history',{'maxchars':'10000','maxstanzas':'100'}) p.getTag('x').addChild('history',{'maxchars':'10000','maxstanzas':'100'})
self.sendToXMPP(p) self.sendToXMPP(p)
elif command == 'PART': elif command == 'PART':
x = arguments.find(' :') x = arguments.find(' :')
text = '' text = ''
@ -1612,11 +1380,6 @@ class ClientThread(Thread):
room = JID(room.strip()) room = JID(room.strip())
else: else:
room = JID(arguments.strip()) room = JID(arguments.strip())
if room == 'roster':
if not self.joinedRoster: # not in roster
return
self.ircCommandROSTERPART()
else:
if room not in self.mucs.keys(): # not in room if room not in self.mucs.keys(): # not in room
return return
self.sendToXMPP(Presence(to='%s/%s' % (room, self.newnick), self.sendToXMPP(Presence(to='%s/%s' % (room, self.newnick),
@ -1640,10 +1403,6 @@ class ClientThread(Thread):
if MUC: if MUC:
type = 'groupchat' type = 'groupchat'
if nick == 'roster':
self.ircCommandROSTERPRIVMSGMUC(text)
return
jid = self.getJIDFromNick(nick) jid = self.getJIDFromNick(nick)
if jid is None: if jid is None:
return return
@ -1686,9 +1445,6 @@ class ClientThread(Thread):
if jid not in self.mucs.keys(): if jid not in self.mucs.keys():
self.ircCommandERROR('', 403) self.ircCommandERROR('', 403)
return return
if jid == 'roster':
self.ircCommandERRORMUC(482, 'TOPIC ON ROSTER CANNOT BE CHANGED', jid)
return
self.sendToXMPP(protocol.Message(jid, self.sendToXMPP(protocol.Message(jid,
typ = 'groupchat', typ = 'groupchat',
@ -1700,8 +1456,6 @@ class ClientThread(Thread):
arguments = arguments.split(' ', 2) arguments = arguments.split(' ', 2)
params = '' params = ''
nick = arguments[0] nick = arguments[0]
if nick == 'roster':
return
if len(arguments) >= 2: if len(arguments) >= 2:
params = arguments[1] params = arguments[1]
@ -1815,14 +1569,56 @@ def main():
else: else:
daemon_main(server, port, muc_server, nickname, ssl_cert, dh_param) daemon_main(server, port, muc_server, nickname, ssl_cert, dh_param)
main_logger = logging.getLogger("main_logger")
clients = {}
def messageHandler(sess, mess):
print "in messageHandler"
main_logger.info("in messageHandler")
try:
jid = mess.getTo()
main_logger.info("jid %s" % (jid))
main_logger.info("clients %s" % (clients))
clients[jid].messageHandler(sess, mess)
except:
main_logger.error("Unexpected error: %s" % sys.exc_info()[0])
pass
def presenceHandler(sess, mess):
print "in presenceHandler"
main_logger.info("in presenceHandler")
try:
jid = mess.getTo()
main_logger.info("jid %s" % (jid))
main_logger.info("clients %s" % (clients))
clients[jid].presenceHandler(sess, mess)
except:
main_logger.error("Unexpected error: %s" % sys.exc_info()[0])
pass
def iqHandler(sess, mess):
print "in iqHandler"
main_logger.info("in iqHandler")
try:
jid = mess.getTo()
main_logger.info("jid %s" % (jid))
main_logger.info("clients %s" % (clients))
clients[jid].iqHandler(sess, mess)
except:
main_logger.error("Unexpected error: %s" % sys.exc_info()[0])
pass
def daemon_main(server, port, muc_server, nickname, ssl_cert, dh_param): def daemon_main(server, port, muc_server, nickname, ssl_cert, dh_param):
service = socket.socket(socket.AF_INET, socket.SOCK_STREAM) service = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
service.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) service.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
service.bind(("", port)) service.bind(("", port))
service.listen(1) service.listen(1)
main_logger = logging.getLogger("main_logger"); #main_logger = logging.getLogger("main_logger")
main_logger.addHandler(logging.handlers.SysLogHandler(address = '/var/run/log')) #main_logger.addHandler(logging.handlers.SysLogHandler(address = '/var/run/log'))
main_logger.addHandler(logging.StreamHandler())
main_logger.setLevel(10)
main_logger.info("listening on port %s" % (port)) main_logger.info("listening on port %s" % (port))
@ -1836,7 +1632,17 @@ def daemon_main(server, port, muc_server, nickname, ssl_cert, dh_param):
ssl_ctx.load_dh_params(dh_param) ssl_ctx.load_dh_params(dh_param)
ssl_ctx.load_cert_chain(ssl_cert) ssl_ctx.load_cert_chain(ssl_cert)
client = Component('irc.moparisthebest.com', 5347)
#client.connect(proxy={})
client.connect(('192.168.1.3', 5347))
client.RegisterHandler('message',messageHandler)
client.RegisterHandler('presence',presenceHandler)
client.RegisterHandler('iq',iqHandler)
if not client.auth('irc.moparisthebest.com', 'irc'):
main_logger.error('auth failed')
return
while (True): while (True):
(clientsocket, address ) = service.accept() (clientsocket, address ) = service.accept()
@ -1851,7 +1657,7 @@ def daemon_main(server, port, muc_server, nickname, ssl_cert, dh_param):
main_logger.error('Failed socket shutdown') main_logger.error('Failed socket shutdown')
clientsocket.close() clientsocket.close()
continue continue
ct = ClientThread(clientsocket, port, server, muc_server) ct = ClientThread(clientsocket, port, server, muc_server, client, main_logger)
ct.start() ct.start()
if __name__ == "__main__": if __name__ == "__main__":