we now stringprep jid and resource everywhere:
when we recieve a jid from server when we enter a jid or resource in GUI
This commit is contained in:
parent
1462b4a27f
commit
f130ce29c0
|
@ -177,25 +177,14 @@ class Connection:
|
|||
self.retrycount = 0
|
||||
# END __init__
|
||||
|
||||
def strip_jid(self, jid):
|
||||
'''look into gajim.contacts if we already have this jid CASE INSENSITIVE
|
||||
and returns it
|
||||
the function accetps jid and fjid'''
|
||||
ji, resource = gajim.get_room_and_nick_from_fjid(jid)
|
||||
for rjid in gajim.contacts[self.name]:
|
||||
if ji.lower() == rjid.lower(): # we found the jid
|
||||
ji = rjid
|
||||
if resource:
|
||||
return ji + '/' + resource
|
||||
return ji
|
||||
|
||||
def get_full_jid(self, iq_obj):
|
||||
'''return the full jid (with resource) from an iq as unicode'''
|
||||
return unicode(self.strip_jid(str(iq_obj.getFrom())))
|
||||
return helpers.parse_jid(str(iq_obj.getFrom()))
|
||||
|
||||
def get_jid(self, iq_obj):
|
||||
'''return the jid (without resource) from an iq as unicode'''
|
||||
return unicode(self.strip_jid(iq_obj.getFrom().getStripped()))
|
||||
jid = self.get_full_jid(iq_obj)
|
||||
return gajim.get_jid_without_resource(jid)
|
||||
|
||||
def put_event(self, ev):
|
||||
if gajim.events_for_ui.has_key(self.name):
|
||||
|
@ -1096,7 +1085,7 @@ class Connection:
|
|||
def _rosterSetCB(self, con, iq_obj):
|
||||
gajim.log.debug('rosterSetCB')
|
||||
for item in iq_obj.getTag('query').getChildren():
|
||||
jid = item.getAttr('jid')
|
||||
jid = helprs.parse_jid(item.getAttr('jid'))
|
||||
name = item.getAttr('name')
|
||||
sub = item.getAttr('subscription')
|
||||
ask = item.getAttr('ask')
|
||||
|
@ -1266,9 +1255,11 @@ class Connection:
|
|||
def _getRosterCB(self, con, iq_obj):
|
||||
if not self.connection:
|
||||
return
|
||||
roster = self.connection.getRoster().getRaw().copy()
|
||||
if not roster:
|
||||
roster = {}
|
||||
r = self.connection.getRoster().getRaw()
|
||||
|
||||
roster = {}
|
||||
for jid in r:
|
||||
roster[helpers.parse_jid(jid)] = r[jid]
|
||||
|
||||
jid = gajim.get_jid_from_account(self.name)
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ import stat
|
|||
|
||||
import gajim
|
||||
from common import i18n
|
||||
from common.xmpp_stringprep import nodeprep, resourceprep, nameprep
|
||||
|
||||
try:
|
||||
import winsound # windows-only built-in module for playing wav
|
||||
|
@ -35,15 +36,104 @@ except:
|
|||
_ = i18n._
|
||||
Q_ = i18n.Q_
|
||||
|
||||
class InvalidFormat(Exception):
|
||||
pass
|
||||
|
||||
def parse_jid(jidstring):
|
||||
'''Perform stringprep on all JID fragments from a string
|
||||
and return the full jid'''
|
||||
# This function comes from http://svn.twistedmatrix.com/cvs/trunk/twisted/words/protocols/jabber/jid.py
|
||||
|
||||
user = None
|
||||
server = None
|
||||
resource = None
|
||||
|
||||
# Search for delimiters
|
||||
user_sep = jidstring.find("@")
|
||||
res_sep = jidstring.find("/")
|
||||
|
||||
if user_sep == -1:
|
||||
if res_sep == -1:
|
||||
# host
|
||||
server = jidstring
|
||||
else:
|
||||
# host/resource
|
||||
server = jidstring[0:res_sep]
|
||||
resource = jidstring[res_sep + 1:] or None
|
||||
else:
|
||||
if res_sep == -1:
|
||||
# user@host
|
||||
user = jidstring[0:user_sep] or None
|
||||
server = jidstring[user_sep + 1:]
|
||||
else:
|
||||
if user_sep < res_sep:
|
||||
# user@host/resource
|
||||
user = jidstring[0:user_sep] or None
|
||||
server = jidstring[user_sep + 1:user_sep + (res_sep - user_sep)]
|
||||
resource = jidstring[res_sep + 1:] or None
|
||||
else:
|
||||
# server/resource (with an @ in resource)
|
||||
server = jidstring[0:res_sep]
|
||||
resource = jidstring[res_sep + 1:] or None
|
||||
|
||||
return prep(user, server, resource)
|
||||
|
||||
def parse_resource(resource):
|
||||
'''Perform stringprep on resource and return it'''
|
||||
if resource:
|
||||
try:
|
||||
return resourceprep.prepare(unicode(resource))
|
||||
except UnicodeError:
|
||||
raise InvalidFormat, "Invalid character in resource"
|
||||
|
||||
def prep(user, server, resource):
|
||||
'''Perform stringprep on all JID fragments and return the full jid'''
|
||||
# This function comes from http://svn.twistedmatrix.com/cvs/trunk/twisted/words/protocols/jabber/jid.py
|
||||
|
||||
if user:
|
||||
try:
|
||||
user = nodeprep.prepare(unicode(user))
|
||||
except UnicodeError:
|
||||
raise InvalidFormat, "Invalid character in username"
|
||||
else:
|
||||
user = None
|
||||
|
||||
if not server:
|
||||
raise InvalidFormat, "Server address required."
|
||||
else:
|
||||
try:
|
||||
server = nameprep.prepare(unicode(server))
|
||||
except UnicodeError:
|
||||
raise InvalidFormat, "Invalid character in hostname"
|
||||
|
||||
if resource:
|
||||
try:
|
||||
resource = resourceprep.prepare(unicode(resource))
|
||||
except UnicodeError:
|
||||
raise InvalidFormat, "Invalid character in resource"
|
||||
else:
|
||||
resource = None
|
||||
|
||||
if user:
|
||||
if resource:
|
||||
return "%s@%s/%s" % (user, server, resource)
|
||||
else:
|
||||
return "%s@%s" % (user, server)
|
||||
else:
|
||||
if resource:
|
||||
return "%s/%s" % (server, resource)
|
||||
else:
|
||||
return server
|
||||
|
||||
def temp_failure_retry(func, *args, **kwargs):
|
||||
while True:
|
||||
try:
|
||||
return func(*args, **kwargs)
|
||||
except (os.error, IOError), ex:
|
||||
if ex.errno == errno.EINTR:
|
||||
continue
|
||||
else:
|
||||
raise
|
||||
while True:
|
||||
try:
|
||||
return func(*args, **kwargs)
|
||||
except (os.error, IOError), ex:
|
||||
if ex.errno == errno.EINTR:
|
||||
continue
|
||||
else:
|
||||
raise
|
||||
|
||||
def check_paths():
|
||||
LOGPATH = gajim.LOGPATH
|
||||
|
@ -422,13 +512,13 @@ def one_account_connected():
|
|||
return one_connected
|
||||
|
||||
def get_output_of_command(command):
|
||||
try:
|
||||
child_stdin, child_stdout = os.popen2(command)
|
||||
except ValueError:
|
||||
return None
|
||||
try:
|
||||
child_stdin, child_stdout = os.popen2(command)
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
output = child_stdout.readlines()
|
||||
child_stdout.close()
|
||||
child_stdin.close()
|
||||
|
||||
return output
|
||||
output = child_stdout.readlines()
|
||||
child_stdout.close()
|
||||
child_stdin.close()
|
||||
|
||||
return output
|
||||
|
|
|
@ -0,0 +1,246 @@
|
|||
## common/xmpp_stringprep.py
|
||||
##
|
||||
## Gajim Team:
|
||||
## - Yann Le Boulanger <asterix@lagaule.org>
|
||||
## - Vincent Hanquez <tab@snarc.org>
|
||||
## - Nikos Kouremenos <kourem@gmail.com>
|
||||
##
|
||||
## Copyright (C) 2001-2005 Twisted Matrix Laboratories.
|
||||
## Copyright (C) 2005 Gajim Team
|
||||
##
|
||||
## This program 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; version 2 only.
|
||||
##
|
||||
## This program 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.
|
||||
##
|
||||
|
||||
import sys, warnings
|
||||
|
||||
if sys.version_info < (2,3,2):
|
||||
import re
|
||||
|
||||
class IDNA:
|
||||
dots = re.compile(u"[\u002E\u3002\uFF0E\uFF61]")
|
||||
def nameprep(self, label):
|
||||
return label.lower()
|
||||
|
||||
idna = IDNA()
|
||||
|
||||
crippled = True
|
||||
|
||||
warnings.warn("Accented and non-Western Jabber IDs will not be properly "
|
||||
"case-folded with this version of Python, resulting in "
|
||||
"incorrect protocol-level behavior. It is strongly "
|
||||
"recommended you upgrade to Python 2.3.2 or newer if you "
|
||||
"intend to use Twisted's Jabber support.")
|
||||
|
||||
else:
|
||||
import stringprep
|
||||
import unicodedata
|
||||
from encodings import idna
|
||||
|
||||
crippled = False
|
||||
|
||||
del sys, warnings
|
||||
|
||||
class ILookupTable:
|
||||
""" Interface for character lookup classes. """
|
||||
|
||||
def lookup(self, c):
|
||||
""" Return whether character is in this table. """
|
||||
|
||||
class IMappingTable:
|
||||
""" Interface for character mapping classes. """
|
||||
|
||||
def map(self, c):
|
||||
""" Return mapping for character. """
|
||||
|
||||
class LookupTableFromFunction:
|
||||
|
||||
__implements__ = ILookupTable
|
||||
|
||||
def __init__(self, in_table_function):
|
||||
self.lookup = in_table_function
|
||||
|
||||
class LookupTable:
|
||||
|
||||
__implements__ = ILookupTable
|
||||
|
||||
def __init__(self, table):
|
||||
self._table = table
|
||||
|
||||
def lookup(self, c):
|
||||
return c in self._table
|
||||
|
||||
class MappingTableFromFunction:
|
||||
|
||||
__implements__ = IMappingTable
|
||||
|
||||
def __init__(self, map_table_function):
|
||||
self.map = map_table_function
|
||||
|
||||
class EmptyMappingTable:
|
||||
|
||||
__implements__ = IMappingTable
|
||||
|
||||
def __init__(self, in_table_function):
|
||||
self._in_table_function = in_table_function
|
||||
|
||||
def map(self, c):
|
||||
if self._in_table_function(c):
|
||||
return None
|
||||
else:
|
||||
return c
|
||||
|
||||
class Profile:
|
||||
def __init__(self, mappings=[], normalize=True, prohibiteds=[],
|
||||
check_unassigneds=True, check_bidi=True):
|
||||
self.mappings = mappings
|
||||
self.normalize = normalize
|
||||
self.prohibiteds = prohibiteds
|
||||
self.do_check_unassigneds = check_unassigneds
|
||||
self.do_check_bidi = check_bidi
|
||||
|
||||
def prepare(self, string):
|
||||
result = self.map(string)
|
||||
if self.normalize:
|
||||
result = unicodedata.normalize("NFKC", result)
|
||||
self.check_prohibiteds(result)
|
||||
if self.do_check_unassigneds:
|
||||
self.check_unassigneds(result)
|
||||
if self.do_check_bidi:
|
||||
self.check_bidirectionals(result)
|
||||
return result
|
||||
|
||||
def map(self, string):
|
||||
result = []
|
||||
|
||||
for c in string:
|
||||
result_c = c
|
||||
|
||||
for mapping in self.mappings:
|
||||
result_c = mapping.map(c)
|
||||
if result_c != c:
|
||||
break
|
||||
|
||||
if result_c is not None:
|
||||
result.append(result_c)
|
||||
|
||||
return u"".join(result)
|
||||
|
||||
def check_prohibiteds(self, string):
|
||||
for c in string:
|
||||
for table in self.prohibiteds:
|
||||
if table.lookup(c):
|
||||
raise UnicodeError, "Invalid character %s" % repr(c)
|
||||
|
||||
def check_unassigneds(self, string):
|
||||
for c in string:
|
||||
if stringprep.in_table_a1(c):
|
||||
raise UnicodeError, "Unassigned code point %s" % repr(c)
|
||||
|
||||
def check_bidirectionals(self, string):
|
||||
found_LCat = False
|
||||
found_RandALCat = False
|
||||
|
||||
for c in string:
|
||||
if stringprep.in_table_d1(c):
|
||||
found_RandALCat = True
|
||||
if stringprep.in_table_d2(c):
|
||||
found_LCat = True
|
||||
|
||||
if found_LCat and found_RandALCat:
|
||||
raise UnicodeError, "Violation of BIDI Requirement 2"
|
||||
|
||||
if found_RandALCat and not (stringprep.in_table_d1(string[0]) and
|
||||
stringprep.in_table_d1(string[-1])):
|
||||
raise UnicodeError, "Violation of BIDI Requirement 3"
|
||||
|
||||
|
||||
class NamePrep:
|
||||
""" Implements nameprep on international domain names.
|
||||
|
||||
STD3ASCIIRules is assumed true in this implementation.
|
||||
"""
|
||||
|
||||
# Prohibited characters.
|
||||
prohibiteds = [unichr(n) for n in range(0x00, 0x2c + 1) +
|
||||
range(0x2e, 0x2f + 1) +
|
||||
range(0x3a, 0x40 + 1) +
|
||||
range(0x5b, 0x60 + 1) +
|
||||
range(0x7b, 0x7f + 1) ]
|
||||
|
||||
def prepare(self, string):
|
||||
result = []
|
||||
|
||||
labels = idna.dots.split(string)
|
||||
|
||||
if labels and len(labels[-1]) == 0:
|
||||
trailing_dot = '.'
|
||||
del labels[-1]
|
||||
else:
|
||||
trailing_dot = ''
|
||||
|
||||
for label in labels:
|
||||
result.append(self.nameprep(label))
|
||||
|
||||
return ".".join(result)+trailing_dot
|
||||
|
||||
def check_prohibiteds(self, string):
|
||||
for c in string:
|
||||
if c in self.prohibiteds:
|
||||
raise UnicodeError, "Invalid character %s" % repr(c)
|
||||
|
||||
def nameprep(self, label):
|
||||
label = idna.nameprep(label)
|
||||
self.check_prohibiteds(label)
|
||||
if label[0] == '-':
|
||||
raise UnicodeError, "Invalid leading hyphen-minus"
|
||||
if label[-1] == '-':
|
||||
raise UnicodeError, "Invalid trailing hyphen-minus"
|
||||
return label
|
||||
|
||||
if crippled:
|
||||
case_map = MappingTableFromFunction(lambda c: c.lower())
|
||||
nodeprep = Profile(mappings=[case_map],
|
||||
normalize=False,
|
||||
prohibiteds=[LookupTable([u' ', u'"', u'&', u"'", u'/',
|
||||
u':', u'<', u'>', u'@'])],
|
||||
check_unassigneds=False,
|
||||
check_bidi=False)
|
||||
|
||||
resourceprep = Profile(normalize=False,
|
||||
check_unassigneds=False,
|
||||
check_bidi=False)
|
||||
|
||||
else:
|
||||
C_11 = LookupTableFromFunction(stringprep.in_table_c11)
|
||||
C_12 = LookupTableFromFunction(stringprep.in_table_c12)
|
||||
C_21 = LookupTableFromFunction(stringprep.in_table_c21)
|
||||
C_22 = LookupTableFromFunction(stringprep.in_table_c22)
|
||||
C_3 = LookupTableFromFunction(stringprep.in_table_c3)
|
||||
C_4 = LookupTableFromFunction(stringprep.in_table_c4)
|
||||
C_5 = LookupTableFromFunction(stringprep.in_table_c5)
|
||||
C_6 = LookupTableFromFunction(stringprep.in_table_c6)
|
||||
C_7 = LookupTableFromFunction(stringprep.in_table_c7)
|
||||
C_8 = LookupTableFromFunction(stringprep.in_table_c8)
|
||||
C_9 = LookupTableFromFunction(stringprep.in_table_c9)
|
||||
|
||||
B_1 = EmptyMappingTable(stringprep.in_table_b1)
|
||||
B_2 = MappingTableFromFunction(stringprep.map_table_b2)
|
||||
|
||||
nodeprep = Profile(mappings=[B_1, B_2],
|
||||
prohibiteds=[C_11, C_12, C_21, C_22,
|
||||
C_3, C_4, C_5, C_6, C_7, C_8, C_9,
|
||||
LookupTable([u'"', u'&', u"'", u'/',
|
||||
u':', u'<', u'>', u'@'])])
|
||||
|
||||
resourceprep = Profile(mappings=[B_1,],
|
||||
prohibiteds=[C_12, C_21, C_22,
|
||||
C_3, C_4, C_5, C_6, C_7, C_8, C_9])
|
||||
|
||||
nameprep = NamePrep()
|
|
@ -1169,16 +1169,28 @@ class AccountModificationWindow:
|
|||
_('Account name cannot contain spaces.')).get_response()
|
||||
return
|
||||
jid = self.xml.get_widget('jid_entry').get_text().decode('utf-8')
|
||||
if jid == '' or jid.count('@') != 1:
|
||||
dialogs.ErrorDialog(_('Invalid Jabber ID'),
|
||||
_('A Jabber ID must be in the form "user@servername".')).get_response()
|
||||
|
||||
# check if jid is conform to RFC and stringprep it
|
||||
try:
|
||||
jid = helpers.parse_jid(jid)
|
||||
except helpers.InvalidFormat, s:
|
||||
pritext = _('Invalid User ID')
|
||||
dialogs.ErrorDialog(pritext, s).get_response()
|
||||
return
|
||||
|
||||
resource = self.xml.get_widget('resource_entry').get_text().decode('utf-8')
|
||||
try:
|
||||
resource = helpers.parse_resource(resource)
|
||||
except helpers.InvalidFormat, s:
|
||||
pritext = _('Invalid User ID')
|
||||
dialogs.ErrorDialog(pritext, s).get_response()
|
||||
return
|
||||
|
||||
config['savepass'] = self.xml.get_widget(
|
||||
'save_password_checkbutton').get_active()
|
||||
config['password'] = self.xml.get_widget('password_entry').get_text().\
|
||||
decode('utf-8')
|
||||
config['resource'] = self.xml.get_widget('resource_entry').get_text().\
|
||||
decode('utf-8')
|
||||
config['resource'] = resource
|
||||
config['priority'] = self.xml.get_widget('priority_spinbutton').\
|
||||
get_value_as_int()
|
||||
config['autoconnect'] = self.xml.get_widget('autoconnect_checkbutton').\
|
||||
|
@ -2516,16 +2528,26 @@ class AccountCreationWizardWindow:
|
|||
server = widgets['server_comboboxentry'].child.get_text()
|
||||
savepass = widgets['save_password_checkbutton'].get_active()
|
||||
password = widgets['pass_entry'].get_text()
|
||||
if self.check_data(username, server):
|
||||
self.save_account(self.account, username, server, savepass, password,
|
||||
register_new)
|
||||
self.finish_label.set_text(finish_text)
|
||||
self.xml.get_widget('cancel_button').hide()
|
||||
self.back_button.hide()
|
||||
self.xml.get_widget('forward_button').hide()
|
||||
self.finish_button.set_sensitive(True)
|
||||
self.advanced_button.show()
|
||||
self.notebook.set_current_page(3)
|
||||
|
||||
jid = username + '@' + server
|
||||
# check if jid is conform to RFC and stringprep it
|
||||
try:
|
||||
jid = helpers.parse_jid(jid)
|
||||
except helpers.InvalidFormat, s:
|
||||
pritext = _('Invalid User ID')
|
||||
dialogs.ErrorDialog(pritext, s).get_response()
|
||||
return
|
||||
|
||||
username, server = gajim.get_room_name_and_server_from_room_jid(jid)
|
||||
self.save_account(self.account, username, server, savepass, password,
|
||||
register_new)
|
||||
self.finish_label.set_text(finish_text)
|
||||
self.xml.get_widget('cancel_button').hide()
|
||||
self.back_button.hide()
|
||||
self.xml.get_widget('forward_button').hide()
|
||||
self.finish_button.set_sensitive(True)
|
||||
self.advanced_button.show()
|
||||
self.notebook.set_current_page(3)
|
||||
|
||||
def on_advanced_button_clicked(self, widget):
|
||||
gajim.interface.windows[self.account]['account_modification'] = \
|
||||
|
@ -2535,18 +2557,6 @@ class AccountCreationWizardWindow:
|
|||
def on_finish_button_clicked(self, widget):
|
||||
self.window.destroy()
|
||||
|
||||
def check_data(self, username, server):
|
||||
if len(username) == 0:
|
||||
dialogs.ErrorDialog(_('Username is missing'),
|
||||
_('You need to enter a username to continue.')).get_response()
|
||||
return False
|
||||
elif len(server) == 0:
|
||||
dialogs.ErrorDialog(_('Server address is missing'),
|
||||
_('You need to enter a valid server address to continue.')).get_response()
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def on_nick_entry_changed(self, widget):
|
||||
self.update_jid(widget)
|
||||
|
||||
|
|
|
@ -355,19 +355,16 @@ _('Please fill in the data of the contact you want to add in account %s') %accou
|
|||
if not jid:
|
||||
return
|
||||
|
||||
if jid.find('@') < 0:
|
||||
# check if jid is conform to RFC and stringprep it
|
||||
try:
|
||||
jid = helpers.parse_jid(jid)
|
||||
except helpers.InvalidFormat, s:
|
||||
pritext = _('Invalid User ID')
|
||||
sectext = _('Jabber ID must be of the form "user@servername".')
|
||||
ErrorDialog(pritext, sectext).get_response()
|
||||
ErrorDialog(pritext, s).get_response()
|
||||
return
|
||||
|
||||
# check if contact is already in roster (user@server == UsEr@server)
|
||||
already_in = False
|
||||
for rjid in gajim.contacts[self.account]:
|
||||
if jid.lower() == rjid.lower():
|
||||
already_in = True
|
||||
break
|
||||
if already_in:
|
||||
# Check if jid is already in roster
|
||||
if jid in gajim.contacts[self.account]:
|
||||
ErrorDialog(_('Contact already in roster'),
|
||||
_('The contact is already listed in your roster.')).get_response()
|
||||
return
|
||||
|
|
Loading…
Reference in New Issue