# -*- coding: utf-8 -*-
# This file is part of emesene.
#
# Emesene is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# emesene is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with emesene; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import common
import os
import hashlib
class Contact(object):
'''class describing a contact'''
def __init__(self, email, id='', nick='', personalMessage='', alias='', \
status='FLN', mobile=False, blocked=False, space=False, allow=False, \
reverse=False, pending=False, groups=None, dummy=False, clientid=0):
'''Constructor'''
self.email = email.lower()
self.id = id
self.nick = nick
self.personalMessage = personalMessage
self.alias = alias
self.status = status
self.mobile = mobile
self.space = space
self.dummy = dummy
self.clientid = clientid
if groups:
self.groups = groups # for performance
else:
self.groups = []
self.allow = allow
self.blocked = blocked
self.reverse = reverse
self.pending = pending
self.locked = False
self.msnobj = None
self._dpPath = ''
self.cid = 0
def __repr__(self):
return self.email + ': ' + self.id + ' ' + self.nick + '\n'\
+ str(self.groups)
def _getEmail(self):
return self._email
def _setEmail(self, value):
self._email = value.lower()
email = property(_getEmail, _setEmail, None)
def _getPath(self):
if self._dpPath:
return self._dpPath
elif self.msnobj is None:
return ''
sha1d = hashlib.sha1(self.msnobj.sha1d).hexdigest()
return self.email.split('@')[0] + "_" + sha1d
def _setPath(self, value):
self._dpPath = value
displayPicturePath = property(_getPath, _setPath, None)
def addGroup(self, id):
if not id in self.groups:
self.groups.append(id)
def removeGroup(self, id):
id = str(id)
if id in self.groups:
self.groups.remove(id)
else:
common.debug('Group %s not found' % id)
def shares_webcam(self):
return ((self.clientid & 0x10) == 0x10)
def getMSNC(self):
return ((self.clientid & 0xf0000000) >> 28)
class Group(object):
'''class representing a group'''
def __init__(self, name, id = ''):
'''Contructor,
users is a dict with an email as key and a contact object as value'''
self.name = name
self.id = id
# { email: contact }
self.users = {}
def getUsersByStatus(self, status):
'''Returns a list user users according to its status'''
return [i for i in self.users.values() if \
i.status == common.status_table[status]]
def getUser(self, email):
email = email.lower()
if self.users.has_key(email):
return self.users[email]
else:
None
def setUser(self, email, contactObject):
email = email.lower()
self.users[email] = contactObject
def removeUser(self, email):
email = email.lower()
# if self.users.has_key(email):
del self.users[email]
def getSize(self):
'''returns how many users the group has'''
return len(self.users)
def getOnlineUsersNumber(self):
'''Returns the number of online users (not offline) in the group'''
offline = self.getUsersByStatus('offline')
return self.getSize() - len(offline)
class ContactList(object):
'''a class that contains groups that contains users'''
def __init__(self, groups=None):
'''Constructor,
groups is a dict with the name as key and a Group object as value'''
self.groups = {}
self.reverseGroups = {}
self.noGroup = Group('No group', 'nogroup')
self.contacts = {}
if groups:
self.setGroups(groups)
self.lists = {}
self.lists['Allow'] = []
self.lists['Block'] = []
self.lists['Reverse'] = []
self.lists['Pending'] = []
self.pendingNicks = {}
def getGroupNames(self):
'''Returns a list with the groups' names in the contact list'''
return self.reverseGroups.keys()
def setGroups(self, groupDict):
'''set the dict'''
self.groups = groupDict.copy()
self.reverseGroups = {}
for i in self.groups.keys():
self.reverseGroups[self.groups[i].name] = self.groups[i]
def addGroup(self, name, gid):
group = Group(name, gid)
self.setGroup(gid, group)
def getGroup(self, id):
if self.groups.has_key(id):
return self.groups[id]
else:
common.debug('group not found, returning dummy group')
return Group(id, 'dummy' + id)
def setGroup(self, id, groupObject):
self.groups[id] = groupObject
self.reverseGroups[groupObject.name] = self.groups[id]
# update contained contacts
for contact in groupObject.users.copy():
self.addUserToGroup(contact, id)
def removeGroup(self, group):
if self.groups.has_key(group):
# update contained contacts
for contact in self.groups[group].users.copy():
self.removeUserFromGroup(contact, group)
name = self.groups[group].name
# remove the group
del self.groups[group]
del self.reverseGroups[name]
def renameGroup(self, id, newName):
if self.groups.has_key(id):
del self.reverseGroups[self.groups[id].name]
self.groups[id].name = newName
self.reverseGroups[newName] = self.groups[id]
def getGroupId(self, name):
if self.reverseGroups.has_key(name):
return self.reverseGroups[name].id
elif name == 'No group':
return 'nogroup'
else:
return None
def getGroupName(self, id):
if id in self.groups:
return self.groups[id].name
elif id == 'nogroup':
return 'No group'
else:
return 'dummy' + str(id)
def addContact(self, contact):
self.contacts[contact.email] = contact
for id in contact.groups:
if self.groups.has_key(id):
self.groups[id].setUser(contact.email, contact)
if contact.groups == []:
self.noGroup.setUser(contact.email, contact)
def addNewContact(self, email, groups=None):
email = email.lower()
if email in self.lists['Block']:
contact = Contact(email, blocked=True)
else:
contact = Contact(email, allow=True)
self.addContact(contact)
def setContactIdXml(self, email, xml):
'''Sets a contact's id from theaddusersoapresponsexml import
email = str(email).lower()
if email in self.contacts:
guid = xml.split('<guid>')[1].split('</guid>')[0]
self.contacts[email].id = guid
else:
common.debug('Contact %s not in list' % email)
def getContact(self, email):
email = email.lower()
if self.contacts.has_key(email):
return self.contacts[email]
else:
common.debug('user %s not found, returning dummy user' % (email,))
return self.getDummyContact(email)
def getDummyContact(self, email):
'''build a dummy contact with some data to be allowed to show data about
contacts that we dont have i.e when someone add in a group chat someone that we dont have.'''
email = email.lower()
return Contact(email, '', email, '', '', 'NLN', False, False, False,
True, True, False, dummy=True, clientid=0)
def contact_exists(self, email): # breaking name conventions wdeaah
return self.contacts.has_key(email.lower())
def getContactStatus(self, email):
email = email.lower()
if self.contacts.has_key(email):
return self.contacts[email].status
else:
return 'FLN'
def setContactStatus(self, email, status):
email = email.lower()
if self.contacts.has_key(email):
self.contacts[email].status = status
def getContactHasSpace(self, email):
email = email.lower()
if self.contacts.has_key(email):
return self.contacts[email].space
else:
return False
def getContactHasMobile(self, email):
email = email.lower()
if self.contacts.has_key(email):
return self.contacts[email].mobile
else:
return False
def getContactIsBlocked(self, email):
email = email.lower()
if self.contacts.has_key(email):
return self.contacts[email].blocked
else:
return False
def setContactIsBlocked(self, email, value):
email = email.lower()
if self.contacts.has_key(email):
self.contacts[email].blocked = value
else:
pass
def getContactIsAllowed(self, email):
email = email.lower()
if self.contacts.has_key(email):
return self.contacts[email].allow
else:
return True
def setContactIsAllowed(self, email, value):
email = email.lower()
if self.contacts.has_key(email):
self.contacts[email].allow = value
def getContactNick(self, email, escaped=False):
email = email.lower()
if self.contacts.has_key(email):
nick = self.contacts[email].nick
elif self.pendingNicks.has_key(email):
nick = self.pendingNicks[email]
else:
nick = email
if escaped:
return common.escape(nick)
else:
return nick
def setContactNick(self, email, value):
email = email.lower()
if self.contacts.has_key(email):
self.contacts[email].nick = value
def getContactPersonalMessage(self, email, escaped=False):
email = email.lower()
if self.contacts.has_key(email):
if escaped:
return common.escape(self.contacts[email].personalMessage)
else:
return self.contacts[email].personalMessage
def setContactPersonalMessage(self, email, value):
email = email.lower()
if self.contacts.has_key(email):
self.contacts[email].personalMessage = value
def getContactAlias(self, email, escaped=False):
email = email.lower()
if self.contacts.has_key(email):
if escaped:
return common.escape(self.contacts[email].alias)
else:
return self.contacts[email].alias
else:
return ''
def setContactAlias(self, email, value):
email = email.lower()
if self.contacts.has_key(email):
self.contacts[email].alias = value
def getContactNameToDisplay(self, email):
email = email.lower()
displayName = self.getContactAlias(email, True)
if displayName == '':
displayName = self.getContactNick(email, True)
return displayName
def getContactId(self, email):
email = email.lower()
if self.contacts.has_key(email):
return self.contacts[email].id
else:
return ''
def getContactGroupIds(self, email):
'''return a list with the group ids or an empty list'''
email = email.lower()
if self.contacts.has_key(email) and len(self.contacts[email].groups) > 0:
return self.contacts[email].groups
return []
def unblockContact(self, email):
email = email.lower()
if self.contacts.has_key(email):
self.contacts[email].blocked = False
self.contacts[email].allow = True
if email in self.lists['Block']:
self.lists['Block'].remove(email)
self.lists['Allow'].append(email)
def blockContact(self, email):
email = email.lower()
if self.contacts.has_key(email):
self.contacts[email].blocked = True
self.contacts[email].allow = False
if email in self.lists['Allow']:
self.lists['Allow'].remove(email)
self.lists['Block'].append(email)
def removeUserFromGroup(self, user, group):
user = str(user).lower()
group = str(group)
if self.groups.has_key(group):
contact = self.groups[group].getUser(user)
if contact != None:
# remove group from user's list of belongings
contact.removeGroup(group)
# add the contact to no group if applicable
if contact.groups == []:
self.noGroup.setUser(user, contact)
# remove user from group
self.groups[group].removeUser(user)
else:
common.debug('Contact %s not in group %s' % (user, group))
else:
common.debug('Group %s not found' % group)
def removeContact(self, contactMail):
contactMail = str(contactMail).lower()
if self.contacts.has_key(contactMail):
# remove user from groups to which he belongs
contact = self.contacts[contactMail]
for group in contact.groups:
self.groups[group].removeUser(contactMail)
# remove user from the no group, if applicable
if len(contact.groups) == 0:
self.noGroup.removeUser(contactMail)
# remove user
del self.contacts[contactMail]
else:
common.debug('Contact %s not in list' % contactMail)
def addUserToGroup(self, user, group):
user = str(user).lower()
group = str(group)
if self.groups.has_key(group) and self.contacts.has_key(user):
contact = self.contacts[user]
# remove from nogroup if applicable
if len(contact.groups) == 0:
self.noGroup.removeUser(user)
groupObj = self.groups[group]
contact.addGroup(group)
groupObj.setUser(user, contact)
elif not self.contacts.has_key(user):
common.debug('Contact %s not in list' % user)
elif group not in self.groups:
common.debug('Group %s not found' % group)
def updateMemberships(self):
'''Updates contact membership info according to self.lists'''
for email in self.contacts:
self.contacts[email.lower()].reverse = (email in self.lists['Reverse'])
self.contacts[email.lower()].allow = (email in self.lists['Allow'])
self.contacts[email.lower()].blocked = (email in self.lists['Block'])
def getADL(self):
'''Create a XML String with all the contacts we have for
the initial ADL Command'''
contacts = {}
for user in self.contacts.keys():
l = 0
if self.getContact(user).allow:
l = 3
if self.getContact(user).blocked:
l = 5
contacts[user] = l
for user in self.lists['Allow']:
if len(contacts) >= 150:
break
if user not in contacts:
contacts[user] = 2
return self.buildDL(contacts, initial=True)
def buildDL(self, contacts, initial=False):
'''return a list of XML for the DL command, is a list because each DL
should be less than 7500 bytes
contacts is a dict {user: type}'''
domains = {}
for i in contacts.keys():
(user, domain) = i.split('@')
if domains.has_key(domain):
domains[domain].append(user)
else:
domains[domain] = [user]
xmlDomains = []
for i in domains.keys():
users = ''
for j in domains[i]:
l = contacts[j + '@' + i]
if l > 0:
users += '<c n="' + j + '" l="' + str(l) + '" t="1" />'
if len(users) + len('<d n="' + i + '"></d>') > 7200:
xmlDomains.append('<d n="' + i + '">' + users + '</d>')
users = ''
if len(users) > 0:
xmlDomains.append('<d n="' + i + '">' + users + '</d>')
adls = []
full = False
while xmlDomains:
if initial:
xml = '<ml l="1">'
else:
xml = '<ml>'
for i in range(len(xmlDomains)):
domain = xmlDomains.pop()
# TODO: consider domains > 7500
# here that's an infinite loop
if len(xml) + len(domain) < 7400:
xml += domain
else:
xml += '</ml>'
adls.append(xml)
xmlDomains.append(domain)
full = True
break
if not full:
xml += '</ml>'
adls.append(xml)
else:
full = False
return adls
def getOnlineUsers(self):
'''return a list of online users'''
ret = []
for i in self.contacts.keys():
if self.getContactStatus(i) != 'FLN':
ret.append([i, self.getContactStatus(i)])
return ret
def getOnlineUsersDict(self):
dictionary = {}
for i in self.contacts.keys():
if self.getContactStatus(i) != 'FLN':
dictionary[i] = self.getContact(i)
return dictionary
def getOnOffUsersRelationByGroup(self, groupName):
#return a 2 tuple containing the relation of users online and offline
groupSizeStr = ''
groupObject = None
if groupName == 'No group':
groupObject = self.noGroup
else:
try:
groupObject = self.reverseGroups[groupName]
except KeyError:
common.debug('Group %s not found' % groupName)
if groupObject != None:
groupSize = groupObject.getSize()
usersOnline = groupObject.getOnlineUsersNumber()
return usersOnline, groupSize
def getContactList(self, showOffline = True, showEmptyGroups = False, \
orderByStatus = False):
'''return a dictionarie with the contact list sorted acording the parameters'''
cl = {}
if orderByStatus:
cl['offline'] = {}
cl['online'] = {}
for email in self.contacts:
status = self.getContactStatus(email)
if status == 'FLN' and not showOffline:
continue
elif status == 'FLN':
cl['offline'][email] = self.contacts[email]
else:
cl['online'][email] = self.contacts[email]
else:
# Initialize return dict and build id2group_name dict
for i in self.reverseGroups:
cl[i] = {}
cl['No group'] = {}
# classify contacts into their group/s
for email in self.contacts:
contactGroups = []
for id in self.getContactGroupIds(email):
contactGroups += [self.groups[id].name]
if len(contactGroups) == 0: # email doesn't belong to any group
contactGroups = ['No group']
# the actual classification:
for group in contactGroups:
if showOffline:
cl[group][email] = self.contacts[email]
elif self.getContactStatus(email) != 'FLN':
cl[group][email] = self.contacts[email]
if not showEmptyGroups:
for i in cl.keys():
if len(cl[i]) == 0:
del cl[i]
return cl
class ContactNotInListError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return 'Contact ' + repr(self.value) + ' is not in the list'
class ContactNotInGroupError(Exception):
def __init__(self, value, group):
self.value = value
self.group = group
def __str__(self):
return 'Contact ' + repr(self.value) + ' is not in this group: ' \
+ str(self.group)
class GroupNotFoundError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return 'Group ' + repr(self.value) + ' does not exist'
|