1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
|
#!/usr/bin/python
"""
__version__ = "$Revision: 1.34 $"
__date__ = "$Date: 2005/12/13 11:13:23 $"
"""
from PythonCard import configuration, model, sound, timer
import threading
import Queue
import ConfigParser
import wx
import os
import jabber
import time
import shutil
from chatWindow import ChatWindow
from groupChatWindow import GroupChatWindow
from connection import JabberConnection
import conferenceDialog
CONFIG_FILE = 'jabberChat.ini'
class Chat(model.Background):
def on_initialize(self, event):
self.initSizers()
self.loadConfig()
self.displayOfflineUsers = 0
self.roster = {}
self.chatWindows = {}
self.msgQueue = Queue.Queue()
self.rosterQueue = Queue.Queue()
self.jabberConnection = JabberConnection(self, self.account)
self.thread = threading.Thread(target = self.jabberConnection.spinMyWheels)
self.thread.setDaemon(1)
self.thread.start()
self.idleTimer = timer.Timer(self.components.listRoster, -1)
self.idleTimer.start(1000) # 1 second
self.doResetIdle()
# the Available and Do Not Disturb strings
# should probably be settable as resource strings
# the connection module references them as menu item labels
# when the user starts the program, just default to Available
self.statusBar.text = "Available"
def initSizers(self):
sizer1 = wx.BoxSizer(wx.VERTICAL)
sizer1.Add(self.components.listRoster, 1, wx.EXPAND)
sizer1.Fit(self)
sizer1.SetSizeHints(self)
self.panel.SetSizer(sizer1)
self.panel.SetAutoLayout(1)
self.panel.Layout()
def setChatWindowFont(self):
for win in self.chatWindows.itervalues():
win.setFonts(self.config['font'])
def on_doSetFont_command(self, event):
result = dialog.fontDialog(self, self.components.fldDocument.font)
if result.accepted:
self.config['font'] = result.font
self.setChatWindowFont()
def loadConfig(self):
self.configPath = os.path.join(configuration.homedir, 'jabberchat')
if not os.path.exists(self.configPath):
os.mkdir(self.configPath)
basePath = self.application.applicationDirectory
configPath = os.path.join(self.configPath, CONFIG_FILE)
if not os.path.exists(configPath):
shutil.copy2(os.path.join(basePath, CONFIG_FILE), configPath)
namesPath = os.path.join(self.configPath, 'names.txt')
if not os.path.exists(namesPath):
shutil.copy2(os.path.join(basePath, 'names.txt'), namesPath)
parser = ConfigParser.ConfigParser()
parser.read(configPath)
self.account = {}
self.account['server'] = parser.get('Account', 'server')
self.account['username'] = parser.get('Account', 'username')
self.account['password'] = parser.get('Account', 'password')
self.account['resource'] = parser.get('Account', 'resource')
self.config = {}
# this needs to be made safe instead of using eval
try:
self.config['font'] = eval(parser.get('ChatWindow', 'font', None))
except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
self.config['font'] = None
try:
self.config['playsound'] = eval(parser.get('Options', 'playsound'))
except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
self.config['playsound'] = 0
try:
self.config['idletime'] = eval(parser.get('Options', 'idletime')) * 60
except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
self.config['idletime'] = 0
self.displayNames = {}
try:
f = open(namesPath)
data = f.readlines()
f.close()
for line in data:
jid, name = line.rstrip().split(',')
self.displayNames[jid] = name
except IOError:
pass
# when user selects "Available"
# we need to reset
def doResetIdle(self):
self.checkForIdle = 1
self.userIsIdle = 0
self.startIdle = time.time()
self.lastPosition = wx.GetMousePosition()
def on_idle(self, event):
# handle incoming Jabber messages
if not self.msgQueue.empty():
msg = self.msgQueue.get()
self.doDisplayMsgReceived(msg)
event.RequestMore()
# handle roster changes
if not self.rosterQueue.empty():
jid, roster = self.rosterQueue.get()
if jid is None:
self.updateRosterDisplay(roster)
else:
self.updateGroupChatRosterDisplay(jid, roster)
event.RequestMore()
# KEA 2002-11-17
# updates to how the roster displays
# I would like to move this into a MultiColumnList
# with icons for online/offline...
# 2002-11-30
# moved from JabberConnection class
# I'm still not sure that thread conflicts won't occur
# but this at least seems safer
# one thing that probably still needs to be added is a way
# of always using the same display order
def updateRosterDisplay(self, roster):
items = []
# use this instead of displayed list since the
# display may have a name or jid and the roster
# itself is a dictionary that doesn't match one to one
# with self._parent.components.listRoster.items
self.displayedRosterList = []
# KEA 2003-06-04
# roster dictionary might change in size
# due to other thread, so make a list of keys
rosterList = roster.keys()
for key in rosterList:
status = roster[key][0]
show = roster[key][1]
if show:
show = " (%s)" % roster[key][1]
else:
show = ''
name = self.displayNames.get(key, key)
if status == 'online':
items.append('* ' + name + show)
self.displayedRosterList.append(key)
elif self.displayOfflineUsers:
items.append(' ' + name)
self.displayedRosterList.append(key)
self.components.listRoster.items = items
self.roster = roster
def updateGroupChatRosterDisplay(self, jid, roster):
listRoster = self.chatWindows[jid].components.listRoster
items = []
for key in roster:
status = roster[key][0]
if status:
items.append("%s (%s)" % (key, str(status)))
else:
items.append(key)
items.sort()
listRoster.items = items
def on_listRoster_timer(self, event):
# check for user idle if user is currently Available
# but don't bother if Do Not Disturb... are set instead
if self.checkForIdle and (self.config['idletime'] != 0):
position = wx.GetMousePosition()
if position == self.lastPosition:
if self.userIsIdle == 0:
# check whether we've been idle too long
if (time.time() - self.startIdle) > self.config['idletime']:
self.userIsIdle = 1
self.jabberConnection.sendPresence("Idle")
self.statusBar.text = "Idle"
#print "***user is idle***"
else:
if self.userIsIdle:
#print "***user is no longer idle"
#print "there was no activity for", round((time.time() - self.startIdle) / 60), "minutes"
self.userIsIdle = 0
self.jabberConnection.sendPresence("Available")
self.statusBar.text = "Available"
self.startIdle = time.time()
self.lastPosition = position
def createChatWindow(self, jid):
# the jid should be in the form of username@domain
win = model.childWindow(self, ChatWindow)
win.setFonts(self.config['font'])
# override resource position
#win.SetPosition((425, -1))
# just in case, convert to string, will this clear up Unicode issues?
jid = str(jid)
toName = self.displayNames.get(jid, jid)
win.setToJID(jid, toName)
win.visible = True
self.chatWindows[jid] = win
def createGroupChatWindow(self, jid, nickname=None):
# the jid should be in the form of username@domain
win = model.childWindow(self, GroupChatWindow)
win.setFonts(self.config['font'])
# override resource position
#win.SetPosition((425, -1))
# just in case, convert to string, will this clear up Unicode issues?
jid = str(jid)
toName = self.displayNames.get(jid, jid)
if nickname is None:
nickname = self.jabberConnection.username
win.nickname = nickname
win.setToJID(jid, toName)
win.visible = True
self.chatWindows[jid] = win
self.jabberConnection.joinGroupChat(jid, nickname)
def playIncomingSound(self):
if self.config['playsound']:
try:
filename = os.path.join(self.application.applicationDirectory, 'incoming.wav')
snd = sound.Sound(filename)
snd.play(1, 0)
except IOError:
pass
def doDisplayMsgReceived(self, data):
if data is not None:
jid, txt = data
jid = str(jid)
try:
jid, resource = jid.split('/')
except ValueError:
resource = "default"
if jid not in self.chatWindows:
self.createChatWindow(jid)
self.playIncomingSound()
#self.components.fldTranscript.appendText(data + '\n')
self.chatWindows[jid].appendMessage(jid + "/" + resource, txt)
else:
pass
# this code is dependent on the format
# of the text in the list
# so a change to the updateRosterDisplay
# method in the connection module must be
# reflected here until the jids are stored
# outside the list
def on_listRoster_mouseDoubleClick(self, event):
jid = self.displayedRosterList[event.target.selection]
if jid not in self.chatWindows:
self.createChatWindow(jid)
else:
self.chatWindows[jid].visible = True
# make sure the chat window is in front
# and isn't minimized (iconized)
if self.chatWindows[jid].IsIconized():
self.chatWindows[jid].Iconize(0)
wx.CallAfter(self.chatWindows[jid].Raise)
def on_close(self, event):
self.jabberConnection.keepRunning = 0
self.jabberConnection.disconnect()
self.idleTimer.stop()
event.skip()
def on_changeStatus_command(self, event):
self.jabberConnection.sendPresence(event.target.label)
self.statusBar.text = event.target.label
if event.target.label == "Available":
self.doResetIdle()
else:
self.checkForIdle = 0
def on_menuOptionsDisplayOfflineUsers_select(self, event):
self.displayOfflineUsers = event.IsChecked()
self.updateRosterDisplay(self.roster)
def on_menuFileJoinConference_select(self, event):
room = ''
server = None
nickname = self.jabberConnection.username
result = conferenceDialog.conferenceDialog(self, '', server, nickname)
if result.accepted:
room = result.room
server = result.server
nickname = result.nickname
jid = room + '@' + server
self.createGroupChatWindow(jid, nickname)
if __name__ == '__main__':
app = model.Application(Chat)
app.MainLoop()
|