[thorstenp] remove whitespace at eol

This commit is contained in:
Yann Leboulanger 2008-12-03 21:56:12 +00:00
parent 0d33683944
commit e389e0b16b
81 changed files with 1186 additions and 1188 deletions

View file

@ -492,7 +492,7 @@ class CommandWindow:
if self.data_form_widget.data_form: if self.data_form_widget.data_form:
# cmdnode.addChild(node=dataforms.DataForm(tofill=self.data_form_widget.data_form)) # cmdnode.addChild(node=dataforms.DataForm(tofill=self.data_form_widget.data_form))
# FIXME: simplified form to send # FIXME: simplified form to send
cmdnode.addChild(node=self.data_form_widget.data_form) cmdnode.addChild(node=self.data_form_widget.data_form)
def callback(response): def callback(response):

View file

@ -92,14 +92,14 @@ class AdvancedConfigurationWindow(object):
# key = option name (root/subopt/opt separated by \n then) # key = option name (root/subopt/opt separated by \n then)
# value = array(oldval, newval) # value = array(oldval, newval)
self.changed_opts = {} self.changed_opts = {}
# For i18n # For i18n
self.right_true_dict = {True: _('Activated'), False: _('Deactivated')} self.right_true_dict = {True: _('Activated'), False: _('Deactivated')}
self.types = { self.types = {
'boolean': _('Boolean'), 'boolean': _('Boolean'),
'integer': _('Integer'), 'integer': _('Integer'),
'string': _('Text'), 'string': _('Text'),
'color': _('Color')} 'color': _('Color')}
treeview = self.xml.get_widget('advanced_treeview') treeview = self.xml.get_widget('advanced_treeview')
self.treeview = treeview self.treeview = treeview
@ -279,6 +279,6 @@ class AdvancedConfigurationWindow(object):
self.treeview.collapse_all() self.treeview.collapse_all()
else: else:
# ... and be restored correctly here # ... and be restored correctly here
self.treeview.expand_all() self.treeview.expand_all()
# vim: se ts=3: # vim: se ts=3:

View file

@ -68,7 +68,7 @@ class AtomWindow:
assert len(self.__class__.entries)>0 assert len(self.__class__.entries)>0
newentry = self.__class__.entries.pop(0) newentry = self.__class__.entries.pop(0)
# fill the fields # fill the fields
if newentry.feed_link is not None: if newentry.feed_link is not None:
self.feed_title_label.set_markup( self.feed_title_label.set_markup(

View file

@ -28,7 +28,7 @@ import gobject
class CellRendererImage(gtk.GenericCellRenderer): class CellRendererImage(gtk.GenericCellRenderer):
__gproperties__ = { __gproperties__ = {
'image': (gobject.TYPE_OBJECT, 'Image', 'image': (gobject.TYPE_OBJECT, 'Image',
'Image', gobject.PARAM_READWRITE), 'Image', gobject.PARAM_READWRITE),
} }
@ -46,13 +46,13 @@ class CellRendererImage(gtk.GenericCellRenderer):
return getattr(self, pspec.name) return getattr(self, pspec.name)
def func(self, model, path, iter_, image_tree): def func(self, model, path, iter_, image_tree):
image, tree = image_tree image, tree = image_tree
if model.get_value(iter_, self.tv_index) != image: if model.get_value(iter_, self.tv_index) != image:
return return
self.redraw = 1 self.redraw = 1
col = tree.get_column(self.col_index) col = tree.get_column(self.col_index)
cell_area = tree.get_cell_area(path, col) cell_area = tree.get_cell_area(path, col)
tree.queue_draw_area(cell_area.x, cell_area.y, tree.queue_draw_area(cell_area.x, cell_area.y,
cell_area.width, cell_area.height) cell_area.width, cell_area.height)
@ -70,7 +70,7 @@ class CellRendererImage(gtk.GenericCellRenderer):
self.animation_timeout, tree, image) self.animation_timeout, tree, image)
elif image in self.iters: elif image in self.iters:
del self.iters[image] del self.iters[image]
def on_render(self, window, widget, background_area, cell_area, def on_render(self, window, widget, background_area, cell_area,
expose_area, flags): expose_area, flags):
if not self.image: if not self.image:

View file

@ -509,7 +509,7 @@ class ChatControlBase(MessageControl):
start_iter, end_iter = message_buffer.get_bounds() start_iter, end_iter = message_buffer.get_bounds()
message = message_buffer.get_text(start_iter, end_iter, False).decode( message = message_buffer.get_text(start_iter, end_iter, False).decode(
'utf-8') 'utf-8')
xhtml = self.msg_textview.get_xhtml() xhtml = self.msg_textview.get_xhtml()
# construct event instance from binding # construct event instance from binding
event = gtk.gdk.Event(gtk.gdk.KEY_PRESS) # it's always a key-press here event = gtk.gdk.Event(gtk.gdk.KEY_PRESS) # it's always a key-press here
@ -792,16 +792,16 @@ class ChatControlBase(MessageControl):
def on_color_menuitem_activale(self, widget): def on_color_menuitem_activale(self, widget):
color_dialog = gtk.ColorSelectionDialog('Select a color') color_dialog = gtk.ColorSelectionDialog('Select a color')
color_dialog.connect('response', self.msg_textview.color_set, color_dialog.connect('response', self.msg_textview.color_set,
color_dialog.colorsel) color_dialog.colorsel)
color_dialog.show_all() color_dialog.show_all()
def on_font_menuitem_activale(self, widget): def on_font_menuitem_activale(self, widget):
font_dialog = gtk.FontSelectionDialog('Select a font') font_dialog = gtk.FontSelectionDialog('Select a font')
font_dialog.connect('response', self.msg_textview.font_set, font_dialog.connect('response', self.msg_textview.font_set,
font_dialog.fontsel) font_dialog.fontsel)
font_dialog.show_all() font_dialog.show_all()
def on_actions_button_clicked(self, widget): def on_actions_button_clicked(self, widget):
'''popup action menu''' '''popup action menu'''

View file

@ -108,7 +108,7 @@ if gajim.HAVE_GPG:
enc = self._addHeaderFooter(str_, 'MESSAGE') enc = self._addHeaderFooter(str_, 'MESSAGE')
proc.handles['stdin'].write(enc) proc.handles['stdin'].write(enc)
proc.handles['stdin'].close() proc.handles['stdin'].close()
output = proc.handles['stdout'].read() output = proc.handles['stdout'].read()
proc.handles['stdout'].close() proc.handles['stdout'].close()
@ -166,7 +166,7 @@ if gajim.HAVE_GPG:
try: proc.wait() try: proc.wait()
except IOError: pass except IOError: pass
keyid = '' keyid = ''
if 'GOODSIG' in resp: if 'GOODSIG' in resp:
keyid = resp['GOODSIG'].split()[0] keyid = resp['GOODSIG'].split()[0]

View file

@ -39,15 +39,15 @@ Process object, which contains the filehandles to talk to GnuPG with.
Example code: Example code:
>>> import GnuPGInterface >>> import GnuPGInterface
>>> >>>
>>> plaintext = "Three blind mice" >>> plaintext = "Three blind mice"
>>> passphrase = "This is the passphrase" >>> passphrase = "This is the passphrase"
>>> >>>
>>> gnupg = GnuPGInterface.GnuPG() >>> gnupg = GnuPGInterface.GnuPG()
>>> gnupg.options.armor = 1 >>> gnupg.options.armor = 1
>>> gnupg.options.meta_interactive = 0 >>> gnupg.options.meta_interactive = 0
>>> gnupg.options.extra_args.append('--no-secmem-warning') >>> gnupg.options.extra_args.append('--no-secmem-warning')
>>> >>>
>>> # Normally we might specify something in >>> # Normally we might specify something in
>>> # gnupg.options.recipients, like >>> # gnupg.options.recipients, like
>>> # gnupg.options.recipients = [ '0xABCD1234', 'bob@foo.bar' ] >>> # gnupg.options.recipients = [ '0xABCD1234', 'bob@foo.bar' ]
@ -55,39 +55,39 @@ Example code:
>>> # If you are doing standard, public-key encryption, using >>> # If you are doing standard, public-key encryption, using
>>> # --encrypt, you will need to specify recipients before >>> # --encrypt, you will need to specify recipients before
>>> # calling gnupg.run() >>> # calling gnupg.run()
>>> >>>
>>> # First we'll encrypt the test_text input symmetrically >>> # First we'll encrypt the test_text input symmetrically
>>> p1 = gnupg.run(['--symmetric'], >>> p1 = gnupg.run(['--symmetric'],
... create_fhs=['stdin', 'stdout', 'passphrase']) ... create_fhs=['stdin', 'stdout', 'passphrase'])
>>> >>>
>>> p1.handles['passphrase'].write(passphrase) >>> p1.handles['passphrase'].write(passphrase)
>>> p1.handles['passphrase'].close() >>> p1.handles['passphrase'].close()
>>> >>>
>>> p1.handles['stdin'].write(plaintext) >>> p1.handles['stdin'].write(plaintext)
>>> p1.handles['stdin'].close() >>> p1.handles['stdin'].close()
>>> >>>
>>> ciphertext = p1.handles['stdout'].read() >>> ciphertext = p1.handles['stdout'].read()
>>> p1.handles['stdout'].close() >>> p1.handles['stdout'].close()
>>> >>>
>>> # process cleanup >>> # process cleanup
>>> p1.wait() >>> p1.wait()
>>> >>>
>>> # Now we'll decrypt what we just encrypted it, >>> # Now we'll decrypt what we just encrypted it,
>>> # using the convience method to get the >>> # using the convience method to get the
>>> # passphrase to GnuPG >>> # passphrase to GnuPG
>>> gnupg.passphrase = passphrase >>> gnupg.passphrase = passphrase
>>> >>>
>>> p2 = gnupg.run(['--decrypt'], create_fhs=['stdin', 'stdout']) >>> p2 = gnupg.run(['--decrypt'], create_fhs=['stdin', 'stdout'])
>>> >>>
>>> p2.handles['stdin'].write(ciphertext) >>> p2.handles['stdin'].write(ciphertext)
>>> p2.handles['stdin'].close() >>> p2.handles['stdin'].close()
>>> >>>
>>> decrypted_plaintext = p2.handles['stdout'].read() >>> decrypted_plaintext = p2.handles['stdout'].read()
>>> p2.handles['stdout'].close() >>> p2.handles['stdout'].close()
>>> >>>
>>> # process cleanup >>> # process cleanup
>>> p2.wait() >>> p2.wait()
>>> >>>
>>> # Our decrypted plaintext: >>> # Our decrypted plaintext:
>>> decrypted_plaintext >>> decrypted_plaintext
'Three blind mice' 'Three blind mice'
@ -99,10 +99,10 @@ Example code:
>>> >>>
>>> ################################################## >>> ##################################################
>>> # Now let's trying using run()'s attach_fhs paramter >>> # Now let's trying using run()'s attach_fhs paramter
>>> >>>
>>> # we're assuming we're running on a unix... >>> # we're assuming we're running on a unix...
>>> input = open('/etc/motd') >>> input = open('/etc/motd')
>>> >>>
>>> p1 = gnupg.run(['--symmetric'], create_fhs=['stdout'], >>> p1 = gnupg.run(['--symmetric'], create_fhs=['stdout'],
... attach_fhs={'stdin': input}) ... attach_fhs={'stdin': input})
>>> >>>
@ -111,26 +111,26 @@ Example code:
>>> >>>
>>> # process cleanup >>> # process cleanup
>>> p1.wait() >>> p1.wait()
>>> >>>
>>> # Now let's run the output through GnuPG >>> # Now let's run the output through GnuPG
>>> # We'll write the output to a temporary file, >>> # We'll write the output to a temporary file,
>>> import tempfile >>> import tempfile
>>> temp = tempfile.TemporaryFile() >>> temp = tempfile.TemporaryFile()
>>> >>>
>>> p2 = gnupg.run(['--decrypt'], create_fhs=['stdin'], >>> p2 = gnupg.run(['--decrypt'], create_fhs=['stdin'],
... attach_fhs={'stdout': temp}) ... attach_fhs={'stdout': temp})
>>> >>>
>>> # give GnuPG our encrypted stuff from the first run >>> # give GnuPG our encrypted stuff from the first run
>>> p2.handles['stdin'].write(ciphertext) >>> p2.handles['stdin'].write(ciphertext)
>>> p2.handles['stdin'].close() >>> p2.handles['stdin'].close()
>>> >>>
>>> # process cleanup >>> # process cleanup
>>> p2.wait() >>> p2.wait()
>>> >>>
>>> # rewind the tempfile and see what GnuPG gave us >>> # rewind the tempfile and see what GnuPG gave us
>>> temp.seek(0) >>> temp.seek(0)
>>> decrypted_plaintext = temp.read() >>> decrypted_plaintext = temp.read()
>>> >>>
>>> # compare what GnuPG decrypted with our original input >>> # compare what GnuPG decrypted with our original input
>>> input.seek(0) >>> input.seek(0)
>>> input_data = input.read() >>> input_data = input.read()
@ -150,7 +150,7 @@ so that it has an encrypt_string() method that returns
ciphertext. ciphertext.
>>> import GnuPGInterface >>> import GnuPGInterface
>>> >>>
>>> class MyGnuPG(GnuPGInterface.GnuPG): >>> class MyGnuPG(GnuPGInterface.GnuPG):
... ...
... def __init__(self): ... def __init__(self):
@ -164,12 +164,12 @@ ciphertext.
... ...
... def encrypt_string(self, string, recipients): ... def encrypt_string(self, string, recipients):
... gnupg.options.recipients = recipients # a list! ... gnupg.options.recipients = recipients # a list!
... ...
... proc = gnupg.run(['--encrypt'], create_fhs=['stdin', 'stdout']) ... proc = gnupg.run(['--encrypt'], create_fhs=['stdin', 'stdout'])
... ...
... proc.handles['stdin'].write(string) ... proc.handles['stdin'].write(string)
... proc.handles['stdin'].close() ... proc.handles['stdin'].close()
... ...
... output = proc.handles['stdout'].read() ... output = proc.handles['stdout'].read()
... proc.handles['stdout'].close() ... proc.handles['stdout'].close()
... ...
@ -194,10 +194,10 @@ Here is an example of generating a key:
>>> # but we capture logger to surpress the dry-run command. >>> # but we capture logger to surpress the dry-run command.
>>> # We also have to capture stdout since otherwise doctest complains; >>> # We also have to capture stdout since otherwise doctest complains;
>>> # Normally you can let stdout through when generating a key. >>> # Normally you can let stdout through when generating a key.
>>> >>>
>>> proc = gnupg.run(['--gen-key'], create_fhs=['stdin', 'stdout', >>> proc = gnupg.run(['--gen-key'], create_fhs=['stdin', 'stdout',
... 'logger']) ... 'logger'])
>>> >>>
>>> proc.handles['stdin'].write('''Key-Type: DSA >>> proc.handles['stdin'].write('''Key-Type: DSA
... Key-Length: 1024 ... Key-Length: 1024
... # We are only testing syntax this time, so dry-run ... # We are only testing syntax this time, so dry-run
@ -212,12 +212,12 @@ Here is an example of generating a key:
... %pubring foo.pub ... %pubring foo.pub
... %secring foo.sec ... %secring foo.sec
... ''') ... ''')
>>> >>>
>>> proc.handles['stdin'].close() >>> proc.handles['stdin'].close()
>>> >>>
>>> report = proc.handles['logger'].read() >>> report = proc.handles['logger'].read()
>>> proc.handles['logger'].close() >>> proc.handles['logger'].close()
>>> >>>
>>> proc.wait() >>> proc.wait()
""" """
@ -250,21 +250,21 @@ _fd_options = { 'passphrase': '--passphrase-fd',
class GnuPG: class GnuPG:
"""Class instances represent GnuPG. """Class instances represent GnuPG.
Instance attributes of a GnuPG object are: Instance attributes of a GnuPG object are:
* call -- string to call GnuPG with. Defaults to "gpg" * call -- string to call GnuPG with. Defaults to "gpg"
* passphrase -- Since it is a common operation * passphrase -- Since it is a common operation
to pass in a passphrase to GnuPG, to pass in a passphrase to GnuPG,
and working with the passphrase filehandle mechanism directly and working with the passphrase filehandle mechanism directly
can be mundane, if set, the passphrase attribute can be mundane, if set, the passphrase attribute
works in a special manner. If the passphrase attribute is set, works in a special manner. If the passphrase attribute is set,
and no passphrase file object is sent in to run(), and no passphrase file object is sent in to run(),
then GnuPG instnace will take care of sending the passphrase to then GnuPG instnace will take care of sending the passphrase to
GnuPG, the executable instead of having the user sent it in manually. GnuPG, the executable instead of having the user sent it in manually.
* options -- Object of type GnuPGInterface.Options. * options -- Object of type GnuPGInterface.Options.
Attribute-setting in options determines Attribute-setting in options determines
the command-line options used when calling GnuPG. the command-line options used when calling GnuPG.
""" """
@ -273,14 +273,14 @@ class GnuPG:
self.call = 'gpg' self.call = 'gpg'
self.passphrase = None self.passphrase = None
self.options = Options() self.options = Options()
def run(self, gnupg_commands, args=None, create_fhs=None, attach_fhs=None): def run(self, gnupg_commands, args=None, create_fhs=None, attach_fhs=None):
"""Calls GnuPG with the list of string commands gnupg_commands, """Calls GnuPG with the list of string commands gnupg_commands,
complete with prefixing dashes. complete with prefixing dashes.
For example, gnupg_commands could be For example, gnupg_commands could be
'["--sign", "--encrypt"]' '["--sign", "--encrypt"]'
Returns a GnuPGInterface.Process object. Returns a GnuPGInterface.Process object.
args is an optional list of GnuPG command arguments (not options), args is an optional list of GnuPG command arguments (not options),
such as keyID's to export, filenames to process, etc. such as keyID's to export, filenames to process, etc.
@ -289,7 +289,7 @@ class GnuPG:
'handles' attribute. The generated filehandles can be used 'handles' attribute. The generated filehandles can be used
to communicate with GnuPG via standard input, standard output, to communicate with GnuPG via standard input, standard output,
the status-fd, passphrase-fd, etc. the status-fd, passphrase-fd, etc.
Valid GnuPG filehandle names are: Valid GnuPG filehandle names are:
* stdin * stdin
* stdout * stdout
@ -298,10 +298,10 @@ class GnuPG:
* passphase * passphase
* command * command
* logger * logger
The purpose of each filehandle is described in the GnuPG The purpose of each filehandle is described in the GnuPG
documentation. documentation.
attach_fhs is an optional dictionary with GnuPG filehandle attach_fhs is an optional dictionary with GnuPG filehandle
names mapping to opened files. GnuPG will read or write names mapping to opened files. GnuPG will read or write
to the file accordingly. For example, if 'my_file' is an to the file accordingly. For example, if 'my_file' is an
@ -309,21 +309,21 @@ class GnuPG:
will read its standard input from my_file. This is useful will read its standard input from my_file. This is useful
if you want GnuPG to read/write to/from an existing file. if you want GnuPG to read/write to/from an existing file.
For instance: For instance:
f = open("encrypted.gpg") f = open("encrypted.gpg")
gnupg.run(["--decrypt"], attach_fhs={'stdin': f}) gnupg.run(["--decrypt"], attach_fhs={'stdin': f})
Using attach_fhs also helps avoid system buffering Using attach_fhs also helps avoid system buffering
issues that can arise when using create_fhs, which issues that can arise when using create_fhs, which
can cause the process to deadlock. can cause the process to deadlock.
If not mentioned in create_fhs or attach_fhs, If not mentioned in create_fhs or attach_fhs,
GnuPG filehandles which are a std* (stdin, stdout, stderr) GnuPG filehandles which are a std* (stdin, stdout, stderr)
are defaulted to the running process' version of handle. are defaulted to the running process' version of handle.
Otherwise, that type of handle is simply not used when calling GnuPG. Otherwise, that type of handle is simply not used when calling GnuPG.
For example, if you do not care about getting data from GnuPG's For example, if you do not care about getting data from GnuPG's
status filehandle, simply do not specify it. status filehandle, simply do not specify it.
run() returns a Process() object which has a 'handles' run() returns a Process() object which has a 'handles'
which is a dictionary mapping from the handle name which is a dictionary mapping from the handle name
(such as 'stdin' or 'stdout') to the respective (such as 'stdin' or 'stdout') to the respective
@ -331,47 +331,47 @@ class GnuPG:
For instance, if the call was For instance, if the call was
process = gnupg.run(["--decrypt"], stdin=1) process = gnupg.run(["--decrypt"], stdin=1)
after run returns 'process.handles["stdin"]' after run returns 'process.handles["stdin"]'
is a FileObject connected to GnuPG's standard input, is a FileObject connected to GnuPG's standard input,
and can be written to. and can be written to.
""" """
if args is None: args = [] if args is None: args = []
if create_fhs is None: create_fhs = [] if create_fhs is None: create_fhs = []
if attach_fhs is None: attach_fhs = {} if attach_fhs is None: attach_fhs = {}
for std in _stds: for std in _stds:
if std not in attach_fhs \ if std not in attach_fhs \
and std not in create_fhs: and std not in create_fhs:
attach_fhs.setdefault(std, getattr(sys, std)) attach_fhs.setdefault(std, getattr(sys, std))
handle_passphrase = 0 handle_passphrase = 0
if self.passphrase is not None \ if self.passphrase is not None \
and 'passphrase' not in attach_fhs \ and 'passphrase' not in attach_fhs \
and 'passphrase' not in create_fhs: and 'passphrase' not in create_fhs:
handle_passphrase = 1 handle_passphrase = 1
create_fhs.append('passphrase') create_fhs.append('passphrase')
process = self._attach_fork_exec(gnupg_commands, args, process = self._attach_fork_exec(gnupg_commands, args,
create_fhs, attach_fhs) create_fhs, attach_fhs)
if handle_passphrase: if handle_passphrase:
passphrase_fh = process.handles['passphrase'] passphrase_fh = process.handles['passphrase']
passphrase_fh.write( self.passphrase ) passphrase_fh.write( self.passphrase )
passphrase_fh.close() passphrase_fh.close()
del process.handles['passphrase'] del process.handles['passphrase']
return process return process
def _attach_fork_exec(self, gnupg_commands, args, create_fhs, attach_fhs): def _attach_fork_exec(self, gnupg_commands, args, create_fhs, attach_fhs):
"""This is like run(), but without the passphrase-helping """This is like run(), but without the passphrase-helping
(note that run() calls this).""" (note that run() calls this)."""
process = Process() process = Process()
for fh_name in create_fhs + attach_fhs.keys(): for fh_name in create_fhs + attach_fhs.keys():
if fh_name not in _fd_modes: if fh_name not in _fd_modes:
raise KeyError, \ raise KeyError, \
@ -393,26 +393,26 @@ class GnuPG:
# if we are writing # if we are writing
if _fd_modes[fh_name] == 'w': pipe = (pipe[1], pipe[0]) if _fd_modes[fh_name] == 'w': pipe = (pipe[1], pipe[0])
process._pipes[fh_name] = Pipe(pipe[0], pipe[1], 0) process._pipes[fh_name] = Pipe(pipe[0], pipe[1], 0)
for fh_name, fh in attach_fhs.items(): for fh_name, fh in attach_fhs.items():
process._pipes[fh_name] = Pipe(fh.fileno(), fh.fileno(), 1) process._pipes[fh_name] = Pipe(fh.fileno(), fh.fileno(), 1)
process.pid = os.fork() process.pid = os.fork()
if process.pid == 0: self._as_child(process, gnupg_commands, args) if process.pid == 0: self._as_child(process, gnupg_commands, args)
return self._as_parent(process) return self._as_parent(process)
def _as_parent(self, process): def _as_parent(self, process):
"""Stuff run after forking in parent""" """Stuff run after forking in parent"""
for k, p in process._pipes.items(): for k, p in process._pipes.items():
if not p.direct: if not p.direct:
os.close(p.child) os.close(p.child)
process.handles[k] = os.fdopen(p.parent, _fd_modes[k]) process.handles[k] = os.fdopen(p.parent, _fd_modes[k])
# user doesn't need these # user doesn't need these
del process._pipes del process._pipes
return process return process
@ -422,27 +422,27 @@ class GnuPG:
for std in _stds: for std in _stds:
p = process._pipes[std] p = process._pipes[std]
os.dup2( p.child, getattr(sys, "__%s__" % std).fileno() ) os.dup2( p.child, getattr(sys, "__%s__" % std).fileno() )
for k, p in process._pipes.items(): for k, p in process._pipes.items():
if p.direct and k not in _stds: if p.direct and k not in _stds:
# we want the fh to stay open after execing # we want the fh to stay open after execing
fcntl.fcntl( p.child, fcntl.F_SETFD, 0 ) fcntl.fcntl( p.child, fcntl.F_SETFD, 0 )
fd_args = [] fd_args = []
for k, p in process._pipes.items(): for k, p in process._pipes.items():
# set command-line options for non-standard fds # set command-line options for non-standard fds
if k not in _stds: if k not in _stds:
fd_args.extend([ _fd_options[k], "%d" % p.child ]) fd_args.extend([ _fd_options[k], "%d" % p.child ])
if not p.direct: os.close(p.parent) if not p.direct: os.close(p.parent)
command = [ self.call ] + fd_args + self.options.get_args() \ command = [ self.call ] + fd_args + self.options.get_args() \
+ gnupg_commands + args + gnupg_commands + args
os.execvp( command[0], command ) os.execvp( command[0], command )
class Pipe: class Pipe:
"""simple struct holding stuff about pipes we use""" """simple struct holding stuff about pipes we use"""
def __init__(self, parent, child, direct): def __init__(self, parent, child, direct):
@ -456,14 +456,14 @@ class Options:
This class is responsible for determining command-line arguments This class is responsible for determining command-line arguments
which are based on options. It can be said that a GnuPG which are based on options. It can be said that a GnuPG
object has-a Options object in its options attribute. object has-a Options object in its options attribute.
Attributes which correlate directly to GnuPG options: Attributes which correlate directly to GnuPG options:
Each option here defaults to false or None, and is described in Each option here defaults to false or None, and is described in
GnuPG documentation. GnuPG documentation.
Booleans (set these attributes to booleans) Booleans (set these attributes to booleans)
* armor * armor
* no_greeting * no_greeting
* no_verbose * no_verbose
@ -475,54 +475,54 @@ class Options:
* force_v3_sigs * force_v3_sigs
* no_options * no_options
* textmode * textmode
Strings (set these attributes to strings) Strings (set these attributes to strings)
* homedir * homedir
* default_key * default_key
* comment * comment
* compress_algo * compress_algo
* options * options
Lists (set these attributes to lists) Lists (set these attributes to lists)
* recipients (***NOTE*** plural of 'recipient') * recipients (***NOTE*** plural of 'recipient')
* encrypt_to * encrypt_to
Meta options Meta options
Meta options are options provided by this module that do Meta options are options provided by this module that do
not correlate directly to any GnuPG option by name, not correlate directly to any GnuPG option by name,
but are rather bundle of options used to accomplish but are rather bundle of options used to accomplish
a specific goal, such as obtaining compatibility with PGP 5. a specific goal, such as obtaining compatibility with PGP 5.
The actual arguments each of these reflects may change with time. Each The actual arguments each of these reflects may change with time. Each
defaults to false unless otherwise specified. defaults to false unless otherwise specified.
meta_pgp_5_compatible -- If true, arguments are generated to try meta_pgp_5_compatible -- If true, arguments are generated to try
to be compatible with PGP 5.x. to be compatible with PGP 5.x.
meta_pgp_2_compatible -- If true, arguments are generated to try meta_pgp_2_compatible -- If true, arguments are generated to try
to be compatible with PGP 2.x. to be compatible with PGP 2.x.
meta_interactive -- If false, arguments are generated to try to meta_interactive -- If false, arguments are generated to try to
help the using program use GnuPG in a non-interactive help the using program use GnuPG in a non-interactive
environment, such as CGI scripts. Default is true. environment, such as CGI scripts. Default is true.
extra_args -- Extra option arguments may be passed in extra_args -- Extra option arguments may be passed in
via the attribute extra_args, a list. via the attribute extra_args, a list.
>>> import GnuPGInterface >>> import GnuPGInterface
>>> >>>
>>> gnupg = GnuPGInterface.GnuPG() >>> gnupg = GnuPGInterface.GnuPG()
>>> gnupg.options.armor = 1 >>> gnupg.options.armor = 1
>>> gnupg.options.recipients = ['Alice', 'Bob'] >>> gnupg.options.recipients = ['Alice', 'Bob']
>>> gnupg.options.extra_args = ['--no-secmem-warning'] >>> gnupg.options.extra_args = ['--no-secmem-warning']
>>> >>>
>>> # no need for users to call this normally; just for show here >>> # no need for users to call this normally; just for show here
>>> gnupg.options.get_args() >>> gnupg.options.get_args()
['--armor', '--recipient', 'Alice', '--recipient', 'Bob', '--no-secmem-warning'] ['--armor', '--recipient', 'Alice', '--recipient', 'Bob', '--no-secmem-warning']
""" """
def __init__(self): def __init__(self):
# booleans # booleans
self.armor = 0 self.armor = 0
@ -553,13 +553,13 @@ class Options:
# lists # lists
self.encrypt_to = [] self.encrypt_to = []
self.recipients = [] self.recipients = []
# miscellaneous arguments # miscellaneous arguments
self.extra_args = [] self.extra_args = []
def get_args( self ): def get_args( self ):
"""Generate a list of GnuPG arguments based upon attributes.""" """Generate a list of GnuPG arguments based upon attributes."""
return self.get_meta_args() + self.get_standard_args() + self.extra_args return self.get_meta_args() + self.get_standard_args() + self.extra_args
def get_standard_args( self ): def get_standard_args( self ):
@ -575,7 +575,7 @@ class Options:
args.extend( [ '--compress-algo', self.compress_algo ] ) args.extend( [ '--compress-algo', self.compress_algo ] )
if self.default_key is not None: if self.default_key is not None:
args.extend( [ '--default-key', self.default_key ] ) args.extend( [ '--default-key', self.default_key ] )
if self.no_options: args.append( '--no-options' ) if self.no_options: args.append( '--no-options' )
if self.armor: args.append( '--armor' ) if self.armor: args.append( '--armor' )
if self.textmode: args.append( '--textmode' ) if self.textmode: args.append( '--textmode' )
@ -591,7 +591,7 @@ class Options:
for r in self.recipients: args.extend( [ '--recipient', r ] ) for r in self.recipients: args.extend( [ '--recipient', r ] )
for r in self.encrypt_to: args.extend( [ '--encrypt-to', r ] ) for r in self.encrypt_to: args.extend( [ '--encrypt-to', r ] )
return args return args
def get_meta_args( self ): def get_meta_args( self ):
@ -610,26 +610,26 @@ class Options:
class Process: class Process:
"""Objects of this class encompass properties of a GnuPG """Objects of this class encompass properties of a GnuPG
process spawned by GnuPG.run(). process spawned by GnuPG.run().
# gnupg is a GnuPG object # gnupg is a GnuPG object
process = gnupg.run( [ '--decrypt' ], stdout = 1 ) process = gnupg.run( [ '--decrypt' ], stdout = 1 )
out = process.handles['stdout'].read() out = process.handles['stdout'].read()
... ...
os.waitpid( process.pid, 0 ) os.waitpid( process.pid, 0 )
Data Attributes Data Attributes
handles -- This is a map of filehandle-names to handles -- This is a map of filehandle-names to
the file handles, if any, that were requested via run() and hence the file handles, if any, that were requested via run() and hence
are connected to the running GnuPG process. Valid names are connected to the running GnuPG process. Valid names
of this map are only those handles that were requested. of this map are only those handles that were requested.
pid -- The PID of the spawned GnuPG process. pid -- The PID of the spawned GnuPG process.
Useful to know, since once should call Useful to know, since once should call
os.waitpid() to clean up the process, especially os.waitpid() to clean up the process, especially
if multiple calls are made to run(). if multiple calls are made to run().
""" """
def __init__(self): def __init__(self):
self._pipes = {} self._pipes = {}
self.handles = {} self.handles = {}
@ -639,7 +639,7 @@ class Process:
def wait(self): def wait(self):
"""Wait on the process to exit, allowing for child cleanup. """Wait on the process to exit, allowing for child cleanup.
Will raise an IOError if the process exits non-zero.""" Will raise an IOError if the process exits non-zero."""
e = os.waitpid(self.pid, 0)[1] e = os.waitpid(self.pid, 0)[1]
if e != 0: if e != 0:
raise IOError, "GnuPG exited non-zero, with code %d" % (e << 8) raise IOError, "GnuPG exited non-zero, with code %d" % (e << 8)

View file

@ -88,7 +88,7 @@ class OldEntry(xmpp.Node, object):
source_feed = self.getTag('feed').getTagData('title') source_feed = self.getTag('feed').getTagData('title')
else: else:
source_feed = None source_feed = None
if main_feed is not None and source_feed is not None: if main_feed is not None and source_feed is not None:
return u'%s: %s' % (main_feed, source_feed) return u'%s: %s' % (main_feed, source_feed)
@ -99,7 +99,7 @@ class OldEntry(xmpp.Node, object):
else: else:
return u'' return u''
feed_title = property(get_feed_title, None, None, feed_title = property(get_feed_title, None, None,
''' Title of feed. It is built from entry''s original feed title and title of feed ''' Title of feed. It is built from entry''s original feed title and title of feed
which delivered this entry. ''') which delivered this entry. ''')
@ -151,7 +151,7 @@ class OldEntry(xmpp.Node, object):
return date return date
updated = property(get_updated, None, None, updated = property(get_updated, None, None,
''' Last significant modification time. ''') ''' Last significant modification time. ''')
feed_tagline = u'' feed_tagline = u''

View file

@ -239,7 +239,7 @@ class ConnectionCaps(object):
if contact is None: if contact is None:
# TODO: a way to put contact not-in-roster # TODO: a way to put contact not-in-roster
# into Contacts # into Contacts
return return
# get the caps element # get the caps element
caps = presence.getTag('c') caps = presence.getTag('c')

View file

@ -42,7 +42,7 @@ except ImportError:
def create_log_db(): def create_log_db():
print _('creating logs database') print _('creating logs database')
con = sqlite.connect(logger.LOG_DB_PATH) con = sqlite.connect(logger.LOG_DB_PATH)
os.chmod(logger.LOG_DB_PATH, 0600) # rw only for us os.chmod(logger.LOG_DB_PATH, 0600) # rw only for us
cur = con.cursor() cur = con.cursor()
# create the tables # create the tables
@ -61,19 +61,19 @@ def create_log_db():
jid TEXT UNIQUE, jid TEXT UNIQUE,
type INTEGER type INTEGER
); );
CREATE TABLE unread_messages( CREATE TABLE unread_messages(
message_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE, message_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
jid_id INTEGER jid_id INTEGER
); );
CREATE INDEX idx_unread_messages_jid_id ON unread_messages (jid_id); CREATE INDEX idx_unread_messages_jid_id ON unread_messages (jid_id);
CREATE TABLE transports_cache ( CREATE TABLE transports_cache (
transport TEXT UNIQUE, transport TEXT UNIQUE,
type INTEGER type INTEGER
); );
CREATE TABLE logs( CREATE TABLE logs(
log_line_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE, log_line_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
jid_id INTEGER, jid_id INTEGER,
@ -84,7 +84,7 @@ def create_log_db():
message TEXT, message TEXT,
subject TEXT subject TEXT
); );
CREATE INDEX idx_logs_jid_id_kind ON logs (jid_id, kind); CREATE INDEX idx_logs_jid_id_kind ON logs (jid_id, kind);
CREATE TABLE caps_cache ( CREATE TABLE caps_cache (
@ -137,7 +137,7 @@ def check_and_possibly_create_paths():
print _('%s is a directory but should be a file') % LOG_DB_PATH print _('%s is a directory but should be a file') % LOG_DB_PATH
print _('Gajim will now exit') print _('Gajim will now exit')
sys.exit() sys.exit()
else: # dot_gajim doesn't exist else: # dot_gajim doesn't exist
if dot_gajim: # is '' on win9x so avoid that if dot_gajim: # is '' on win9x so avoid that
create_path(dot_gajim) create_path(dot_gajim)

View file

@ -36,7 +36,7 @@ class AdHocCommand:
def isVisibleFor(samejid): def isVisibleFor(samejid):
''' This returns True if that command should be visible and invokable ''' This returns True if that command should be visible and invokable
for others. for others.
samejid - True when command is invoked by an entity with the same bare samejid - True when command is invoked by an entity with the same bare
jid.''' jid.'''
return True return True
@ -88,7 +88,7 @@ class ChangeStatusCommand(AdHocCommand):
# first query... # first query...
response, cmd = self.buildResponse(request, defaultaction = 'execute', response, cmd = self.buildResponse(request, defaultaction = 'execute',
actions = ['execute']) actions = ['execute'])
cmd.addChild(node = dataforms.SimpleDataForm( cmd.addChild(node = dataforms.SimpleDataForm(
title = _('Change status'), title = _('Change status'),
instructions = _('Set the presence type and description'), instructions = _('Set the presence type and description'),
@ -113,7 +113,7 @@ class ChangeStatusCommand(AdHocCommand):
# for next invocation # for next invocation
self.execute = self.changestatus self.execute = self.changestatus
return True # keep the session return True # keep the session
def changestatus(self, request): def changestatus(self, request):
@ -193,7 +193,7 @@ class LeaveGroupchatsCommand(AdHocCommand):
if not len(options): if not len(options):
response, cmd = self.buildResponse(request, status = 'completed') response, cmd = self.buildResponse(request, status = 'completed')
cmd.addChild('note', {}, _('You have not joined a groupchat.')) cmd.addChild('note', {}, _('You have not joined a groupchat.'))
self.connection.connection.send(response) self.connection.connection.send(response)
return False return False

View file

@ -191,7 +191,7 @@ class Config:
'noconfirm_close_muc_rooms': [opt_str, '', _('Never ask before closing group chat tab/window in this space separated list of group chat jids.')], 'noconfirm_close_muc_rooms': [opt_str, '', _('Never ask before closing group chat tab/window in this space separated list of group chat jids.')],
'notify_on_file_complete': [opt_bool, True], 'notify_on_file_complete': [opt_bool, True],
'file_transfers_port': [opt_int, 28011], 'file_transfers_port': [opt_int, 28011],
'ft_add_hosts_to_send': [opt_str, '', _('Comma separated list of hosts that we send, in addition of local interfaces, for File Transfer in case of address translation/port forwarding.')], 'ft_add_hosts_to_send': [opt_str, '', _('Comma separated list of hosts that we send, in addition of local interfaces, for File Transfer in case of address translation/port forwarding.')],
'conversation_font': [opt_str, ''], 'conversation_font': [opt_str, ''],
'use_kib_mib': [opt_bool, False, _('IEC standard says KiB = 1024 bytes, KB = 1000 bytes.')], 'use_kib_mib': [opt_bool, False, _('IEC standard says KiB = 1024 bytes, KB = 1000 bytes.')],
'notify_on_all_muc_messages': [opt_bool, False], 'notify_on_all_muc_messages': [opt_bool, False],
@ -557,7 +557,7 @@ class Config:
if optname not in self.__options: if optname not in self.__options:
return None return None
return self.__options[optname][OPT_VAL] return self.__options[optname][OPT_VAL]
def get_desc(self, optname): def get_desc(self, optname):
if optname not in self.__options: if optname not in self.__options:
return None return None
@ -574,7 +574,7 @@ class Config:
if typename not in self.__options_per_key: if typename not in self.__options_per_key:
# raise RuntimeError, 'option %s does not exist' % typename # raise RuntimeError, 'option %s does not exist' % typename
return return
opt = self.__options_per_key[typename] opt = self.__options_per_key[typename]
if name in opt[1]: if name in opt[1]:
# we already have added group name before # we already have added group name before
@ -589,7 +589,7 @@ class Config:
opt = self.__options_per_key[typename] opt = self.__options_per_key[typename]
if subname is None: if subname is None:
del opt[1][name] del opt[1][name]
# if subname is specified, delete the item in the group. # if subname is specified, delete the item in the group.
elif subname in opt[1][name]: elif subname in opt[1][name]:
del opt[1][name][subname] del opt[1][name][subname]

View file

@ -1542,7 +1542,7 @@ class Connection(ConnectionHandlers):
# Not in special table, get it from messages DB # Not in special table, get it from messages DB
last_log = gajim.logger.get_last_date_that_has_logs(room_jid, last_log = gajim.logger.get_last_date_that_has_logs(room_jid,
is_room = True) is_room = True)
# Create self.last_history_time[room_jid] even if not logging, # Create self.last_history_time[room_jid] even if not logging,
# could be used in connection_handlers # could be used in connection_handlers
if last_log is None: if last_log is None:
last_log = 0 last_log = 0

View file

@ -331,7 +331,7 @@ class ConnectionBytestream:
return return
def _connect_error(self, to, _id, sid, code = 404): def _connect_error(self, to, _id, sid, code = 404):
''' cb, when there is an error establishing BS connection, or ''' cb, when there is an error establishing BS connection, or
when connection is rejected''' when connection is rejected'''
if not self.connection or self.connected < 2: if not self.connection or self.connected < 2:
return return
@ -1471,7 +1471,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
'password': conf.getTagData('password'), 'password': conf.getTagData('password'),
'nick': conf.getTagData('nick'), 'nick': conf.getTagData('nick'),
'print_status': print_status} 'print_status': print_status}
self.bookmarks.append(bm) self.bookmarks.append(bm)
self.dispatch('BOOKMARKS', self.bookmarks) self.dispatch('BOOKMARKS', self.bookmarks)
@ -1501,7 +1501,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
groups.append(group.getData()) groups.append(group.getData())
self.dispatch('ROSTER_INFO', (jid, name, sub, ask, groups)) self.dispatch('ROSTER_INFO', (jid, name, sub, ask, groups))
raise common.xmpp.NodeProcessed raise common.xmpp.NodeProcessed
def _VersionCB(self, con, iq_obj): def _VersionCB(self, con, iq_obj):
gajim.log.debug('VersionCB') gajim.log.debug('VersionCB')
if not self.connection or self.connected < 2: if not self.connection or self.connected < 2:
@ -1526,7 +1526,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
qp.attrs['seconds'] = '0' qp.attrs['seconds'] = '0'
else: else:
qp.attrs['seconds'] = idle.getIdleSec() qp.attrs['seconds'] = idle.getIdleSec()
self.connection.send(iq_obj) self.connection.send(iq_obj)
raise common.xmpp.NodeProcessed raise common.xmpp.NodeProcessed
@ -2256,7 +2256,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
if reason: if reason:
users_dict[jid]['reason'] = reason users_dict[jid]['reason'] = reason
self.dispatch('GC_AFFILIATION', (helpers.get_full_jid_from_iq(iq_obj), self.dispatch('GC_AFFILIATION', (helpers.get_full_jid_from_iq(iq_obj),
users_dict)) users_dict))
def _MucErrorCB(self, con, iq_obj): def _MucErrorCB(self, con, iq_obj):
@ -2294,13 +2294,13 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
if not self.connection: if not self.connection:
return return
self.connection.getRoster(self._on_roster_set) self.connection.getRoster(self._on_roster_set)
self.discoverItems(gajim.config.get_per('accounts', self.name, self.discoverItems(gajim.config.get_per('accounts', self.name,
'hostname'), id_prefix='p') 'hostname'), id_prefix='p')
self.discoverInfo(gajim.config.get_per('accounts', self.name, self.discoverInfo(gajim.config.get_per('accounts', self.name,
'hostname'), id_prefix='p') 'hostname'), id_prefix='p')
if gajim.config.get_per('accounts', self.name, 'use_ft_proxies'): if gajim.config.get_per('accounts', self.name, 'use_ft_proxies'):
self.discover_ft_proxies() self.discover_ft_proxies()
def discover_ft_proxies(self): def discover_ft_proxies(self):
cfg_proxies = gajim.config.get_per('accounts', self.name, cfg_proxies = gajim.config.get_per('accounts', self.name,
'file_transfer_proxies') 'file_transfer_proxies')
@ -2310,7 +2310,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
proxies = map(lambda e:e.strip(), cfg_proxies.split(',')) proxies = map(lambda e:e.strip(), cfg_proxies.split(','))
for proxy in proxies: for proxy in proxies:
gajim.proxy65_manager.resolve(proxy, self.connection, our_jid) gajim.proxy65_manager.resolve(proxy, self.connection, our_jid)
def _on_roster_set(self, roster): def _on_roster_set(self, roster):
raw_roster = roster.getRaw() raw_roster = roster.getRaw()
roster = {} roster = {}
@ -2398,7 +2398,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
# Inform GUI we just signed in # Inform GUI we just signed in
self.dispatch('SIGNED_IN', ()) self.dispatch('SIGNED_IN', ())
self.continue_connect_info = None self.continue_connect_info = None
def request_gmail_notifications(self): def request_gmail_notifications(self):
if not self.connection or self.connected < 2: if not self.connection or self.connected < 2:
return return
@ -2421,7 +2421,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
query.setNamespace(common.xmpp.NS_GMAILNOTIFY) query.setNamespace(common.xmpp.NS_GMAILNOTIFY)
self.connection.send(iq) self.connection.send(iq)
def _search_fields_received(self, con, iq_obj): def _search_fields_received(self, con, iq_obj):
jid = jid = helpers.get_jid_from_iq(iq_obj) jid = jid = helpers.get_jid_from_iq(iq_obj)
tag = iq_obj.getTag('query', namespace = common.xmpp.NS_SEARCH) tag = iq_obj.getTag('query', namespace = common.xmpp.NS_SEARCH)

View file

@ -197,7 +197,7 @@ class Contacts:
caps_hash_method=None, caps_hash=None, our_chatstate=None, caps_hash_method=None, caps_hash=None, our_chatstate=None,
chatstate=None, last_status_time=None, composing_xep=None, chatstate=None, last_status_time=None, composing_xep=None,
mood={}, tune={}, activity={}): mood={}, tune={}, activity={}):
# We don't want duplicated group values # We don't want duplicated group values
groups_unique = [] groups_unique = []
for group in groups: for group in groups:
@ -210,7 +210,7 @@ class Contacts:
caps_hash=caps_hash, our_chatstate=our_chatstate, chatstate=chatstate, caps_hash=caps_hash, our_chatstate=our_chatstate, chatstate=chatstate,
last_status_time=last_status_time, composing_xep=composing_xep, last_status_time=last_status_time, composing_xep=composing_xep,
mood=mood, tune=tune, activity=activity) mood=mood, tune=tune, activity=activity)
def copy_contact(self, contact): def copy_contact(self, contact):
return self.create_contact(jid=contact.jid, name=contact.name, return self.create_contact(jid=contact.jid, name=contact.name,
groups=contact.groups, show=contact.show, status=contact.status, groups=contact.groups, show=contact.show, status=contact.status,
@ -272,7 +272,7 @@ class Contacts:
return self._contacts[account][jid] return self._contacts[account][jid]
else: else:
return [] return []
def get_contact(self, account, jid, resource=None): def get_contact(self, account, jid, resource=None):
### WARNING ### ### WARNING ###
# This function returns a *RANDOM* resource if resource = None! # This function returns a *RANDOM* resource if resource = None!
@ -437,7 +437,7 @@ class Contacts:
nearby_family = [data for data in family nearby_family = [data for data in family
if account in accounts] if account in accounts]
bb_data = self.get_metacontacts_big_brother(nearby_family) bb_data = self.get_metacontacts_big_brother(nearby_family)
if bb_data['jid'] == jid and bb_data['account'] == account: if bb_data['jid'] == jid and bb_data['account'] == account:
return True return True
return False return False
@ -484,7 +484,7 @@ class Contacts:
# is not in our roster # is not in our roster
if not contact1: if not contact1:
if contact2: if contact2:
return -1 # prefer the known contact return -1 # prefer the known contact
else: else:
show1 = 0 show1 = 0
priority1 = 0 priority1 = 0
@ -578,7 +578,7 @@ class Contacts:
role='', affiliation='', jid='', resource=''): role='', affiliation='', jid='', resource=''):
return GC_Contact(room_jid, name, show, status, role, affiliation, jid, return GC_Contact(room_jid, name, show, status, role, affiliation, jid,
resource) resource)
def add_gc_contact(self, account, gc_contact): def add_gc_contact(self, account, gc_contact):
# No such account before ? # No such account before ?
if account not in self._gc_contacts: if account not in self._gc_contacts:

View file

@ -90,7 +90,7 @@ def srand(bottom, top):
return (decode_mpi(random_bytes(bytes)) % (top - bottom)) + bottom return (decode_mpi(random_bytes(bytes)) % (top - bottom)) + bottom
# a faster version of (base ** exp) % mod # a faster version of (base ** exp) % mod
# taken from <http://lists.danga.com/pipermail/yadis/2005-September/001445.html> # taken from <http://lists.danga.com/pipermail/yadis/2005-September/001445.html>
def powmod(base, exp, mod): def powmod(base, exp, mod):
square = base % mod square = base % mod
result = 1 result = 1

View file

@ -129,7 +129,7 @@ class DataField(ExtendedNode):
assert isinstance(value, basestring) assert isinstance(value, basestring)
self.setAttr('type', value) self.setAttr('type', value)
return locals() return locals()
@nested_property @nested_property
def var(): def var():
'''Field identifier.''' '''Field identifier.'''
@ -274,7 +274,7 @@ class ListMultiField(ListField):
for element in self.getTags('value'): for element in self.getTags('value'):
self.delChild(element) self.delChild(element)
return locals() return locals()
def iter_values(self): def iter_values(self):
for element in self.getTags('value'): for element in self.getTags('value'):
yield element.getData() yield element.getData()
@ -412,7 +412,7 @@ class SimpleDataForm(DataForm, DataRecord):
def __init__(self, type_=None, title=None, instructions=None, fields=None, extend=None): def __init__(self, type_=None, title=None, instructions=None, fields=None, extend=None):
DataForm.__init__(self, type_=type_, title=title, instructions=instructions, extend=extend) DataForm.__init__(self, type_=type_, title=title, instructions=instructions, extend=extend)
DataRecord.__init__(self, fields=fields, extend=self, associated=self) DataRecord.__init__(self, fields=fields, extend=self, associated=self)
def get_purged(self): def get_purged(self):
c = SimpleDataForm(extend=self) c = SimpleDataForm(extend=self)
del c.title del c.title

View file

@ -51,7 +51,7 @@ class SystemBus:
'''A Singleton for the DBus SystemBus''' '''A Singleton for the DBus SystemBus'''
def __init__(self): def __init__(self):
self.system_bus = None self.system_bus = None
def SystemBus(self): def SystemBus(self):
if not supported: if not supported:
raise exceptions.DbusNotSupported raise exceptions.DbusNotSupported
@ -84,7 +84,7 @@ class SessionBus:
'''A Singleton for the D-Bus SessionBus''' '''A Singleton for the D-Bus SessionBus'''
def __init__(self): def __init__(self):
self.session_bus = None self.session_bus = None
def SessionBus(self): def SessionBus(self):
if not supported: if not supported:
raise exceptions.DbusNotSupported raise exceptions.DbusNotSupported
@ -112,7 +112,7 @@ class SessionBus:
session_bus = SessionBus() session_bus = SessionBus()
def get_interface(interface, path): def get_interface(interface, path):
'''Returns an interface on the current SessionBus. If the interface isn\'t '''Returns an interface on the current SessionBus. If the interface isn\'t
running, it tries to start it first.''' running, it tries to start it first.'''
if not supported: if not supported:
return None return None
@ -148,7 +148,7 @@ def get_notifications_interface():
if supported: if supported:
class MissingArgument(dbus.DBusException): class MissingArgument(dbus.DBusException):
_dbus_error_name = _GAJIM_ERROR_IFACE + '.MissingArgument' _dbus_error_name = _GAJIM_ERROR_IFACE + '.MissingArgument'
class InvalidArgument(dbus.DBusException): class InvalidArgument(dbus.DBusException):
'''Raised when one of the provided arguments is invalid.''' '''Raised when one of the provided arguments is invalid.'''
_dbus_error_name = _GAJIM_ERROR_IFACE + '.InvalidArgument' _dbus_error_name = _GAJIM_ERROR_IFACE + '.InvalidArgument'

View file

@ -166,7 +166,7 @@ except ImportError:
HAVE_GPG = True HAVE_GPG = True
try: try:
import GnuPGInterface import GnuPGInterface
except ImportError: except ImportError:
HAVE_GPG = False HAVE_GPG = False
else: else:

View file

@ -350,10 +350,10 @@ def get_uf_role(role, plural = False):
else: else:
role_name = _('Visitor') role_name = _('Visitor')
return role_name return role_name
def get_uf_affiliation(affiliation): def get_uf_affiliation(affiliation):
'''Get a nice and translated affilition for muc''' '''Get a nice and translated affilition for muc'''
if affiliation == 'none': if affiliation == 'none':
affiliation_name = Q_('?Group Chat Contact Affiliation:None') affiliation_name = Q_('?Group Chat Contact Affiliation:None')
elif affiliation == 'owner': elif affiliation == 'owner':
affiliation_name = _('Owner') affiliation_name = _('Owner')
@ -593,7 +593,7 @@ def get_global_status():
status = gajim.connections[account].status status = gajim.connections[account].status
return status return status
def statuses_unified(): def statuses_unified():
'''testing if all statuses are the same.''' '''testing if all statuses are the same.'''
reference = None reference = None
for account in gajim.connections: for account in gajim.connections:
@ -765,7 +765,7 @@ def get_random_string_16():
char_sequence = map(lambda e:chr(e), rng) char_sequence = map(lambda e:chr(e), rng)
from random import sample from random import sample
return ''.join(sample(char_sequence, 16)) return ''.join(sample(char_sequence, 16))
def get_os_info(): def get_os_info():
if os.name == 'nt': if os.name == 'nt':
ver = os.sys.getwindowsversion() ver = os.sys.getwindowsversion()
@ -790,9 +790,9 @@ def get_os_info():
full_path_to_executable = is_in_path(executable, return_abs_path = True) full_path_to_executable = is_in_path(executable, return_abs_path = True)
if full_path_to_executable: if full_path_to_executable:
command = executable + params command = executable + params
p = subprocess.Popen([command], shell=True, stdin=subprocess.PIPE, p = subprocess.Popen([command], shell=True, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, close_fds=True) stdout=subprocess.PIPE, close_fds=True)
p.wait() p.wait()
output = temp_failure_retry(p.stdout.readline).strip() output = temp_failure_retry(p.stdout.readline).strip()
# some distros put n/a in places, so remove those # some distros put n/a in places, so remove those
output = output.replace('n/a', '').replace('N/A', '') output = output.replace('n/a', '').replace('N/A', '')
@ -832,7 +832,7 @@ def get_os_info():
return 'N/A' return 'N/A'
def sanitize_filename(filename): def sanitize_filename(filename):
'''makes sure the filename we will write does contain only acceptable and '''makes sure the filename we will write does contain only acceptable and
latin characters, and is not too long (in that case hash it)''' latin characters, and is not too long (in that case hash it)'''
# 48 is the limit # 48 is the limit
if len(filename) > 48: if len(filename) > 48:
@ -845,7 +845,7 @@ def sanitize_filename(filename):
filename = filename.replace('?', '_').replace(':', '_')\ filename = filename.replace('?', '_').replace(':', '_')\
.replace('\\', '_').replace('"', "'").replace('|', '_')\ .replace('\\', '_').replace('"', "'").replace('|', '_')\
.replace('*', '_').replace('<', '_').replace('>', '_') .replace('*', '_').replace('<', '_').replace('>', '_')
return filename return filename
def allow_showing_notification(account, type_ = 'notify_on_new_message', def allow_showing_notification(account, type_ = 'notify_on_new_message',
@ -952,7 +952,7 @@ def get_account_status(account):
return status return status
def get_notification_icon_tooltip_dict(): def get_notification_icon_tooltip_dict():
'''returns a dict of the form {acct: {'show': show, 'message': message, '''returns a dict of the form {acct: {'show': show, 'message': message,
'event_lines': [list of text lines to show in tooltip]}''' 'event_lines': [list of text lines to show in tooltip]}'''
# How many events must there be before they're shown summarized, not per-user # How many events must there be before they're shown summarized, not per-user
max_ungrouped_events = 10 max_ungrouped_events = 10
@ -1000,7 +1000,7 @@ def get_notification_icon_tooltip_dict():
else: else:
text += _(' from %s') % (jid) text += _(' from %s') % (jid)
account['event_lines'].append(text) account['event_lines'].append(text)
# Display unseen events numbers, if any # Display unseen events numbers, if any
if total_non_messages > 0: if total_non_messages > 0:
if total_non_messages > max_ungrouped_events: if total_non_messages > max_ungrouped_events:
@ -1044,7 +1044,7 @@ def get_notification_icon_tooltip_text():
# If there is only one account, its status is shown on the first line. # If there is only one account, its status is shown on the first line.
if show_more_accounts: if show_more_accounts:
text = _('Gajim') text = _('Gajim')
else: else:
text = _('Gajim - %s') % (get_account_status(accounts[0])) text = _('Gajim - %s') % (get_account_status(accounts[0]))
# Gather and display events. (With accounts, when there are more.) # Gather and display events. (With accounts, when there are more.)
@ -1081,7 +1081,7 @@ def get_accounts_info():
message = message.strip() message = message.strip()
if message != '': if message != '':
single_line += ': ' + message single_line += ': ' + message
accounts.append({'name': account, 'status_line': single_line, accounts.append({'name': account, 'status_line': single_line,
'show': status, 'message': message}) 'show': status, 'message': message})
return accounts return accounts
@ -1150,13 +1150,13 @@ def prepare_and_validate_gpg_keyID(account, jid, keyID):
'''Returns an eight char long keyID that can be used with for GPG encryption with this contact. '''Returns an eight char long keyID that can be used with for GPG encryption with this contact.
If the given keyID is None, return UNKNOWN; if the key does not match the assigned key If the given keyID is None, return UNKNOWN; if the key does not match the assigned key
XXXXXXXXMISMATCH is returned. If the key is trusted and not yet assigned, assign it''' XXXXXXXXMISMATCH is returned. If the key is trusted and not yet assigned, assign it'''
if gajim.connections[account].USE_GPG: if gajim.connections[account].USE_GPG:
if keyID and len(keyID) == 16: if keyID and len(keyID) == 16:
keyID = keyID[8:] keyID = keyID[8:]
attached_keys = gajim.config.get_per('accounts', account, attached_keys = gajim.config.get_per('accounts', account,
'attached_gpg_keys').split() 'attached_gpg_keys').split()
if jid in attached_keys and keyID: if jid in attached_keys and keyID:
attachedkeyID = attached_keys[attached_keys.index(jid) + 1] attachedkeyID = attached_keys[attached_keys.index(jid) + 1]
if attachedkeyID != keyID: if attachedkeyID != keyID:
@ -1165,7 +1165,7 @@ def prepare_and_validate_gpg_keyID(account, jid, keyID):
elif jid in attached_keys: elif jid in attached_keys:
# An unsigned presence, just use the assigned key # An unsigned presence, just use the assigned key
keyID = attached_keys[attached_keys.index(jid) + 1] keyID = attached_keys[attached_keys.index(jid) + 1]
elif keyID: elif keyID:
public_keys = gajim.connections[account].ask_gpg_keys() public_keys = gajim.connections[account].ask_gpg_keys()
# Assign the corresponding key, if we have it in our keyring # Assign the corresponding key, if we have it in our keyring
if keyID in public_keys: if keyID in public_keys:
@ -1208,7 +1208,7 @@ def sort_dataforms_func(d1, d2):
def compute_caps_hash(identities, features, dataforms=[], hash_method='sha-1'): def compute_caps_hash(identities, features, dataforms=[], hash_method='sha-1'):
'''Compute caps hash according to XEP-0115, V1.5 '''Compute caps hash according to XEP-0115, V1.5
dataforms are xmpp.DataForms objects as common.dataforms don't allow several dataforms are xmpp.DataForms objects as common.dataforms don't allow several
values without a field type list-multi''' values without a field type list-multi'''
S = '' S = ''

View file

@ -58,7 +58,7 @@ def Q_(s):
# so we must use as: # so we must use as:
# s = Q_('?vcard:Unknown') # s = Q_('?vcard:Unknown')
# widget.set_text(s) # widget.set_text(s)
# Q_() removes the ?vcard: # Q_() removes the ?vcard:
# but gettext while parsing the file detects ?vcard:Unknown as a whole string. # but gettext while parsing the file detects ?vcard:Unknown as a whole string.
# translator can either put the ?vcard: part or no (easier for him or her to no) # translator can either put the ?vcard: part or no (easier for him or her to no)
# nothing fails # nothing fails
@ -70,7 +70,7 @@ def Q_(s):
def ngettext(s_sing, s_plural, n, replace_sing = None, replace_plural = None): def ngettext(s_sing, s_plural, n, replace_sing = None, replace_plural = None):
'''use as: '''use as:
i18n.ngettext('leave room %s', 'leave rooms %s', len(rooms), 'a', 'a, b, c') i18n.ngettext('leave room %s', 'leave rooms %s', len(rooms), 'a', 'a, b, c')
in other words this is a hack to ngettext() to support %s %d etc.. in other words this is a hack to ngettext() to support %s %d etc..
''' '''
text = _translation.ungettext(s_sing, s_plural, n) text = _translation.ungettext(s_sing, s_plural, n)

View file

@ -176,8 +176,8 @@ class Logger:
pm (so higly unlikely) and if we fail we do not go chaos pm (so higly unlikely) and if we fail we do not go chaos
(user will see the first pm as if it was message in room's public chat) (user will see the first pm as if it was message in room's public chat)
and after that all okay''' and after that all okay'''
if jid.find('/') > -1: if jid.find('/') > -1:
possible_room_jid = jid.split('/', 1)[1] possible_room_jid = jid.split('/', 1)[1]
return self.jid_is_room_jid(possible_room_jid) return self.jid_is_room_jid(possible_room_jid)
else: else:
@ -336,7 +336,7 @@ class Logger:
try: try:
self.cur.execute(sql, values) self.cur.execute(sql, values)
except sqlite.DatabaseError: except sqlite.DatabaseError:
raise exceptions.DatabaseMalformed raise exceptions.DatabaseMalformed
except sqlite.OperationalError, e: except sqlite.OperationalError, e:
raise exceptions.PysqliteOperationalError(str(e)) raise exceptions.PysqliteOperationalError(str(e))
message_id = None message_id = None
@ -373,7 +373,7 @@ class Logger:
for message in results: for message in results:
msg_id = message[0] msg_id = message[0]
# here we get infos for that message, and related jid from jids table # here we get infos for that message, and related jid from jids table
# do NOT change order of SELECTed things, unless you change function(s) # do NOT change order of SELECTed things, unless you change function(s)
# that called this function # that called this function
self.cur.execute(''' self.cur.execute('''
SELECT logs.log_line_id, logs.message, logs.time, logs.subject, SELECT logs.log_line_id, logs.message, logs.time, logs.subject,

View file

@ -43,22 +43,22 @@ class Resolver:
def __init__(self, idlequeue): def __init__(self, idlequeue):
self.idlequeue = idlequeue self.idlequeue = idlequeue
# dict {host : list of srv records} # dict {host : list of srv records}
self.resolved_hosts = {} self.resolved_hosts = {}
# dict {host : list of callbacks} # dict {host : list of callbacks}
self.handlers = {} self.handlers = {}
def parse_srv_result(self, fqdn, result): def parse_srv_result(self, fqdn, result):
''' parse the output of nslookup command and return list of ''' parse the output of nslookup command and return list of
properties: 'host', 'port','weight', 'priority' corresponding to the found properties: 'host', 'port','weight', 'priority' corresponding to the found
srv hosts ''' srv hosts '''
if os.name == 'nt': if os.name == 'nt':
return self._parse_srv_result_nt(fqdn, result) return self._parse_srv_result_nt(fqdn, result)
elif os.name == 'posix': elif os.name == 'posix':
return self._parse_srv_result_posix(fqdn, result) return self._parse_srv_result_posix(fqdn, result)
def _parse_srv_result_nt(self, fqdn, result): def _parse_srv_result_nt(self, fqdn, result):
# output from win32 nslookup command # output from win32 nslookup command
if not result: if not result:
return [] return []
hosts = [] hosts = []
lines = result.replace('\r','').split('\n') lines = result.replace('\r','').split('\n')
@ -78,7 +78,7 @@ class Resolver:
hosts.append(current_host) hosts.append(current_host)
current_host = None current_host = None
continue continue
prop_type = res[0].strip() prop_type = res[0].strip()
prop_value = res[1].strip() prop_value = res[1].strip()
if prop_type.find('prio') > -1: if prop_type.find('prio') > -1:
try: try:
@ -104,11 +104,11 @@ class Resolver:
hosts.append(current_host) hosts.append(current_host)
current_host = None current_host = None
return hosts return hosts
def _parse_srv_result_posix(self, fqdn, result): def _parse_srv_result_posix(self, fqdn, result):
# typical output of bind-tools nslookup command: # typical output of bind-tools nslookup command:
# _xmpp-client._tcp.jabber.org service = 30 30 5222 jabber.org. # _xmpp-client._tcp.jabber.org service = 30 30 5222 jabber.org.
if not result: if not result:
return [] return []
ufqdn = helpers.ascii_to_idn(fqdn) # Unicode domain name ufqdn = helpers.ascii_to_idn(fqdn) # Unicode domain name
hosts = [] hosts = []
@ -144,11 +144,11 @@ class Resolver:
hosts.append({'host': host, 'port': port,'weight': weight, hosts.append({'host': host, 'port': port,'weight': weight,
'prio': prio}) 'prio': prio})
return hosts return hosts
def _on_ready(self, host, result): def _on_ready(self, host, result):
# nslookup finished, parse the result and call the handlers # nslookup finished, parse the result and call the handlers
result_list = self.parse_srv_result(host, result) result_list = self.parse_srv_result(host, result)
# practically it is impossible to be the opposite, but who knows :) # practically it is impossible to be the opposite, but who knows :)
if host not in self.resolved_hosts: if host not in self.resolved_hosts:
self.resolved_hosts[host] = result_list self.resolved_hosts[host] = result_list
@ -156,14 +156,14 @@ class Resolver:
for callback in self.handlers[host]: for callback in self.handlers[host]:
callback(host, result_list) callback(host, result_list)
del(self.handlers[host]) del(self.handlers[host])
def start_resolve(self, host): def start_resolve(self, host):
''' spawn new nslookup process and start waiting for results ''' ''' spawn new nslookup process and start waiting for results '''
ns = NsLookup(self._on_ready, host) ns = NsLookup(self._on_ready, host)
ns.set_idlequeue(self.idlequeue) ns.set_idlequeue(self.idlequeue)
ns.commandtimeout = 10 ns.commandtimeout = 10
ns.start() ns.start()
def resolve(self, host, on_ready): def resolve(self, host, on_ready):
if not host: if not host:
# empty host, return empty list of srv records # empty host, return empty list of srv records
@ -175,7 +175,7 @@ class Resolver:
return return
if host in self.handlers: if host in self.handlers:
# host is about to be resolved by another connection, # host is about to be resolved by another connection,
# attach our callback # attach our callback
self.handlers[host].append(on_ready) self.handlers[host].append(on_ready)
else: else:
# host has never been resolved, start now # host has never been resolved, start now
@ -187,29 +187,29 @@ class IdleCommand(IdleObject):
def __init__(self, on_result): def __init__(self, on_result):
# how long (sec.) to wait for result ( 0 - forever ) # how long (sec.) to wait for result ( 0 - forever )
# it is a class var, instead of a constant and we can override it. # it is a class var, instead of a constant and we can override it.
self.commandtimeout = 0 self.commandtimeout = 0
# when we have some kind of result (valid, ot not) we call this handler # when we have some kind of result (valid, ot not) we call this handler
self.result_handler = on_result self.result_handler = on_result
# if it is True, we can safetely execute the command # if it is True, we can safetely execute the command
self.canexecute = True self.canexecute = True
self.idlequeue = None self.idlequeue = None
self.result = '' self.result = ''
def set_idlequeue(self, idlequeue): def set_idlequeue(self, idlequeue):
self.idlequeue = idlequeue self.idlequeue = idlequeue
def _return_result(self): def _return_result(self):
if self.result_handler: if self.result_handler:
self.result_handler(self.result) self.result_handler(self.result)
self.result_handler = None self.result_handler = None
def _compose_command_args(self): def _compose_command_args(self):
return ['echo', 'da'] return ['echo', 'da']
def _compose_command_line(self): def _compose_command_line(self):
''' return one line representation of command and its arguments ''' ''' return one line representation of command and its arguments '''
return ' '.join(self._compose_command_args()) return ' '.join(self._compose_command_args())
def wait_child(self): def wait_child(self):
if self.pipe.poll() is None: if self.pipe.poll() is None:
# result timeout # result timeout
@ -235,16 +235,16 @@ class IdleCommand(IdleObject):
self._start_nt() self._start_nt()
elif os.name == 'posix': elif os.name == 'posix':
self._start_posix() self._start_posix()
def _start_nt(self): def _start_nt(self):
# if gajim is started from noninteraactive shells stdin is closed and # if gajim is started from noninteraactive shells stdin is closed and
# cannot be forwarded, so we have to keep it open # cannot be forwarded, so we have to keep it open
self.pipe = Popen(self._compose_command_args(), stdout=PIPE, self.pipe = Popen(self._compose_command_args(), stdout=PIPE,
bufsize = 1024, shell = True, stderr = STDOUT, stdin = PIPE) bufsize = 1024, shell = True, stderr = STDOUT, stdin = PIPE)
if self.commandtimeout >= 0: if self.commandtimeout >= 0:
self.endtime = self.idlequeue.current_time() + self.commandtimeout self.endtime = self.idlequeue.current_time() + self.commandtimeout
self.idlequeue.set_alarm(self.wait_child, 0.1) self.idlequeue.set_alarm(self.wait_child, 0.1)
def _start_posix(self): def _start_posix(self):
self.pipe = os.popen(self._compose_command_line()) self.pipe = os.popen(self._compose_command_line())
self.fd = self.pipe.fileno() self.fd = self.pipe.fileno()
@ -252,19 +252,19 @@ class IdleCommand(IdleObject):
self.idlequeue.plug_idle(self, False, True) self.idlequeue.plug_idle(self, False, True)
if self.commandtimeout >= 0: if self.commandtimeout >= 0:
self.idlequeue.set_read_timeout(self.fd, self.commandtimeout) self.idlequeue.set_read_timeout(self.fd, self.commandtimeout)
def end(self): def end(self):
self.idlequeue.unplug_idle(self.fd) self.idlequeue.unplug_idle(self.fd)
try: try:
self.pipe.close() self.pipe.close()
except Exception: except Exception:
pass pass
def pollend(self): def pollend(self):
self.idlequeue.remove_timeout(self.fd) self.idlequeue.remove_timeout(self.fd)
self.end() self.end()
self._return_result() self._return_result()
def pollin(self): def pollin(self):
try: try:
res = self.pipe.read() res = self.pipe.read()
@ -274,15 +274,15 @@ class IdleCommand(IdleObject):
return self.pollend() return self.pollend()
else: else:
self.result += res self.result += res
def read_timeout(self): def read_timeout(self):
self.end() self.end()
self._return_result() self._return_result()
class NsLookup(IdleCommand): class NsLookup(IdleCommand):
def __init__(self, on_result, host='_xmpp-client', type_ = 'srv'): def __init__(self, on_result, host='_xmpp-client', type_ = 'srv'):
IdleCommand.__init__(self, on_result) IdleCommand.__init__(self, on_result)
self.commandtimeout = 10 self.commandtimeout = 10
self.host = host.lower() self.host = host.lower()
self.type = type_.lower() self.type = type_.lower()
if not host_pattern.match(self.host): if not host_pattern.match(self.host):
@ -294,15 +294,15 @@ class NsLookup(IdleCommand):
print >> sys.stderr, 'Invalid querytype: %s' % self.type print >> sys.stderr, 'Invalid querytype: %s' % self.type
self.canexecute = False self.canexecute = False
return return
def _compose_command_args(self): def _compose_command_args(self):
return ['nslookup', '-type=' + self.type , self.host] return ['nslookup', '-type=' + self.type , self.host]
def _return_result(self): def _return_result(self):
if self.result_handler: if self.result_handler:
self.result_handler(self.host, self.result) self.result_handler(self.host, self.result)
self.result_handler = None self.result_handler = None
# below lines is on how to use API and assist in testing # below lines is on how to use API and assist in testing
if __name__ == '__main__': if __name__ == '__main__':
if os.name == 'posix': if os.name == 'posix':
@ -312,9 +312,9 @@ if __name__ == '__main__':
# testing Resolver class # testing Resolver class
import gobject import gobject
import gtk import gtk
resolver = Resolver(idlequeue) resolver = Resolver(idlequeue)
def clicked(widget): def clicked(widget):
host = text_view.get_text() host = text_view.get_text()
def on_result(host, result_array): def on_result(host, result_array):

View file

@ -106,7 +106,7 @@ class OptionsParser:
s += p + '.' s += p + '.'
s += opt s += opt
fd.write(s + ' = ' + value + '\n') fd.write(s + ' = ' + value + '\n')
def write(self): def write(self):
(base_dir, filename) = os.path.split(self.__filename) (base_dir, filename) = os.path.split(self.__filename)
self.__tempfile = os.path.join(base_dir, '.' + filename) self.__tempfile = os.path.join(base_dir, '.' + filename)
@ -192,7 +192,7 @@ class OptionsParser:
gajim.config.set('version', new_version) gajim.config.set('version', new_version)
gajim.capscache.load_from_db() gajim.capscache.load_from_db()
def update_config_x_to_09(self): def update_config_x_to_09(self):
# Var name that changed: # Var name that changed:
# avatar_width /height -> chat_avatar_width / height # avatar_width /height -> chat_avatar_width / height
@ -212,7 +212,7 @@ class OptionsParser:
d = ['accounttextcolor', 'accountbgcolor', 'accountfont', d = ['accounttextcolor', 'accountbgcolor', 'accountfont',
'accountfontattrs', 'grouptextcolor', 'groupbgcolor', 'groupfont', 'accountfontattrs', 'grouptextcolor', 'groupbgcolor', 'groupfont',
'groupfontattrs', 'contacttextcolor', 'contactbgcolor', 'contactfont', 'groupfontattrs', 'contacttextcolor', 'contactbgcolor', 'contactfont',
'contactfontattrs', 'bannertextcolor', 'bannerbgcolor', 'bannerfont', 'contactfontattrs', 'bannertextcolor', 'bannerbgcolor', 'bannerfont',
'bannerfontattrs'] 'bannerfontattrs']
for theme_name in (_('grocery'), _('default')): for theme_name in (_('grocery'), _('default')):
if theme_name not in gajim.config.get_per('themes'): if theme_name not in gajim.config.get_per('themes'):
@ -281,15 +281,15 @@ class OptionsParser:
if 'always_compact_view_gc' in self.old_values and \ if 'always_compact_view_gc' in self.old_values and \
self.old_values['always_compact_view_gc'] != 'False': self.old_values['always_compact_view_gc'] != 'False':
gajim.config.set('always_hide_groupchat_buttons', True) gajim.config.set('always_hide_groupchat_buttons', True)
for account in gajim.config.get_per('accounts'): for account in gajim.config.get_per('accounts'):
proxies_str = gajim.config.get_per('accounts', account, proxies_str = gajim.config.get_per('accounts', account,
'file_transfer_proxies') 'file_transfer_proxies')
proxies = proxies_str.split(',') proxies = proxies_str.split(',')
for i in range(0, len(proxies)): for i in range(0, len(proxies)):
proxies[i] = proxies[i].strip() proxies[i] = proxies[i].strip()
for wrong_proxy in ('proxy65.jabber.autocom.pl', for wrong_proxy in ('proxy65.jabber.autocom.pl',
'proxy65.jabber.ccc.de'): 'proxy65.jabber.ccc.de'):
if wrong_proxy in proxies: if wrong_proxy in proxies:
proxies.remove(wrong_proxy) proxies.remove(wrong_proxy)
if not 'transfer.jabber.freenet.de' in proxies: if not 'transfer.jabber.freenet.de' in proxies:
@ -380,9 +380,9 @@ class OptionsParser:
cur.close() # remove this in 2007 [pysqlite old versions need this] cur.close() # remove this in 2007 [pysqlite old versions need this]
con.close() con.close()
gajim.config.set('version', '0.10.1.5') gajim.config.set('version', '0.10.1.5')
def update_config_to_01016(self): def update_config_to_01016(self):
'''#2494 : Now we play gc_received_message sound even if '''#2494 : Now we play gc_received_message sound even if
notify_on_all_muc_messages is false. Keep precedent behaviour.''' notify_on_all_muc_messages is false. Keep precedent behaviour.'''
if 'notify_on_all_muc_messages' in self.old_values and \ if 'notify_on_all_muc_messages' in self.old_values and \
self.old_values['notify_on_all_muc_messages'] == 'False' and \ self.old_values['notify_on_all_muc_messages'] == 'False' and \
@ -419,7 +419,7 @@ class OptionsParser:
gajim.config.set('ft_add_hosts_to_send', gajim.config.set('ft_add_hosts_to_send',
self.old_values['ft_override_host_to_send']) self.old_values['ft_override_host_to_send'])
gajim.config.set('version', '0.11.0.2') gajim.config.set('version', '0.11.0.2')
def update_config_to_01111(self): def update_config_to_01111(self):
'''always_hide_chatbuttons -> compact_view''' '''always_hide_chatbuttons -> compact_view'''
if 'always_hide_groupchat_buttons' in self.old_values and \ if 'always_hide_groupchat_buttons' in self.old_values and \
@ -464,7 +464,7 @@ class OptionsParser:
d = ['accounttextcolor', 'accountbgcolor', 'accountfont', d = ['accounttextcolor', 'accountbgcolor', 'accountfont',
'accountfontattrs', 'grouptextcolor', 'groupbgcolor', 'groupfont', 'accountfontattrs', 'grouptextcolor', 'groupbgcolor', 'groupfont',
'groupfontattrs', 'contacttextcolor', 'contactbgcolor', 'contactfont', 'groupfontattrs', 'contacttextcolor', 'contactbgcolor', 'contactfont',
'contactfontattrs', 'bannertextcolor', 'bannerbgcolor', 'bannerfont', 'contactfontattrs', 'bannertextcolor', 'bannerbgcolor', 'bannerfont',
'bannerfontattrs'] 'bannerfontattrs']
theme_name = _('default') theme_name = _('default')
if theme_name not in gajim.config.get_per('themes'): if theme_name not in gajim.config.get_per('themes'):
@ -481,7 +481,7 @@ class OptionsParser:
for o in d: for o in d:
gajim.config.set_per('themes', theme_name, o, theme[d.index(o)]) gajim.config.set_per('themes', theme_name, o, theme[d.index(o)])
gajim.config.set('version', '0.11.1.4') gajim.config.set('version', '0.11.1.4')
def update_config_to_01115(self): def update_config_to_01115(self):
# copy&pasted from update_config_to_01013, possibly 'FIXME see #2812' applies too # copy&pasted from update_config_to_01013, possibly 'FIXME see #2812' applies too
back = os.getcwd() back = os.getcwd()

View file

@ -20,7 +20,7 @@
## along with Gajim. If not, see <http://www.gnu.org/licenses/>. ## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
## ##
import socket import socket
import struct import struct
import errno import errno
@ -39,9 +39,9 @@ S_FINISHED = 4
CONNECT_TIMEOUT = 20 CONNECT_TIMEOUT = 20
class Proxy65Manager: class Proxy65Manager:
''' keep records for file transfer proxies. Each time account ''' keep records for file transfer proxies. Each time account
establishes a connection to its server call proxy65manger.resolve(proxy) establishes a connection to its server call proxy65manger.resolve(proxy)
for every proxy that is convigured within the account. The class takes for every proxy that is convigured within the account. The class takes
care to resolve and test each proxy only once.''' care to resolve and test each proxy only once.'''
def __init__(self, idlequeue): def __init__(self, idlequeue):
# dict {proxy: proxy properties} # dict {proxy: proxy properties}
@ -111,9 +111,9 @@ class ProxyResolver:
# self.sid, self.sender_jid, self._on_receiver_success, # self.sid, self.sender_jid, self._on_receiver_success,
# self._on_connect_failure) # self._on_connect_failure)
#self.receiver_tester.connect() #self.receiver_tester.connect()
def _on_receiver_success(self): def _on_receiver_success(self):
self.host_tester = HostTester(self.host, self.port, self.jid, self.host_tester = HostTester(self.host, self.port, self.jid,
self.sid, self.sender_jid, self._on_connect_success, self.sid, self.sender_jid, self._on_connect_success,
self._on_connect_failure) self._on_connect_failure)
self.host_tester.connect() self.host_tester.connect()
@ -252,7 +252,7 @@ class HostTester(Socks5, IdleObject):
self.idlequeue.remove_timeout(self.fd) self.idlequeue.remove_timeout(self.fd)
if self.state == 2: if self.state == 2:
self.idlequeue.set_read_timeout(self.fd, CONNECT_TIMEOUT) self.idlequeue.set_read_timeout(self.fd, CONNECT_TIMEOUT)
# begin negotiation. on success 'address' != 0 # begin negotiation. on success 'address' != 0
buff = self.receive() buff = self.receive()
if buff == '': if buff == '':
# end connection # end connection
@ -296,7 +296,7 @@ class HostTester(Socks5, IdleObject):
self.buff = '' self.buff = ''
self.state = 1 # connected self.state = 1 # connected
self.idlequeue.plug_idle(self, True, False) self.idlequeue.plug_idle(self, True, False)
return return
class ReceiverTester(Socks5, IdleObject): class ReceiverTester(Socks5, IdleObject):
''' fake proxy tester. ''' ''' fake proxy tester. '''
@ -356,7 +356,7 @@ class ReceiverTester(Socks5, IdleObject):
self.idlequeue.remove_timeout(self.fd) self.idlequeue.remove_timeout(self.fd)
if self.state in (2, 3): if self.state in (2, 3):
self.idlequeue.set_read_timeout(self.fd, CONNECT_TIMEOUT) self.idlequeue.set_read_timeout(self.fd, CONNECT_TIMEOUT)
# begin negotiation. on success 'address' != 0 # begin negotiation. on success 'address' != 0
buff = self.receive() buff = self.receive()
if buff == '': if buff == '':
# end connection # end connection
@ -408,6 +408,6 @@ class ReceiverTester(Socks5, IdleObject):
self.buff = '' self.buff = ''
self.state = 1 # connected self.state = 1 # connected
self.idlequeue.plug_idle(self, True, False) self.idlequeue.plug_idle(self, True, False)
return return
# vim: se ts=3: # vim: se ts=3:

View file

@ -57,7 +57,7 @@ else:
interpret_url: interpret_url:
this, modulo the validated text, will be added to it this, modulo the validated text, will be added to it
validator: validator:
should return the validated text, or raise ValueError should return the validated text, or raise ValueError
''' '''
def uri_reference_role(role, rawtext, text, lineno, inliner, def uri_reference_role(role, rawtext, text, lineno, inliner,
options={}, content=[]): options={}, content=[]):
@ -143,7 +143,7 @@ else:
def create_xhtml(text): def create_xhtml(text):
return Generator.create_xhtml(text) return Generator.create_xhtml(text)
if __name__ == '__main__': if __name__ == '__main__':
print "test 1\n", Generator.create_xhtml(""" print "test 1\n", Generator.create_xhtml("""

View file

@ -14,8 +14,8 @@ features - different stuff that didn't worths separating into modules
browser - DISCO server framework. Allows to build dynamic disco tree. browser - DISCO server framework. Allows to build dynamic disco tree.
filetransfer - Currently contains only IBB stuff. Can be used for bot-to-bot transfers. filetransfer - Currently contains only IBB stuff. Can be used for bot-to-bot transfers.
Most of the classes that is defined in all these modules is an ancestors of Most of the classes that is defined in all these modules is an ancestors of
class PlugIn so they share a single set of methods allowing you to compile class PlugIn so they share a single set of methods allowing you to compile
a featured XMPP client. For every instance of PlugIn class the 'owner' is the class a featured XMPP client. For every instance of PlugIn class the 'owner' is the class
in what the plug was plugged. While plugging in such instance usually sets some in what the plug was plugged. While plugging in such instance usually sets some
methods of owner to it's own ones for easy access. All session specific info stored methods of owner to it's own ones for easy access. All session specific info stored

View file

@ -208,7 +208,7 @@ class SASL(PlugIn):
node=Node('response',attrs={'xmlns':NS_SASL},payload=[base64.encodestring(sasl_data[:-1]).replace('\r','').replace('\n','')]) node=Node('response',attrs={'xmlns':NS_SASL},payload=[base64.encodestring(sasl_data[:-1]).replace('\r','').replace('\n','')])
self._owner.send(node.__str__()) self._owner.send(node.__str__())
elif 'rspauth' in chal: self._owner.send(Node('response',attrs={'xmlns':NS_SASL}).__str__()) elif 'rspauth' in chal: self._owner.send(Node('response',attrs={'xmlns':NS_SASL}).__str__())
else: else:
self.startsasl='failure' self.startsasl='failure'
self.DEBUG('Failed SASL authentification: unknown challenge','error') self.DEBUG('Failed SASL authentification: unknown challenge','error')
raise NodeProcessed raise NodeProcessed

View file

@ -50,7 +50,7 @@ def challenge_splitter(data):
keyword, value = '', '' keyword, value = '', ''
dict_ = {} dict_ = {}
arr = None arr = None
expecting = X_KEYWORD expecting = X_KEYWORD
for iter_ in range(len(data) + 1): for iter_ in range(len(data) + 1):
end = False end = False
@ -104,12 +104,12 @@ class SASL(PlugIn):
self.on_sasl = on_sasl self.on_sasl = on_sasl
self.realm = None self.realm = None
def plugin(self,owner): def plugin(self,owner):
if 'version' not in self._owner.Dispatcher.Stream._document_attrs: if 'version' not in self._owner.Dispatcher.Stream._document_attrs:
self.startsasl='not-supported' self.startsasl='not-supported'
elif self._owner.Dispatcher.Stream.features: elif self._owner.Dispatcher.Stream.features:
try: try:
self.FeaturesHandler(self._owner.Dispatcher, self._owner.Dispatcher.Stream.features) self.FeaturesHandler(self._owner.Dispatcher, self._owner.Dispatcher.Stream.features)
except NodeProcessed: except NodeProcessed:
pass pass
else: self.startsasl=None else: self.startsasl=None
@ -117,12 +117,12 @@ class SASL(PlugIn):
''' Start authentication. Result can be obtained via "SASL.startsasl" attribute and will be ''' Start authentication. Result can be obtained via "SASL.startsasl" attribute and will be
either "success" or "failure". Note that successfull auth will take at least either "success" or "failure". Note that successfull auth will take at least
two Dispatcher.Process() calls. ''' two Dispatcher.Process() calls. '''
if self.startsasl: if self.startsasl:
pass pass
elif self._owner.Dispatcher.Stream.features: elif self._owner.Dispatcher.Stream.features:
try: try:
self.FeaturesHandler(self._owner.Dispatcher, self._owner.Dispatcher.Stream.features) self.FeaturesHandler(self._owner.Dispatcher, self._owner.Dispatcher.Stream.features)
except NodeProcessed: except NodeProcessed:
pass pass
else: self._owner.RegisterHandler('features', self.FeaturesHandler, xmlns=NS_STREAMS) else: self._owner.RegisterHandler('features', self.FeaturesHandler, xmlns=NS_STREAMS)
@ -164,9 +164,9 @@ class SASL(PlugIn):
self.mechanism = 'DIGEST-MD5' self.mechanism = 'DIGEST-MD5'
elif 'PLAIN' in self.mecs: elif 'PLAIN' in self.mecs:
self.mecs.remove('PLAIN') self.mecs.remove('PLAIN')
sasl_data='%s\x00%s\x00%s' % (self.username+'@' + self._owner.Server, sasl_data='%s\x00%s\x00%s' % (self.username+'@' + self._owner.Server,
self.username, self.password) self.username, self.password)
node=Node('auth', attrs={'xmlns':NS_SASL,'mechanism':'PLAIN'}, node=Node('auth', attrs={'xmlns':NS_SASL,'mechanism':'PLAIN'},
payload=[base64.encodestring(sasl_data).replace('\n','')]) payload=[base64.encodestring(sasl_data).replace('\n','')])
self.mechanism = 'PLAIN' self.mechanism = 'PLAIN'
else: else:
@ -179,13 +179,13 @@ class SASL(PlugIn):
def SASLHandler(self, conn, challenge): def SASLHandler(self, conn, challenge):
''' Perform next SASL auth step. Used internally. ''' ''' Perform next SASL auth step. Used internally. '''
if challenge.getNamespace() != NS_SASL: if challenge.getNamespace() != NS_SASL:
return return
if challenge.getName() == 'failure': if challenge.getName() == 'failure':
self.startsasl = 'failure' self.startsasl = 'failure'
try: try:
reason = challenge.getChildren()[0] reason = challenge.getChildren()[0]
except Exception: except Exception:
reason = challenge reason = challenge
self.DEBUG('Failed SASL authentification: %s' % reason, 'error') self.DEBUG('Failed SASL authentification: %s' % reason, 'error')
if len(self.mecs) > 0: if len(self.mecs) > 0:
@ -244,7 +244,7 @@ class SASL(PlugIn):
resp['nc'] = ('00000001') resp['nc'] = ('00000001')
resp['qop'] = 'auth' resp['qop'] = 'auth'
resp['digest-uri'] = 'xmpp/'+self._owner.Server resp['digest-uri'] = 'xmpp/'+self._owner.Server
A1=C([H(C([resp['username'], resp['realm'], self.password])), A1=C([H(C([resp['username'], resp['realm'], self.password])),
resp['nonce'], resp['cnonce']]) resp['nonce'], resp['cnonce']])
A2=C(['AUTHENTICATE',resp['digest-uri']]) A2=C(['AUTHENTICATE',resp['digest-uri']])
response= HH(C([HH(A1), resp['nonce'], resp['nc'], resp['cnonce'], response= HH(C([HH(A1), resp['nonce'], resp['nc'], resp['cnonce'],
@ -253,25 +253,25 @@ class SASL(PlugIn):
resp['charset'] = 'utf-8' resp['charset'] = 'utf-8'
sasl_data='' sasl_data=''
for key in ('charset', 'username', 'realm', 'nonce', 'nc', 'cnonce', 'digest-uri', 'response', 'qop'): for key in ('charset', 'username', 'realm', 'nonce', 'nc', 'cnonce', 'digest-uri', 'response', 'qop'):
if key in ['nc','qop','response','charset']: if key in ['nc','qop','response','charset']:
sasl_data += "%s=%s," % (key,resp[key]) sasl_data += "%s=%s," % (key,resp[key])
else: else:
sasl_data += '%s="%s",' % (key,resp[key]) sasl_data += '%s="%s",' % (key,resp[key])
########################################3333 ########################################3333
node=Node('response', attrs={'xmlns':NS_SASL}, node=Node('response', attrs={'xmlns':NS_SASL},
payload=[base64.encodestring(sasl_data[:-1]).replace('\r','').replace('\n','')]) payload=[base64.encodestring(sasl_data[:-1]).replace('\r','').replace('\n','')])
self._owner.send(node.__str__()) self._owner.send(node.__str__())
elif 'rspauth' in chal: elif 'rspauth' in chal:
self._owner.send(Node('response', attrs={'xmlns':NS_SASL}).__str__()) self._owner.send(Node('response', attrs={'xmlns':NS_SASL}).__str__())
else: else:
self.startsasl='failure' self.startsasl='failure'
self.DEBUG('Failed SASL authentification: unknown challenge', 'error') self.DEBUG('Failed SASL authentification: unknown challenge', 'error')
if self.on_sasl : if self.on_sasl :
self.on_sasl () self.on_sasl ()
raise NodeProcessed raise NodeProcessed
class NonBlockingNonSASL(PlugIn): class NonBlockingNonSASL(PlugIn):
''' Implements old Non-SASL (JEP-0078) authentication used ''' Implements old Non-SASL (JEP-0078) authentication used
in jabberd1.4 and transport authentication. in jabberd1.4 and transport authentication.
''' '''
def __init__(self, user, password, resource, on_auth): def __init__(self, user, password, resource, on_auth):
@ -286,15 +286,15 @@ class NonBlockingNonSASL(PlugIn):
def plugin(self, owner): def plugin(self, owner):
''' Determine the best auth method (digest/0k/plain) and use it for auth. ''' Determine the best auth method (digest/0k/plain) and use it for auth.
Returns used method name on success. Used internally. ''' Returns used method name on success. Used internally. '''
if not self.resource: if not self.resource:
return self.authComponent(owner) return self.authComponent(owner)
self.DEBUG('Querying server about possible auth methods', 'start') self.DEBUG('Querying server about possible auth methods', 'start')
self.owner = owner self.owner = owner
owner.Dispatcher.SendAndWaitForResponse( owner.Dispatcher.SendAndWaitForResponse(
Iq('get', NS_AUTH, payload=[Node('username', payload=[self.user])]), func=self._on_username Iq('get', NS_AUTH, payload=[Node('username', payload=[self.user])]), func=self._on_username
) )
def _on_username(self, resp): def _on_username(self, resp):
if not isResultNode(resp): if not isResultNode(resp):
self.DEBUG('No result node arrived! Aborting...','error') self.DEBUG('No result node arrived! Aborting...','error')
@ -306,9 +306,9 @@ class NonBlockingNonSASL(PlugIn):
if query.getTag('digest'): if query.getTag('digest'):
self.DEBUG("Performing digest authentication",'ok') self.DEBUG("Performing digest authentication",'ok')
query.setTagData('digest', query.setTagData('digest',
sha.new(self.owner.Dispatcher.Stream._document_attrs['id']+self.password).hexdigest()) sha.new(self.owner.Dispatcher.Stream._document_attrs['id']+self.password).hexdigest())
if query.getTag('password'): if query.getTag('password'):
query.delChild('password') query.delChild('password')
self._method='digest' self._method='digest'
elif query.getTag('token'): elif query.getTag('token'):
@ -330,7 +330,7 @@ class NonBlockingNonSASL(PlugIn):
query.setTagData('password',self.password) query.setTagData('password',self.password)
self._method='plain' self._method='plain'
resp=self.owner.Dispatcher.SendAndWaitForResponse(iq, func=self._on_auth) resp=self.owner.Dispatcher.SendAndWaitForResponse(iq, func=self._on_auth)
def _on_auth(self, resp): def _on_auth(self, resp):
if isResultNode(resp): if isResultNode(resp):
self.DEBUG('Sucessfully authenticated with remove host.','ok') self.DEBUG('Sucessfully authenticated with remove host.','ok')
@ -348,7 +348,7 @@ class NonBlockingNonSASL(PlugIn):
payload=[sha.new(owner.Dispatcher.Stream._document_attrs['id']+self.password).hexdigest()])) payload=[sha.new(owner.Dispatcher.Stream._document_attrs['id']+self.password).hexdigest()]))
owner.RegisterHandler('handshake', self.handshakeHandler, xmlns=NS_COMPONENT_ACCEPT) owner.RegisterHandler('handshake', self.handshakeHandler, xmlns=NS_COMPONENT_ACCEPT)
self._owner.onreceive(self._on_auth_component) self._owner.onreceive(self._on_auth_component)
def _on_auth_component(self, data): def _on_auth_component(self, data):
''' called when we receive some response, after we send the handshake ''' ''' called when we receive some response, after we send the handshake '''
if data: if data:
@ -358,25 +358,25 @@ class NonBlockingNonSASL(PlugIn):
return return
self._owner.onreceive(None) self._owner.onreceive(None)
self._owner._registered_name=self.user self._owner._registered_name=self.user
if self.handshake+1: if self.handshake+1:
return self.on_auth('ok') return self.on_auth('ok')
self.on_auth(None) self.on_auth(None)
def handshakeHandler(self,disp,stanza): def handshakeHandler(self,disp,stanza):
''' Handler for registering in dispatcher for accepting transport authentication. ''' ''' Handler for registering in dispatcher for accepting transport authentication. '''
if stanza.getName() == 'handshake': if stanza.getName() == 'handshake':
self.handshake=1 self.handshake=1
else: else:
self.handshake=-1 self.handshake=-1
class NonBlockingBind(Bind): class NonBlockingBind(Bind):
''' Bind some JID to the current connection to allow router know of our location.''' ''' Bind some JID to the current connection to allow router know of our location.'''
def plugin(self, owner): def plugin(self, owner):
''' Start resource binding, if allowed at this time. Used internally. ''' ''' Start resource binding, if allowed at this time. Used internally. '''
if self._owner.Dispatcher.Stream.features: if self._owner.Dispatcher.Stream.features:
try: try:
self.FeaturesHandler(self._owner.Dispatcher, self._owner.Dispatcher.Stream.features) self.FeaturesHandler(self._owner.Dispatcher, self._owner.Dispatcher.Stream.features)
except NodeProcessed: except NodeProcessed:
pass pass
else: self._owner.RegisterHandler('features', self.FeaturesHandler, xmlns=NS_STREAMS) else: self._owner.RegisterHandler('features', self.FeaturesHandler, xmlns=NS_STREAMS)
@ -388,15 +388,15 @@ class NonBlockingBind(Bind):
''' Perform binding. Use provided resource name or random (if not provided). ''' ''' Perform binding. Use provided resource name or random (if not provided). '''
self.on_bound = on_bound self.on_bound = on_bound
self._resource = resource self._resource = resource
if self._resource: if self._resource:
self._resource = [Node('resource', payload=[self._resource])] self._resource = [Node('resource', payload=[self._resource])]
else: else:
self._resource = [] self._resource = []
self._owner.onreceive(None) self._owner.onreceive(None)
self._owner.Dispatcher.SendAndWaitForResponse( self._owner.Dispatcher.SendAndWaitForResponse(
Protocol('iq',typ='set', Protocol('iq',typ='set',
payload=[Node('bind', attrs={'xmlns':NS_BIND}, payload=self._resource)]), payload=[Node('bind', attrs={'xmlns':NS_BIND}, payload=self._resource)]),
func=self._on_bound) func=self._on_bound)
def _on_bound(self, resp): def _on_bound(self, resp):
if isResultNode(resp): if isResultNode(resp):
@ -405,7 +405,7 @@ class NonBlockingBind(Bind):
jid=JID(resp.getTag('bind').getTagData('jid')) jid=JID(resp.getTag('bind').getTagData('jid'))
self._owner.User=jid.getNode() self._owner.User=jid.getNode()
self._owner.Resource=jid.getResource() self._owner.Resource=jid.getResource()
self._owner.SendAndWaitForResponse(Protocol('iq', typ='set', self._owner.SendAndWaitForResponse(Protocol('iq', typ='set',
payload=[Node('session', attrs={'xmlns':NS_SESSION})]), func=self._on_session) payload=[Node('session', attrs={'xmlns':NS_SESSION})]), func=self._on_session)
elif resp: elif resp:
self.DEBUG('Binding failed: %s.' % resp.getTag('error'),'error') self.DEBUG('Binding failed: %s.' % resp.getTag('error'),'error')
@ -413,7 +413,7 @@ class NonBlockingBind(Bind):
else: else:
self.DEBUG('Binding failed: timeout expired.', 'error') self.DEBUG('Binding failed: timeout expired.', 'error')
self.on_bound(None) self.on_bound(None)
def _on_session(self, resp): def _on_session(self, resp):
self._owner.onreceive(None) self._owner.onreceive(None)
if isResultNode(resp): if isResultNode(resp):
@ -435,15 +435,15 @@ class NonBlockingBind(Bind):
self.on_bound(None) self.on_bound(None)
class NBComponentBind(ComponentBind): class NBComponentBind(ComponentBind):
''' ComponentBind some JID to the current connection to allow ''' ComponentBind some JID to the current connection to allow
router know of our location. router know of our location.
''' '''
def plugin(self,owner): def plugin(self,owner):
''' Start resource binding, if allowed at this time. Used internally. ''' ''' Start resource binding, if allowed at this time. Used internally. '''
if self._owner.Dispatcher.Stream.features: if self._owner.Dispatcher.Stream.features:
try: try:
self.FeaturesHandler(self._owner.Dispatcher, self._owner.Dispatcher.Stream.features) self.FeaturesHandler(self._owner.Dispatcher, self._owner.Dispatcher.Stream.features)
except NodeProcessed: except NodeProcessed:
pass pass
else: else:
self._owner.RegisterHandler('features', self.FeaturesHandler, xmlns=NS_STREAMS) self._owner.RegisterHandler('features', self.FeaturesHandler, xmlns=NS_STREAMS)
@ -453,14 +453,14 @@ class NBComponentBind(ComponentBind):
''' Remove ComponentBind handler from owner's dispatcher. Used internally. ''' ''' Remove ComponentBind handler from owner's dispatcher. Used internally. '''
if self.needsUnregister: if self.needsUnregister:
self._owner.UnregisterHandler('features', self.FeaturesHandler, xmlns=NS_STREAMS) self._owner.UnregisterHandler('features', self.FeaturesHandler, xmlns=NS_STREAMS)
def Bind(self, domain = None, on_bind = None): def Bind(self, domain = None, on_bind = None):
''' Perform binding. Use provided domain name (if not provided). ''' ''' Perform binding. Use provided domain name (if not provided). '''
def wrapper(resp): def wrapper(resp):
self._on_bound(resp, domain) self._on_bound(resp, domain)
self._owner.onreceive(wrapper) self._owner.onreceive(wrapper)
self.on_bind = on_bind self.on_bind = on_bind
def _on_bound(self, resp, domain=None): def _on_bound(self, resp, domain=None):
if resp: if resp:
self.Dispatcher.ProcessNonBlocking(resp) self.Dispatcher.ProcessNonBlocking(resp)
@ -468,9 +468,9 @@ class NBComponentBind(ComponentBind):
return return
self._owner.onreceive(None) self._owner.onreceive(None)
self._owner.SendAndWaitForResponse( self._owner.SendAndWaitForResponse(
Protocol('bind', attrs={'name':domain}, xmlns=NS_COMPONENT_1), Protocol('bind', attrs={'name':domain}, xmlns=NS_COMPONENT_1),
func=self._on_bind_reponse) func=self._on_bind_reponse)
def _on_bind_reponse(self, resp): def _on_bind_reponse(self, resp):
if resp and resp.getAttr('error'): if resp and resp.getAttr('error'):
self.DEBUG('Binding failed: %s.' % resp.getAttr('error'), 'error') self.DEBUG('Binding failed: %s.' % resp.getAttr('error'), 'error')

View file

@ -128,7 +128,7 @@ class Browser(PlugIn):
as handler of some disco tree branch. as handler of some disco tree branch.
If you do not specify the node this handler will be used for all queried nodes. If you do not specify the node this handler will be used for all queried nodes.
If you do not specify the jid this handler will be used for all queried JIDs. If you do not specify the jid this handler will be used for all queried JIDs.
Usage: Usage:
cl.Browser.setDiscoHandler(someDict,node,jid) cl.Browser.setDiscoHandler(someDict,node,jid)
or or
@ -147,8 +147,8 @@ class Browser(PlugIn):
{'category':'category1','type':'type1','name':'name1'}, {'category':'category1','type':'type1','name':'name1'},
{'category':'category2','type':'type2','name':'name2'}, {'category':'category2','type':'type2','name':'name2'},
{'category':'category3','type':'type3','name':'name3'}, {'category':'category3','type':'type3','name':'name3'},
], ],
'features':['feature1','feature2','feature3','feature4'], 'features':['feature1','feature2','feature3','feature4'],
'xdata':DataForm 'xdata':DataForm
} }
} }

View file

@ -71,7 +71,7 @@ class PlugIn:
owner.__dict__[method.__name__]=method owner.__dict__[method.__name__]=method
owner.__dict__[self.__class__.__name__]=self owner.__dict__[self.__class__.__name__]=self
if 'plugin' in self.__class__.__dict__: return self.plugin(owner) if 'plugin' in self.__class__.__dict__: return self.plugin(owner)
def PlugOut(self): def PlugOut(self):
""" Unregister all our staff from main instance and detach from it. """ """ Unregister all our staff from main instance and detach from it. """
self.DEBUG('Plugging %s out of %s.'%(self,self._owner),'stop') self.DEBUG('Plugging %s out of %s.'%(self,self._owner),'stop')
@ -93,7 +93,7 @@ class CommonClient:
""" Caches server name and (optionally) port to connect to. "debug" parameter specifies """ Caches server name and (optionally) port to connect to. "debug" parameter specifies
the debug IDs that will go into debug output. You can either specifiy an "include" the debug IDs that will go into debug output. You can either specifiy an "include"
or "exclude" list. The latter is done via adding "always" pseudo-ID to the list. or "exclude" list. The latter is done via adding "always" pseudo-ID to the list.
Full list: ['nodebuilder', 'dispatcher', 'gen_auth', 'SASL_auth', 'bind', 'socket', Full list: ['nodebuilder', 'dispatcher', 'gen_auth', 'SASL_auth', 'bind', 'socket',
'CONNECTproxy', 'TLS', 'roster', 'browser', 'ibb'] . """ 'CONNECTproxy', 'TLS', 'roster', 'browser', 'ibb'] . """
if self.__class__.__name__=='Client': self.Namespace,self.DBG='jabber:client',DBG_CLIENT if self.__class__.__name__=='Client': self.Namespace,self.DBG='jabber:client',DBG_CLIENT
elif self.__class__.__name__=='Component': self.Namespace,self.DBG=dispatcher.NS_COMPONENT_ACCEPT,DBG_COMPONENT elif self.__class__.__name__=='Component': self.Namespace,self.DBG=dispatcher.NS_COMPONENT_ACCEPT,DBG_COMPONENT
@ -161,7 +161,7 @@ class CommonClient:
return self.connected return self.connected
def get_peerhost(self): def get_peerhost(self):
''' get the ip address of the account, from which is made connection ''' get the ip address of the account, from which is made connection
to the server , (e.g. me). to the server , (e.g. me).
We will create listening socket on the same ip ''' We will create listening socket on the same ip '''
if hasattr(self, 'Connection'): if hasattr(self, 'Connection'):
@ -174,7 +174,7 @@ class CommonClient:
if proxy: socket=transports.HTTPPROXYsocket(proxy,server,use_srv) if proxy: socket=transports.HTTPPROXYsocket(proxy,server,use_srv)
else: socket=transports.TCPsocket(server,use_srv) else: socket=transports.TCPsocket(server,use_srv)
connected=socket.PlugIn(self) connected=socket.PlugIn(self)
if not connected: if not connected:
socket.PlugOut() socket.PlugOut()
return return
self._Server,self._Proxy=server,proxy self._Server,self._Proxy=server,proxy
@ -196,7 +196,7 @@ class Client(CommonClient):
""" Example client class, based on CommonClient. """ """ Example client class, based on CommonClient. """
def connect(self,server=None,proxy=None,secure=None,use_srv=True): def connect(self,server=None,proxy=None,secure=None,use_srv=True):
""" Connect to jabber server. If you want to specify different ip/port to connect to you can """ Connect to jabber server. If you want to specify different ip/port to connect to you can
pass it as tuple as first parameter. If there is HTTP proxy between you and server pass it as tuple as first parameter. If there is HTTP proxy between you and server
specify it's address and credentials (if needed) in the second argument. specify it's address and credentials (if needed) in the second argument.
If you want ssl/tls support to be discovered and enable automatically - leave third argument as None. (ssl will be autodetected only if port is 5223 or 443) If you want ssl/tls support to be discovered and enable automatically - leave third argument as None. (ssl will be autodetected only if port is 5223 or 443)
If you want to force SSL start (i.e. if port 5223 or 443 is remapped to some non-standard port) then set it to 1. If you want to force SSL start (i.e. if port 5223 or 443 is remapped to some non-standard port) then set it to 1.
@ -265,7 +265,7 @@ class Component(CommonClient):
Jabberd1.4 and Ejabberd use the default namespace then for all client messages. Jabberd1.4 and Ejabberd use the default namespace then for all client messages.
Jabberd2 uses jabber:client. Jabberd2 uses jabber:client.
'server' argument is a server name that you are connecting to (f.e. "localhost"). 'server' argument is a server name that you are connecting to (f.e. "localhost").
'port' can be specified if 'server' resolves to correct IP. If it is not then you'll need to specify IP 'port' can be specified if 'server' resolves to correct IP. If it is not then you'll need to specify IP
and port while calling "connect()".""" and port while calling "connect()"."""
CommonClient.__init__(self,server,port=port,debug=debug) CommonClient.__init__(self,server,port=port,debug=debug)
self.typ=typ self.typ=typ
@ -274,7 +274,7 @@ class Component(CommonClient):
self.domains=domains self.domains=domains
else: else:
self.domains=[server] self.domains=[server]
def connect(self,server=None,proxy=None): def connect(self,server=None,proxy=None):
""" This will connect to the server, and if the features tag is found then set """ This will connect to the server, and if the features tag is found then set
the namespace to be jabber:client as that is required for jabberd2. the namespace to be jabber:client as that is required for jabberd2.

View file

@ -28,28 +28,28 @@ from client import *
class NBCommonClient(CommonClient): class NBCommonClient(CommonClient):
''' Base for Client and Component classes.''' ''' Base for Client and Component classes.'''
def __init__(self, server, port=5222, debug=['always', 'nodebuilder'], caller=None, def __init__(self, server, port=5222, debug=['always', 'nodebuilder'], caller=None,
on_connect=None, on_proxy_failure=None, on_connect_failure=None): on_connect=None, on_proxy_failure=None, on_connect_failure=None):
''' Caches server name and (optionally) port to connect to. "debug" parameter specifies ''' Caches server name and (optionally) port to connect to. "debug" parameter specifies
the debug IDs that will go into debug output. You can either specifiy an "include" the debug IDs that will go into debug output. You can either specifiy an "include"
or "exclude" list. The latter is done via adding "always" pseudo-ID to the list. or "exclude" list. The latter is done via adding "always" pseudo-ID to the list.
Full list: ['nodebuilder', 'dispatcher', 'gen_auth', 'SASL_auth', 'bind', 'socket', Full list: ['nodebuilder', 'dispatcher', 'gen_auth', 'SASL_auth', 'bind', 'socket',
'CONNECTproxy', 'TLS', 'roster', 'browser', 'ibb'] . ''' 'CONNECTproxy', 'TLS', 'roster', 'browser', 'ibb'] . '''
if isinstance(self, NonBlockingClient): if isinstance(self, NonBlockingClient):
self.Namespace, self.DBG = 'jabber:client', DBG_CLIENT self.Namespace, self.DBG = 'jabber:client', DBG_CLIENT
elif isinstance(self, NBCommonClient): elif isinstance(self, NBCommonClient):
self.Namespace, self.DBG = dispatcher_nb.NS_COMPONENT_ACCEPT, DBG_COMPONENT self.Namespace, self.DBG = dispatcher_nb.NS_COMPONENT_ACCEPT, DBG_COMPONENT
self.defaultNamespace = self.Namespace self.defaultNamespace = self.Namespace
self.disconnect_handlers = [] self.disconnect_handlers = []
self.Server = server self.Server = server
self.Port = port self.Port = port
# Who initiated this client # Who initiated this client
# Used to register the EventDispatcher # Used to register the EventDispatcher
self._caller = caller self._caller = caller
if debug and not isinstance(debug, list): if debug and not isinstance(debug, list):
debug = ['always', 'nodebuilder'] debug = ['always', 'nodebuilder']
self._DEBUG = Debug.Debug(debug) self._DEBUG = Debug.Debug(debug)
self.DEBUG = self._DEBUG.Show self.DEBUG = self._DEBUG.Show
@ -64,10 +64,10 @@ class NBCommonClient(CommonClient):
self.on_connect = on_connect self.on_connect = on_connect
self.on_proxy_failure = on_proxy_failure self.on_proxy_failure = on_proxy_failure
self.on_connect_failure = on_connect_failure self.on_connect_failure = on_connect_failure
def set_idlequeue(self, idlequeue): def set_idlequeue(self, idlequeue):
self.idlequeue = idlequeue self.idlequeue = idlequeue
def disconnected(self): def disconnected(self):
''' Called on disconnection. Calls disconnect handlers and cleans things up. ''' ''' Called on disconnection. Calls disconnect handlers and cleans things up. '''
self.connected='' self.connected=''
@ -90,15 +90,15 @@ class NBCommonClient(CommonClient):
self.NBSOCKS5PROXYsocket.PlugOut() self.NBSOCKS5PROXYsocket.PlugOut()
if 'NonBlockingTcp' in self.__dict__: if 'NonBlockingTcp' in self.__dict__:
self.NonBlockingTcp.PlugOut() self.NonBlockingTcp.PlugOut()
def reconnectAndReauth(self): def reconnectAndReauth(self):
''' Just disconnect. We do reconnecting in connection.py ''' ''' Just disconnect. We do reconnecting in connection.py '''
self.disconnect() self.disconnect()
return '' return ''
def connect(self,server=None,proxy=None, ssl=None, on_stream_start = None): def connect(self,server=None,proxy=None, ssl=None, on_stream_start = None):
''' Make a tcp/ip connection, protect it with tls/ssl if possible and start XMPP stream. ''' ''' Make a tcp/ip connection, protect it with tls/ssl if possible and start XMPP stream. '''
if not server: if not server:
server = (self.Server, self.Port) server = (self.Server, self.Port)
self._Server, self._Proxy, self._Ssl = server , proxy, ssl self._Server, self._Proxy, self._Ssl = server , proxy, ssl
self.on_stream_start = on_stream_start self.on_stream_start = on_stream_start
@ -117,22 +117,22 @@ class NBCommonClient(CommonClient):
self.socket = transports_nb.NBHTTPPROXYsocket(self._on_connected, self.socket = transports_nb.NBHTTPPROXYsocket(self._on_connected,
self._on_proxy_failure, self._on_connected_failure, proxy, self._on_proxy_failure, self._on_connected_failure, proxy,
server) server)
else: else:
self.connected = 'tcp' self.connected = 'tcp'
self.socket = transports_nb.NonBlockingTcp(self._on_connected, self.socket = transports_nb.NonBlockingTcp(self._on_connected,
self._on_connected_failure, server) self._on_connected_failure, server)
self.socket.PlugIn(self) self.socket.PlugIn(self)
return True return True
def get_attrs(self, on_stream_start): def get_attrs(self, on_stream_start):
self.on_stream_start = on_stream_start self.on_stream_start = on_stream_start
self.onreceive(self._on_receive_document_attrs) self.onreceive(self._on_receive_document_attrs)
def _on_proxy_failure(self, reason): def _on_proxy_failure(self, reason):
if self.on_proxy_failure: if self.on_proxy_failure:
self.on_proxy_failure(reason) self.on_proxy_failure(reason)
def _on_connected_failure(self, retry = None): def _on_connected_failure(self, retry = None):
if self.socket: if self.socket:
self.socket.disconnect() self.socket.disconnect()
if self.on_connect_failure: if self.on_connect_failure:
@ -143,7 +143,7 @@ class NBCommonClient(CommonClient):
# in nonblocking mode, and this handler is actually called # in nonblocking mode, and this handler is actually called
# as soon as connection is initiated, NOT when connection # as soon as connection is initiated, NOT when connection
# succeeds, as the name suggests. # succeeds, as the name suggests.
# # connect succeeded, so no need of this callback anymore # # connect succeeded, so no need of this callback anymore
# self.on_connect_failure = None # self.on_connect_failure = None
self.connected = 'tcp' self.connected = 'tcp'
if self._Ssl: if self._Ssl:
@ -153,7 +153,7 @@ class NBCommonClient(CommonClient):
self.connected = 'ssl' self.connected = 'ssl'
self.onreceive(self._on_receive_document_attrs) self.onreceive(self._on_receive_document_attrs)
dispatcher_nb.Dispatcher().PlugIn(self) dispatcher_nb.Dispatcher().PlugIn(self)
def _on_receive_document_attrs(self, data): def _on_receive_document_attrs(self, data):
if data: if data:
self.Dispatcher.ProcessNonBlocking(data) self.Dispatcher.ProcessNonBlocking(data)
@ -169,11 +169,11 @@ class NBCommonClient(CommonClient):
self.on_stream_start() self.on_stream_start()
self.on_stream_start = None self.on_stream_start = None
return True return True
def _on_receive_stream_features(self, data): def _on_receive_stream_features(self, data):
if data: if data:
self.Dispatcher.ProcessNonBlocking(data) self.Dispatcher.ProcessNonBlocking(data)
if not self.Dispatcher.Stream.features: if not self.Dispatcher.Stream.features:
return return
# pass # If we get version 1.0 stream the features tag MUST BE presented # pass # If we get version 1.0 stream the features tag MUST BE presented
self.onreceive(None) self.onreceive(None)
@ -181,12 +181,12 @@ class NBCommonClient(CommonClient):
self.on_stream_start() self.on_stream_start()
self.on_stream_start = None self.on_stream_start = None
return True return True
class NonBlockingClient(NBCommonClient): class NonBlockingClient(NBCommonClient):
''' Example client class, based on CommonClient. ''' ''' Example client class, based on CommonClient. '''
def connect(self,server=None,proxy=None,secure=None,use_srv=True): def connect(self,server=None,proxy=None,secure=None,use_srv=True):
''' Connect to jabber server. If you want to specify different ip/port to connect to you can ''' Connect to jabber server. If you want to specify different ip/port to connect to you can
pass it as tuple as first parameter. If there is HTTP proxy between you and server pass it as tuple as first parameter. If there is HTTP proxy between you and server
specify it's address and credentials (if needed) in the second argument. specify it's address and credentials (if needed) in the second argument.
If you want ssl/tls support to be discovered and enable automatically - leave third argument as None. (ssl will be autodetected only if port is 5223 or 443) If you want ssl/tls support to be discovered and enable automatically - leave third argument as None. (ssl will be autodetected only if port is 5223 or 443)
If you want to force SSL start (i.e. if port 5223 or 443 is remapped to some non-standard port) then set it to 1. If you want to force SSL start (i.e. if port 5223 or 443 is remapped to some non-standard port) then set it to 1.
@ -195,18 +195,18 @@ class NonBlockingClient(NBCommonClient):
Returns '' or 'tcp' or 'tls', depending on the result.''' Returns '' or 'tcp' or 'tls', depending on the result.'''
self.__secure = secure self.__secure = secure
self.Connection = None self.Connection = None
NBCommonClient.connect(self, server = server, proxy = proxy, ssl = secure, NBCommonClient.connect(self, server = server, proxy = proxy, ssl = secure,
on_stream_start = self._on_tcp_stream_start) on_stream_start = self._on_tcp_stream_start)
return self.connected return self.connected
def _is_connected(self): def _is_connected(self):
self.onreceive(None) self.onreceive(None)
if self.on_connect: if self.on_connect:
self.on_connect(self, self.connected) self.on_connect(self, self.connected)
self.on_connect_failure = None self.on_connect_failure = None
self.on_connect = None self.on_connect = None
def _on_tcp_stream_start(self): def _on_tcp_stream_start(self):
if not self.connected or self.__secure is not None and not self.__secure: if not self.connected or self.__secure is not None and not self.__secure:
self._is_connected() self._is_connected()
@ -217,12 +217,12 @@ class NonBlockingClient(NBCommonClient):
if not self.Connection: # ssl error, stream is closed if not self.Connection: # ssl error, stream is closed
return True return True
if 'version' not in self.Dispatcher.Stream._document_attrs or \ if 'version' not in self.Dispatcher.Stream._document_attrs or \
not self.Dispatcher.Stream._document_attrs['version']=='1.0': not self.Dispatcher.Stream._document_attrs['version']=='1.0':
self._is_connected() self._is_connected()
return return
if not self.Dispatcher.Stream.features.getTag('starttls'): if not self.Dispatcher.Stream.features.getTag('starttls'):
self._is_connected() self._is_connected()
return return
self.onreceive(self._on_receive_starttls) self.onreceive(self._on_receive_starttls)
def _on_receive_starttls(self, data): def _on_receive_starttls(self, data):
@ -231,7 +231,7 @@ class NonBlockingClient(NBCommonClient):
if not self.NonBlockingTLS.starttls: if not self.NonBlockingTLS.starttls:
return return
self.onreceive(None) self.onreceive(None)
if not hasattr(self, 'NonBlockingTLS') or self.NonBlockingTLS.starttls != 'success': if not hasattr(self, 'NonBlockingTLS') or self.NonBlockingTLS.starttls != 'success':
self.event('tls_failed') self.event('tls_failed')
self._is_connected() self._is_connected()
return return
@ -239,7 +239,7 @@ class NonBlockingClient(NBCommonClient):
self.onreceive(None) self.onreceive(None)
self._is_connected() self._is_connected()
return True return True
def auth(self, user, password, resource = '', sasl = 1, on_auth = None): def auth(self, user, password, resource = '', sasl = 1, on_auth = None):
''' Authenticate connnection and bind resource. If resource is not provided ''' Authenticate connnection and bind resource. If resource is not provided
random one or library name used. ''' random one or library name used. '''
@ -247,7 +247,7 @@ class NonBlockingClient(NBCommonClient):
self.on_auth = on_auth self.on_auth = on_auth
self.get_attrs(self._on_doc_attrs) self.get_attrs(self._on_doc_attrs)
return return
def _on_old_auth(self, res): def _on_old_auth(self, res):
if res: if res:
self.connected += '+old_auth' self.connected += '+old_auth'
@ -256,27 +256,27 @@ class NonBlockingClient(NBCommonClient):
self.on_auth(self, None) self.on_auth(self, None)
def _on_doc_attrs(self): def _on_doc_attrs(self):
if self._sasl: if self._sasl:
auth_nb.SASL(self._User, self._Password, self._on_start_sasl).PlugIn(self) auth_nb.SASL(self._User, self._Password, self._on_start_sasl).PlugIn(self)
if not self._sasl or self.SASL.startsasl == 'not-supported': if not self._sasl or self.SASL.startsasl == 'not-supported':
if not self._Resource: if not self._Resource:
self._Resource = 'xmpppy' self._Resource = 'xmpppy'
auth_nb.NonBlockingNonSASL(self._User, self._Password, self._Resource, self._on_old_auth).PlugIn(self) auth_nb.NonBlockingNonSASL(self._User, self._Password, self._Resource, self._on_old_auth).PlugIn(self)
return return
self.onreceive(self._on_start_sasl) self.onreceive(self._on_start_sasl)
self.SASL.auth() self.SASL.auth()
return True return True
def _on_start_sasl(self, data=None): def _on_start_sasl(self, data=None):
if data: if data:
self.Dispatcher.ProcessNonBlocking(data) self.Dispatcher.ProcessNonBlocking(data)
if 'SASL' not in self.__dict__: if 'SASL' not in self.__dict__:
# SASL is pluged out, possible disconnect # SASL is pluged out, possible disconnect
return return
if self.SASL.startsasl == 'in-process': if self.SASL.startsasl == 'in-process':
return return
self.onreceive(None) self.onreceive(None)
if self.SASL.startsasl == 'failure': if self.SASL.startsasl == 'failure':
# wrong user/pass, stop auth # wrong user/pass, stop auth
self.connected = None self.connected = None
self._on_sasl_auth(None) self._on_sasl_auth(None)
@ -285,16 +285,16 @@ class NonBlockingClient(NBCommonClient):
auth_nb.NonBlockingBind().PlugIn(self) auth_nb.NonBlockingBind().PlugIn(self)
self.onreceive(self._on_auth_bind) self.onreceive(self._on_auth_bind)
return True return True
def _on_auth_bind(self, data): def _on_auth_bind(self, data):
if data: if data:
self.Dispatcher.ProcessNonBlocking(data) self.Dispatcher.ProcessNonBlocking(data)
if not hasattr(self, 'NonBlockingBind') or self.NonBlockingBind.bound is \ if not hasattr(self, 'NonBlockingBind') or self.NonBlockingBind.bound is \
None: None:
return return
self.NonBlockingBind.NonBlockingBind(self._Resource, self._on_sasl_auth) self.NonBlockingBind.NonBlockingBind(self._Resource, self._on_sasl_auth)
return True return True
def _on_sasl_auth(self, res): def _on_sasl_auth(self, res):
self.onreceive(None) self.onreceive(None)
if res: if res:
@ -302,10 +302,10 @@ class NonBlockingClient(NBCommonClient):
self.on_auth(self, 'sasl') self.on_auth(self, 'sasl')
else: else:
self.on_auth(self, None) self.on_auth(self, None)
def initRoster(self): def initRoster(self):
''' Plug in the roster. ''' ''' Plug in the roster. '''
if 'NonBlockingRoster' not in self.__dict__: if 'NonBlockingRoster' not in self.__dict__:
roster_nb.NonBlockingRoster().PlugIn(self) roster_nb.NonBlockingRoster().PlugIn(self)
def getRoster(self, on_ready = None): def getRoster(self, on_ready = None):
@ -330,7 +330,7 @@ class Component(NBCommonClient):
Jabberd1.4 and Ejabberd use the default namespace then for all client messages. Jabberd1.4 and Ejabberd use the default namespace then for all client messages.
Jabberd2 uses jabber:client. Jabberd2 uses jabber:client.
'server' argument is a server name that you are connecting to (f.e. "localhost"). 'server' argument is a server name that you are connecting to (f.e. "localhost").
'port' can be specified if 'server' resolves to correct IP. If it is not then you'll need to specify IP 'port' can be specified if 'server' resolves to correct IP. If it is not then you'll need to specify IP
and port while calling "connect()".''' and port while calling "connect()".'''
NBCommonClient.__init__(self, server, port=port, debug=debug) NBCommonClient.__init__(self, server, port=port, debug=debug)
self.typ = typ self.typ = typ
@ -341,7 +341,7 @@ class Component(NBCommonClient):
self.domains=[server] self.domains=[server]
self.on_connect_component = on_connect self.on_connect_component = on_connect
self.on_connect_failure = on_connect_failure self.on_connect_failure = on_connect_failure
def connect(self, server=None, proxy=None): def connect(self, server=None, proxy=None):
''' This will connect to the server, and if the features tag is found then set ''' This will connect to the server, and if the features tag is found then set
the namespace to be jabber:client as that is required for jabberd2. the namespace to be jabber:client as that is required for jabberd2.
@ -349,9 +349,9 @@ class Component(NBCommonClient):
if self.component: if self.component:
self.Namespace=auth.NS_COMPONENT_1 self.Namespace=auth.NS_COMPONENT_1
self.Server=server[0] self.Server=server[0]
NBCommonClient.connect(self, server=server, proxy=proxy, NBCommonClient.connect(self, server=server, proxy=proxy,
on_connect = self._on_connect, on_connect_failure = self.on_connect_failure) on_connect = self._on_connect, on_connect_failure = self.on_connect_failure)
def _on_connect(self): def _on_connect(self):
if self.typ=='jabberd2' or not self.typ and self.Dispatcher.Stream.features is not None: if self.typ=='jabberd2' or not self.typ and self.Dispatcher.Stream.features is not None:
self.defaultNamespace=auth.NS_CLIENT self.defaultNamespace=auth.NS_CLIENT
@ -365,9 +365,9 @@ class Component(NBCommonClient):
''' Authenticate component "name" with password "password".''' ''' Authenticate component "name" with password "password".'''
self._User, self._Password, self._Resource=name, password,'' self._User, self._Password, self._Resource=name, password,''
try: try:
if self.component: if self.component:
sasl=1 sasl=1
if sasl: if sasl:
auth.SASL(name,password).PlugIn(self) auth.SASL(name,password).PlugIn(self)
if not sasl or self.SASL.startsasl=='not-supported': if not sasl or self.SASL.startsasl=='not-supported':
if auth.NonSASL(name,password,'').PlugIn(self): if auth.NonSASL(name,password,'').PlugIn(self):
@ -378,11 +378,11 @@ class Component(NBCommonClient):
self.onreceive(self._on_auth_component) self.onreceive(self._on_auth_component)
except Exception: except Exception:
self.DEBUG(self.DBG,"Failed to authenticate %s" % name,'error') self.DEBUG(self.DBG,"Failed to authenticate %s" % name,'error')
def _on_auth_component(self, data): def _on_auth_component(self, data):
if data: if data:
self.Dispatcher.ProcessNonBlocking(data) self.Dispatcher.ProcessNonBlocking(data)
if self.SASL.startsasl == 'in-process': if self.SASL.startsasl == 'in-process':
return return
if self.SASL.startsasl =='success': if self.SASL.startsasl =='success':
if self.component: if self.component:
@ -392,18 +392,18 @@ class Component(NBCommonClient):
self.connected += '+sasl' self.connected += '+sasl'
else: else:
raise auth.NotAuthorized(self.SASL.startsasl) raise auth.NotAuthorized(self.SASL.startsasl)
def _on_component_bind(self, data): def _on_component_bind(self, data):
if data: if data:
self.Dispatcher.ProcessNonBlocking(data) self.Dispatcher.ProcessNonBlocking(data)
if self.NBComponentBind.bound is None: if self.NBComponentBind.bound is None:
return return
for domain in self.domains: for domain in self.domains:
self.NBComponentBind.Bind(domain, _on_component_bound) self.NBComponentBind.Bind(domain, _on_component_bound)
def _on_component_bound(self, resp): def _on_component_bound(self, resp):
self.NBComponentBind.PlugOut() self.NBComponentBind.PlugOut()
# vim: se ts=3: # vim: se ts=3:

View file

@ -19,13 +19,13 @@
There are 3 classes here, a command processor Commands like the Browser, and a command template plugin Command, and an example command. There are 3 classes here, a command processor Commands like the Browser, and a command template plugin Command, and an example command.
To use this module: To use this module:
Instansiate the module with the parent transport and disco browser manager as parameters. Instansiate the module with the parent transport and disco browser manager as parameters.
'Plug in' commands using the command template. 'Plug in' commands using the command template.
The command feature must be added to existing disco replies where neccessary. The command feature must be added to existing disco replies where neccessary.
What it supplies: What it supplies:
Automatic command registration with the disco browser manager. Automatic command registration with the disco browser manager.
Automatic listing of commands in the public command list. Automatic listing of commands in the public command list.
A means of handling requests, by redirection though the command manager. A means of handling requests, by redirection though the command manager.
@ -39,9 +39,9 @@ DBG_COMMANDS = 'commands'
class Commands(PlugIn): class Commands(PlugIn):
"""Commands is an ancestor of PlugIn and can be attached to any session. """Commands is an ancestor of PlugIn and can be attached to any session.
The commands class provides a lookup and browse mechnism. It follows the same priciple of the Browser class, for Service Discovery to provide the list of commands, it adds the 'list' disco type to your existing disco handler function. The commands class provides a lookup and browse mechnism. It follows the same priciple of the Browser class, for Service Discovery to provide the list of commands, it adds the 'list' disco type to your existing disco handler function.
How it works: How it works:
The commands are added into the existing Browser on the correct nodes. When the command list is built the supplied discovery handler function needs to have a 'list' option in type. This then gets enumerated, all results returned as None are ignored. The commands are added into the existing Browser on the correct nodes. When the command list is built the supplied discovery handler function needs to have a 'list' option in type. This then gets enumerated, all results returned as None are ignored.
The command executed is then called using it's Execute method. All session management is handled by the command itself. The command executed is then called using it's Execute method. All session management is handled by the command itself.
@ -53,7 +53,7 @@ class Commands(PlugIn):
self._exported_methods=[] self._exported_methods=[]
self._handlers={'':{}} self._handlers={'':{}}
self._browser = browser self._browser = browser
def plugin(self, owner): def plugin(self, owner):
"""Makes handlers within the session""" """Makes handlers within the session"""
# Plug into the session and the disco manager # Plug into the session and the disco manager
@ -61,15 +61,15 @@ class Commands(PlugIn):
owner.RegisterHandler('iq',self._CommandHandler,typ='set',ns=NS_COMMANDS) owner.RegisterHandler('iq',self._CommandHandler,typ='set',ns=NS_COMMANDS)
owner.RegisterHandler('iq',self._CommandHandler,typ='get',ns=NS_COMMANDS) owner.RegisterHandler('iq',self._CommandHandler,typ='get',ns=NS_COMMANDS)
self._browser.setDiscoHandler(self._DiscoHandler,node=NS_COMMANDS,jid='') self._browser.setDiscoHandler(self._DiscoHandler,node=NS_COMMANDS,jid='')
owner.debug_flags.append(DBG_COMMANDS) owner.debug_flags.append(DBG_COMMANDS)
def plugout(self): def plugout(self):
"""Removes handlers from the session""" """Removes handlers from the session"""
# unPlug from the session and the disco manager # unPlug from the session and the disco manager
self._owner.UnregisterHandler('iq',self._CommandHandler,ns=NS_COMMANDS) self._owner.UnregisterHandler('iq',self._CommandHandler,ns=NS_COMMANDS)
for jid in self._handlers: for jid in self._handlers:
self._browser.delDiscoHandler(self._DiscoHandler,node=NS_COMMANDS,jid=jid) self._browser.delDiscoHandler(self._DiscoHandler,node=NS_COMMANDS,jid=jid)
def _CommandHandler(self,conn,request): def _CommandHandler(self,conn,request):
"""The internal method to process the routing of command execution requests""" """The internal method to process the routing of command execution requests"""
# This is the command handler itself. # This is the command handler itself.
@ -93,7 +93,7 @@ class Commands(PlugIn):
else: else:
conn.send(Error(request,ERR_ITEM_NOT_FOUND)) conn.send(Error(request,ERR_ITEM_NOT_FOUND))
raise NodeProcessed raise NodeProcessed
def _DiscoHandler(self,conn,request,typ): def _DiscoHandler(self,conn,request,typ):
"""The internal method to process service discovery requests""" """The internal method to process service discovery requests"""
# This is the disco manager handler. # This is the disco manager handler.
@ -130,7 +130,7 @@ class Commands(PlugIn):
raise NodeProcessed raise NodeProcessed
elif typ == 'info': elif typ == 'info':
return {'ids':[{'category':'automation','type':'command-list'}],'features':[]} return {'ids':[{'category':'automation','type':'command-list'}],'features':[]}
def addCommand(self,name,cmddisco,cmdexecute,jid=''): def addCommand(self,name,cmddisco,cmdexecute,jid=''):
"""The method to call if adding a new command to the session, the requred parameters of cmddisco and cmdexecute are the methods to enable that command to be executed""" """The method to call if adding a new command to the session, the requred parameters of cmddisco and cmdexecute are the methods to enable that command to be executed"""
# This command takes a command object and the name of the command for registration # This command takes a command object and the name of the command for registration
@ -146,7 +146,7 @@ class Commands(PlugIn):
self._handlers[jid][name]={'disco':cmddisco,'execute':cmdexecute} self._handlers[jid][name]={'disco':cmddisco,'execute':cmdexecute}
# Need to add disco stuff here # Need to add disco stuff here
self._browser.setDiscoHandler(cmddisco,node=name,jid=jid) self._browser.setDiscoHandler(cmddisco,node=name,jid=jid)
def delCommand(self,name,jid=''): def delCommand(self,name,jid=''):
"""Removed command from the session""" """Removed command from the session"""
# This command takes a command object and the name used for registration # This command takes a command object and the name used for registration
@ -162,7 +162,7 @@ class Commands(PlugIn):
command = self.getCommand(name,jid)['disco'] command = self.getCommand(name,jid)['disco']
del self._handlers[jid][name] del self._handlers[jid][name]
self._browser.delDiscoHandler(command,node=name,jid=jid) self._browser.delDiscoHandler(command,node=name,jid=jid)
def getCommand(self,name,jid=''): def getCommand(self,name,jid=''):
"""Returns the command tuple""" """Returns the command tuple"""
# This gets the command object with name # This gets the command object with name
@ -174,19 +174,19 @@ class Commands(PlugIn):
raise NameError,'Command not found' raise NameError,'Command not found'
else: else:
return self._handlers[jid][name] return self._handlers[jid][name]
class Command_Handler_Prototype(PlugIn): class Command_Handler_Prototype(PlugIn):
"""This is a prototype command handler, as each command uses a disco method """This is a prototype command handler, as each command uses a disco method
and execute method you can implement it any way you like, however this is and execute method you can implement it any way you like, however this is
my first attempt at making a generic handler that you can hang process my first attempt at making a generic handler that you can hang process
stages on too. There is an example command below. stages on too. There is an example command below.
The parameters are as follows: The parameters are as follows:
name : the name of the command within the jabber environment name : the name of the command within the jabber environment
description : the natural language description description : the natural language description
discofeatures : the features supported by the command discofeatures : the features supported by the command
initial : the initial command in the from of {'execute':commandname} initial : the initial command in the from of {'execute':commandname}
All stages set the 'actions' dictionary for each session to represent the possible options available. All stages set the 'actions' dictionary for each session to represent the possible options available.
""" """
name = 'examplecommand' name = 'examplecommand'
@ -203,14 +203,14 @@ class Command_Handler_Prototype(PlugIn):
# Disco information for command list pre-formatted as a tuple # Disco information for command list pre-formatted as a tuple
self.discoinfo = {'ids':[{'category':'automation','type':'command-node','name':self.description}],'features': self.discofeatures} self.discoinfo = {'ids':[{'category':'automation','type':'command-node','name':self.description}],'features': self.discofeatures}
self._jid = jid self._jid = jid
def plugin(self,owner): def plugin(self,owner):
"""Plug command into the commands class""" """Plug command into the commands class"""
# The owner in this instance is the Command Processor # The owner in this instance is the Command Processor
self._commands = owner self._commands = owner
self._owner = owner._owner self._owner = owner._owner
self._commands.addCommand(self.name,self._DiscoHandler,self.Execute,jid=self._jid) self._commands.addCommand(self.name,self._DiscoHandler,self.Execute,jid=self._jid)
def plugout(self): def plugout(self):
"""Remove command from the commands class""" """Remove command from the commands class"""
self._commands.delCommand(name,self._jid) self._commands.delCommand(name,self._jid)
@ -219,7 +219,7 @@ class Command_Handler_Prototype(PlugIn):
"""Returns an id for the command session""" """Returns an id for the command session"""
self.count = self.count+1 self.count = self.count+1
return 'cmd-%s-%d'%(self.name,self.count) return 'cmd-%s-%d'%(self.name,self.count)
def Execute(self,conn,request): def Execute(self,conn,request):
"""The method that handles all the commands, and routes them to the correct method for that stage.""" """The method that handles all the commands, and routes them to the correct method for that stage."""
# New request or old? # New request or old?
@ -254,7 +254,7 @@ class Command_Handler_Prototype(PlugIn):
else: else:
# New session # New session
self.initial[action](conn,request) self.initial[action](conn,request)
def _DiscoHandler(self,conn,request,type_): def _DiscoHandler(self,conn,request,type_):
"""The handler for discovery events""" """The handler for discovery events"""
if type_ == 'list': if type_ == 'list':
@ -263,9 +263,9 @@ class Command_Handler_Prototype(PlugIn):
return [] return []
elif type_ == 'info': elif type_ == 'info':
return self.discoinfo return self.discoinfo
class TestCommand(Command_Handler_Prototype): class TestCommand(Command_Handler_Prototype):
""" Example class. You should read source if you wish to understate how it works. """ Example class. You should read source if you wish to understate how it works.
Generally, it presents a "master" that giudes user through to calculate something. Generally, it presents a "master" that giudes user through to calculate something.
""" """
name = 'testcommand' name = 'testcommand'
@ -275,7 +275,7 @@ class TestCommand(Command_Handler_Prototype):
Command_Handler_Prototype.__init__(self,jid) Command_Handler_Prototype.__init__(self,jid)
self.pi = 3.14 self.pi = 3.14
self.initial = {'execute':self.cmdFirstStage} self.initial = {'execute':self.cmdFirstStage}
def cmdFirstStage(self,conn,request): def cmdFirstStage(self,conn,request):
""" Determine """ """ Determine """
# This is the only place this should be repeated as all other stages should have SessionIDs # This is the only place this should be repeated as all other stages should have SessionIDs
@ -300,7 +300,7 @@ class TestCommand(Command_Handler_Prototype):
sessions[request.getTagAttr('command','sessionid')]['actions']={'cancel':self.cmdCancel,None:self.cmdThirdStage,'previous':cmdFirstStage} sessions[request.getTagAttr('command','sessionid')]['actions']={'cancel':self.cmdCancel,None:self.cmdThirdStage,'previous':cmdFirstStage}
# The form generation is split out to another method as it may be called by cmdThirdStage # The form generation is split out to another method as it may be called by cmdThirdStage
self.cmdSecondStageReply(conn,request) self.cmdSecondStageReply(conn,request)
def cmdSecondStageReply(self,conn,request): def cmdSecondStageReply(self,conn,request):
reply = request.buildReply('result') reply = request.buildReply('result')
form = DataForm(title = 'Enter the radius', data=['Enter the radius of the circle (numbers only)',DataField(label='Radius',name='radius',typ='text-single')]) form = DataForm(title = 'Enter the radius', data=['Enter the radius of the circle (numbers only)',DataField(label='Radius',name='radius',typ='text-single')])
@ -308,7 +308,7 @@ class TestCommand(Command_Handler_Prototype):
reply.addChild(name='command',attrs={'xmlns':NS_COMMAND,'node':request.getTagAttr('command','node'),'sessionid':request.getTagAttr('command','sessionid'),'status':'executing'},payload=replypayload) reply.addChild(name='command',attrs={'xmlns':NS_COMMAND,'node':request.getTagAttr('command','node'),'sessionid':request.getTagAttr('command','sessionid'),'status':'executing'},payload=replypayload)
self._owner.send(reply) self._owner.send(reply)
raise NodeProcessed raise NodeProcessed
def cmdThirdStage(self,conn,request): def cmdThirdStage(self,conn,request):
form = DataForm(node = result.getTag(name='command').getTag(name='x',namespace=NS_DATA)) form = DataForm(node = result.getTag(name='command').getTag(name='x',namespace=NS_DATA))
try: try:
@ -324,13 +324,13 @@ class TestCommand(Command_Handler_Prototype):
reply.addChild(name='command',attrs={'xmlns':NS_COMMAND,'node':request.getTagAttr('command','node'),'sessionid':request.getTagAttr('command','sessionid'),'status':'completed'},payload=form) reply.addChild(name='command',attrs={'xmlns':NS_COMMAND,'node':request.getTagAttr('command','node'),'sessionid':request.getTagAttr('command','sessionid'),'status':'completed'},payload=form)
self._owner.send(reply) self._owner.send(reply)
raise NodeProcessed raise NodeProcessed
def cmdCancel(self,conn,request): def cmdCancel(self,conn,request):
reply = request.buildReply('result') reply = request.buildReply('result')
reply.addChild(name='command',attrs={'xmlns':NS_COMMAND,'node':request.getTagAttr('command','node'),'sessionid':request.getTagAttr('command','sessionid'),'status':'cancelled'}) reply.addChild(name='command',attrs={'xmlns':NS_COMMAND,'node':request.getTagAttr('command','node'),'sessionid':request.getTagAttr('command','sessionid'),'status':'cancelled'})
self._owner.send(reply) self._owner.send(reply)
del self.sessions[request.getTagAttr('command','sessionid')] del self.sessions[request.getTagAttr('command','sessionid')]
# vim: se ts=3: # vim: se ts=3:

View file

@ -1,4 +1,4 @@
## debug.py ## debug.py
## ##
## Copyright (C) 2003 Jacob Lundqvist ## Copyright (C) 2003 Jacob Lundqvist
## ##
@ -19,7 +19,7 @@ Other modules can always define extra debug flags for local usage, as long as
they make sure they append them to debug_flags they make sure they append them to debug_flags
Also its always a good thing to prefix local flags with something, to reduce risk Also its always a good thing to prefix local flags with something, to reduce risk
of coliding flags. Nothing breaks if two flags would be identical, but it might of coliding flags. Nothing breaks if two flags would be identical, but it might
activate unintended debugging. activate unintended debugging.
flags can be numeric, but that makes analysing harder, on creation its flags can be numeric, but that makes analysing harder, on creation its
@ -104,12 +104,12 @@ class NoDebug:
pass pass
def active_set( self, active_flags = None ): def active_set( self, active_flags = None ):
return 0 return 0
LINE_FEED = '\n' LINE_FEED = '\n'
class Debug: class Debug:
def __init__( self, def __init__( self,
# #
# active_flags are those that will trigger output # active_flags are those that will trigger output
@ -128,7 +128,7 @@ class Debug:
prefix = 'DEBUG: ', prefix = 'DEBUG: ',
sufix = '\n', sufix = '\n',
# #
# If you want unix style timestamps, # If you want unix style timestamps,
# 0 disables timestamps # 0 disables timestamps
# 1 before prefix, good when prefix is a string # 1 before prefix, good when prefix is a string
# 2 after prefix, good when prefix is a color # 2 after prefix, good when prefix is a color
@ -138,8 +138,8 @@ class Debug:
# flag_show should normaly be of, but can be turned on to get a # flag_show should normaly be of, but can be turned on to get a
# good view of what flags are actually used for calls, # good view of what flags are actually used for calls,
# if it is not None, it should be a string # if it is not None, it should be a string
# flags for current call will be displayed # flags for current call will be displayed
# with flag_show as separator # with flag_show as separator
# recomended values vould be '-' or ':', but any string goes # recomended values vould be '-' or ':', but any string goes
# #
flag_show = None, flag_show = None,
@ -153,14 +153,14 @@ class Debug:
# default is to show welcome if any flags are active # default is to show welcome if any flags are active
welcome = -1 welcome = -1
): ):
self.debug_flags = [] self.debug_flags = []
if welcome == -1: if welcome == -1:
if active_flags and len(active_flags): if active_flags and len(active_flags):
welcome = 1 welcome = 1
else: else:
welcome = 0 welcome = 0
self._remove_dupe_flags() self._remove_dupe_flags()
if log_file: if log_file:
if isinstance(log_file, str): if isinstance(log_file, str):
@ -173,7 +173,7 @@ class Debug:
self._fh = log_file self._fh = log_file
else: else:
self._fh = sys.stdout self._fh = sys.stdout
if time_stamp not in (0,1,2): if time_stamp not in (0,1,2):
raise Exception('Invalid time_stamp param "%s"' % str(time_stamp)) raise Exception('Invalid time_stamp param "%s"' % str(time_stamp))
self.prefix = prefix self.prefix = prefix
@ -206,18 +206,18 @@ class Debug:
flag can be of folowing types: flag can be of folowing types:
None - this msg will always be shown if any debugging is on None - this msg will always be shown if any debugging is on
flag - will be shown if flag is active flag - will be shown if flag is active
(flag1,flag2,,,) - will be shown if any of the given flags (flag1,flag2,,,) - will be shown if any of the given flags
are active are active
if prefix / sufix are not given, default ones from init will be used if prefix / sufix are not given, default ones from init will be used
lf = -1 means strip linefeed if pressent lf = -1 means strip linefeed if pressent
lf = 1 means add linefeed if not pressent lf = 1 means add linefeed if not pressent
""" """
if self.validate_flags: if self.validate_flags:
self._validate_flag( flag ) self._validate_flag( flag )
if not self.is_active(flag): if not self.is_active(flag):
return return
if prefix: if prefix:
@ -241,7 +241,7 @@ class Debug:
) )
else: else:
output = pre output = pre
if self.flag_show: if self.flag_show:
if flag: if flag:
output = '%s%s%s' % ( output, flag, self.flag_show ) output = '%s%s%s' % ( output, flag, self.flag_show )
@ -271,7 +271,7 @@ class Debug:
s=s+c s=s+c
self._fh.write( '%s%s%s' % ( pre, s, suf )) self._fh.write( '%s%s%s' % ( pre, s, suf ))
self._fh.flush() self._fh.flush()
def active_set( self, active_flags = None ): def active_set( self, active_flags = None ):
"returns 1 if any flags where actually set, otherwise 0." "returns 1 if any flags where actually set, otherwise 0."
r = 0 r = 0
@ -285,7 +285,7 @@ class Debug:
if t not in self.debug_flags: if t not in self.debug_flags:
print 'Invalid debugflag given', t print 'Invalid debugflag given', t
ok_flags.append( t ) ok_flags.append( t )
self.active = ok_flags self.active = ok_flags
r = 1 r = 1
else: else:
@ -298,7 +298,7 @@ class Debug:
self.show( '*** please correct your param!' ) self.show( '*** please correct your param!' )
self.show( '*** due to this, full debuging is enabled' ) self.show( '*** due to this, full debuging is enabled' )
self.active = self.debug_flags self.active = self.debug_flags
for f in flags: for f in flags:
s = f.strip() s = f.strip()
ok_flags.append( s ) ok_flags.append( s )
@ -306,15 +306,15 @@ class Debug:
self._remove_dupe_flags() self._remove_dupe_flags()
return r return r
def active_get( self ): def active_get( self ):
"returns currently active flags." "returns currently active flags."
return self.active return self.active
def _as_one_list( self, items ): def _as_one_list( self, items ):
""" init param might contain nested lists, typically from group flags. """ init param might contain nested lists, typically from group flags.
This code organises lst and remves dupes This code organises lst and remves dupes
""" """
if not isinstance(items, (list, tuple)): if not isinstance(items, (list, tuple)):
@ -323,15 +323,15 @@ class Debug:
for l in items: for l in items:
if isinstance(l, list): if isinstance(l, list):
lst2 = self._as_one_list( l ) lst2 = self._as_one_list( l )
for l2 in lst2: for l2 in lst2:
self._append_unique_str(r, l2 ) self._append_unique_str(r, l2 )
elif l is None: elif l is None:
continue continue
else: else:
self._append_unique_str(r, l ) self._append_unique_str(r, l )
return r return r
def _append_unique_str( self, lst, item ): def _append_unique_str( self, lst, item ):
"""filter out any dupes.""" """filter out any dupes."""
if not isinstance(item, str): if not isinstance(item, str):
@ -342,7 +342,7 @@ class Debug:
lst.append( item ) lst.append( item )
return lst return lst
def _validate_flag( self, flags ): def _validate_flag( self, flags ):
'verify that flag is defined.' 'verify that flag is defined.'
if flags: if flags:
@ -353,7 +353,7 @@ class Debug:
def _remove_dupe_flags( self ): def _remove_dupe_flags( self ):
""" """
if multiple instances of Debug is used in same app, if multiple instances of Debug is used in same app,
some flags might be created multiple time, filter out dupes some flags might be created multiple time, filter out dupes
""" """
unique_flags = [] unique_flags = []
@ -371,12 +371,12 @@ class Debug:
if not colors_enabled: prefixcolor='' if not colors_enabled: prefixcolor=''
elif flag in self.colors: prefixcolor=self.colors[flag] elif flag in self.colors: prefixcolor=self.colors[flag]
else: prefixcolor=color_none else: prefixcolor=color_none
if prefix=='error': if prefix=='error':
_exception = sys.exc_info() _exception = sys.exc_info()
if _exception[0]: if _exception[0]:
msg=msg+'\n'+''.join(traceback.format_exception(_exception[0], _exception[1], _exception[2])).rstrip() msg=msg+'\n'+''.join(traceback.format_exception(_exception[0], _exception[1], _exception[2])).rstrip()
prefix= self.prefix+prefixcolor+(flag+' '*12)[:12]+' '+(prefix+' '*6)[:6] prefix= self.prefix+prefixcolor+(flag+' '*12)[:12]+' '+(prefix+' '*6)[:6]
self.show(msg, flag, prefix) self.show(msg, flag, prefix)

View file

@ -17,7 +17,7 @@
""" """
Main xmpppy mechanism. Provides library with methods to assign different handlers Main xmpppy mechanism. Provides library with methods to assign different handlers
to different XMPP stanzas. to different XMPP stanzas.
Contains one tunable attribute: DefaultTimeout (25 seconds by default). It defines time that Contains one tunable attribute: DefaultTimeout (25 seconds by default). It defines time that
Dispatcher.SendAndWaitForResponce method will wait for reply stanza before giving up. Dispatcher.SendAndWaitForResponce method will wait for reply stanza before giving up.
""" """
@ -135,7 +135,7 @@ class Dispatcher(PlugIn):
raise _pendingException[0], _pendingException[1], _pendingException[2] raise _pendingException[0], _pendingException[1], _pendingException[2]
return len(data) return len(data)
return '0' # It means that nothing is received but link is alive. return '0' # It means that nothing is received but link is alive.
def RegisterNamespace(self,xmlns,order='info'): def RegisterNamespace(self,xmlns,order='info'):
""" Creates internal structures for newly registered namespace. """ Creates internal structures for newly registered namespace.
You can register handlers for this namespace afterwards. By default one namespace You can register handlers for this namespace afterwards. By default one namespace
@ -235,7 +235,7 @@ class Dispatcher(PlugIn):
def Event(self,realm,event,data): def Event(self,realm,event,data):
""" Raise some event. Takes three arguments: """ Raise some event. Takes three arguments:
1) "realm" - scope of event. Usually a namespace. 1) "realm" - scope of event. Usually a namespace.
2) "event" - the event itself. F.e. "SUCESSFULL SEND". 2) "event" - the event itself. F.e. "SUCESSFULL SEND".
3) data that comes along with event. Depends on event.""" 3) data that comes along with event. Depends on event."""
if self._eventHandler: self._eventHandler(realm,event,data) if self._eventHandler: self._eventHandler(realm,event,data)

View file

@ -19,7 +19,7 @@
''' '''
Main xmpppy mechanism. Provides library with methods to assign different handlers Main xmpppy mechanism. Provides library with methods to assign different handlers
to different XMPP stanzas. to different XMPP stanzas.
Contains one tunable attribute: DefaultTimeout (25 seconds by default). It defines time that Contains one tunable attribute: DefaultTimeout (25 seconds by default). It defines time that
Dispatcher.SendAndWaitForResponce method will wait for reply stanza before giving up. Dispatcher.SendAndWaitForResponce method will wait for reply stanza before giving up.
''' '''
@ -59,7 +59,7 @@ class Dispatcher(PlugIn):
''' Return set of user-registered callbacks in it's internal format. ''' Return set of user-registered callbacks in it's internal format.
Used within the library to carry user handlers set over Dispatcher replugins. ''' Used within the library to carry user handlers set over Dispatcher replugins. '''
return self.handlers return self.handlers
def restoreHandlers(self, handlers): def restoreHandlers(self, handlers):
''' Restores user-registered callbacks structure from dump previously obtained via dumpHandlers. ''' Restores user-registered callbacks structure from dump previously obtained via dumpHandlers.
Used within the library to carry user handlers set over Dispatcher replugins. ''' Used within the library to carry user handlers set over Dispatcher replugins. '''
@ -76,7 +76,7 @@ class Dispatcher(PlugIn):
self.RegisterDefaultHandler(self.returnStanzaHandler) self.RegisterDefaultHandler(self.returnStanzaHandler)
self.RegisterEventHandler(self._owner._caller._event_dispatcher) self.RegisterEventHandler(self._owner._caller._event_dispatcher)
self.on_responses = {} self.on_responses = {}
def plugin(self, owner): def plugin(self, owner):
''' Plug the Dispatcher instance into Client class instance and send initial stream header. Used internally.''' ''' Plug the Dispatcher instance into Client class instance and send initial stream header. Used internally.'''
self._init() self._init()
@ -87,7 +87,7 @@ class Dispatcher(PlugIn):
self._owner.StreamInit() self._owner.StreamInit()
else: else:
self.StreamInit() self.StreamInit()
def plugout(self): def plugout(self):
''' Prepares instance to be destructed. ''' ''' Prepares instance to be destructed. '''
self.Stream.dispatch = None self.Stream.dispatch = None
@ -126,7 +126,7 @@ class Dispatcher(PlugIn):
1) length of processed data if some data were processed; 1) length of processed data if some data were processed;
2) '0' string if no data were processed but link is alive; 2) '0' string if no data were processed but link is alive;
3) 0 (zero) if underlying connection is closed.''' 3) 0 (zero) if underlying connection is closed.'''
for handler in self._cycleHandlers: for handler in self._cycleHandlers:
handler(self) handler(self)
if len(self._pendingExceptions) > 0: if len(self._pendingExceptions) > 0:
_pendingException = self._pendingExceptions.pop() _pendingException = self._pendingExceptions.pop()
@ -150,7 +150,7 @@ class Dispatcher(PlugIn):
raise _pendingException[0], _pendingException[1], _pendingException[2] raise _pendingException[0], _pendingException[1], _pendingException[2]
if len(data) == 0: return '0' if len(data) == 0: return '0'
return len(data) return len(data)
def RegisterNamespace(self, xmlns, order='info'): def RegisterNamespace(self, xmlns, order='info'):
''' Creates internal structures for newly registered namespace. ''' Creates internal structures for newly registered namespace.
You can register handlers for this namespace afterwards. By default one namespace You can register handlers for this namespace afterwards. By default one namespace
@ -191,46 +191,46 @@ class Dispatcher(PlugIn):
will be called first nevertheless. will be called first nevertheless.
"system" - call handler even if NodeProcessed Exception were raised already. "system" - call handler even if NodeProcessed Exception were raised already.
''' '''
if not xmlns: if not xmlns:
xmlns=self._owner.defaultNamespace xmlns=self._owner.defaultNamespace
self.DEBUG('Registering handler %s for "%s" type->%s ns->%s(%s)' % self.DEBUG('Registering handler %s for "%s" type->%s ns->%s(%s)' %
(handler, name, typ, ns, xmlns), 'info') (handler, name, typ, ns, xmlns), 'info')
if not typ and not ns: if not typ and not ns:
typ='default' typ='default'
if xmlns not in self.handlers: if xmlns not in self.handlers:
self.RegisterNamespace(xmlns,'warn') self.RegisterNamespace(xmlns,'warn')
if name not in self.handlers[xmlns]: if name not in self.handlers[xmlns]:
self.RegisterProtocol(name,Protocol,xmlns,'warn') self.RegisterProtocol(name,Protocol,xmlns,'warn')
if typ+ns not in self.handlers[xmlns][name]: if typ+ns not in self.handlers[xmlns][name]:
self.handlers[xmlns][name][typ+ns]=[] self.handlers[xmlns][name][typ+ns]=[]
if makefirst: if makefirst:
self.handlers[xmlns][name][typ+ns].insert(0,{'func':handler,'system':system}) self.handlers[xmlns][name][typ+ns].insert(0,{'func':handler,'system':system})
else: else:
self.handlers[xmlns][name][typ+ns].append({'func':handler,'system':system}) self.handlers[xmlns][name][typ+ns].append({'func':handler,'system':system})
def RegisterHandlerOnce(self,name,handler,typ='',ns='',xmlns=None,makefirst=0, system=0): def RegisterHandlerOnce(self,name,handler,typ='',ns='',xmlns=None,makefirst=0, system=0):
''' Unregister handler after first call (not implemented yet). ''' ''' Unregister handler after first call (not implemented yet). '''
if not xmlns: if not xmlns:
xmlns=self._owner.defaultNamespace xmlns=self._owner.defaultNamespace
self.RegisterHandler(name, handler, typ, ns, xmlns, makefirst, system) self.RegisterHandler(name, handler, typ, ns, xmlns, makefirst, system)
def UnregisterHandler(self, name, handler, typ='', ns='', xmlns=None): def UnregisterHandler(self, name, handler, typ='', ns='', xmlns=None):
''' Unregister handler. "typ" and "ns" must be specified exactly the same as with registering.''' ''' Unregister handler. "typ" and "ns" must be specified exactly the same as with registering.'''
if not xmlns: if not xmlns:
xmlns=self._owner.defaultNamespace xmlns=self._owner.defaultNamespace
if not typ and not ns: if not typ and not ns:
typ='default' typ='default'
if xmlns not in self.handlers: if xmlns not in self.handlers:
return return
if name not in self.handlers[xmlns]: if name not in self.handlers[xmlns]:
return return
if typ+ns not in self.handlers[xmlns][name]: if typ+ns not in self.handlers[xmlns][name]:
return return
for pack in self.handlers[xmlns][name][typ+ns]: for pack in self.handlers[xmlns][name][typ+ns]:
if pack['func'] == handler: if pack['func'] == handler:
try: try:
self.handlers[xmlns][name][typ+ns].remove(pack) self.handlers[xmlns][name][typ+ns].remove(pack)
except ValueError: except ValueError:
pass pass
def RegisterDefaultHandler(self,handler): def RegisterDefaultHandler(self,handler):
@ -251,29 +251,29 @@ class Dispatcher(PlugIn):
name,text='error',error.getData() name,text='error',error.getData()
for tag in error.getChildren(): for tag in error.getChildren():
if tag.getNamespace()==NS_XMPP_STREAMS: if tag.getNamespace()==NS_XMPP_STREAMS:
if tag.getName()=='text': if tag.getName()=='text':
text=tag.getData() text=tag.getData()
else: else:
name=tag.getName() name=tag.getName()
if name in stream_exceptions.keys(): if name in stream_exceptions.keys():
exc=stream_exceptions[name] exc=stream_exceptions[name]
else: else:
exc=StreamError exc=StreamError
raise exc((name,text)) raise exc((name,text))
def RegisterCycleHandler(self, handler): def RegisterCycleHandler(self, handler):
''' Register handler that will be called on every Dispatcher.Process() call. ''' ''' Register handler that will be called on every Dispatcher.Process() call. '''
if handler not in self._cycleHandlers: if handler not in self._cycleHandlers:
self._cycleHandlers.append(handler) self._cycleHandlers.append(handler)
def UnregisterCycleHandler(self, handler): def UnregisterCycleHandler(self, handler):
''' Unregister handler that will is called on every Dispatcher.Process() call.''' ''' Unregister handler that will is called on every Dispatcher.Process() call.'''
if handler in self._cycleHandlers: if handler in self._cycleHandlers:
self._cycleHandlers.remove(handler) self._cycleHandlers.remove(handler)
def Event(self, realm, event, data): def Event(self, realm, event, data):
''' Raise some event. Takes three arguments: ''' Raise some event. Takes three arguments:
1) "realm" - scope of event. Usually a namespace. 1) "realm" - scope of event. Usually a namespace.
2) "event" - the event itself. F.e. "SUCESSFULL SEND". 2) "event" - the event itself. F.e. "SUCESSFULL SEND".
3) data that comes along with event. Depends on event.''' 3) data that comes along with event. Depends on event.'''
if self._eventHandler: self._eventHandler(realm,event,data) if self._eventHandler: self._eventHandler(realm,event,data)
@ -281,7 +281,7 @@ class Dispatcher(PlugIn):
def dispatch(self, stanza, session=None, direct=0): def dispatch(self, stanza, session=None, direct=0):
''' Main procedure that performs XMPP stanza recognition and calling apppropriate handlers for it. ''' Main procedure that performs XMPP stanza recognition and calling apppropriate handlers for it.
Called internally. ''' Called internally. '''
if not session: if not session:
session = self session = self
session.Stream._mini_dom = None session.Stream._mini_dom = None
name = stanza.getName() name = stanza.getName()
@ -302,10 +302,10 @@ class Dispatcher(PlugIn):
pass pass
else: else:
raise UnsupportedStanzaType(name) raise UnsupportedStanzaType(name)
if name=='features': if name=='features':
session.Stream.features=stanza session.Stream.features=stanza
xmlns=stanza.getNamespace() xmlns=stanza.getNamespace()
if xmlns not in self.handlers: if xmlns not in self.handlers:
self.DEBUG("Unknown namespace: " + xmlns, 'warn') self.DEBUG("Unknown namespace: " + xmlns, 'warn')
@ -316,38 +316,38 @@ class Dispatcher(PlugIn):
else: else:
self.DEBUG("Got %s/%s stanza" % (xmlns, name), 'ok') self.DEBUG("Got %s/%s stanza" % (xmlns, name), 'ok')
if stanza.__class__.__name__=='Node': if stanza.__class__.__name__=='Node':
stanza=self.handlers[xmlns][name][type](node=stanza) stanza=self.handlers[xmlns][name][type](node=stanza)
typ=stanza.getType() typ=stanza.getType()
if not typ: typ='' if not typ: typ=''
stanza.props=stanza.getProperties() stanza.props=stanza.getProperties()
ID=stanza.getID() ID=stanza.getID()
session.DEBUG("Dispatching %s stanza with type->%s props->%s id->%s"%(name,typ,stanza.props,ID),'ok') session.DEBUG("Dispatching %s stanza with type->%s props->%s id->%s"%(name,typ,stanza.props,ID),'ok')
list_=['default'] # we will use all handlers: list_=['default'] # we will use all handlers:
if typ in self.handlers[xmlns][name]: list_.append(typ) # from very common... if typ in self.handlers[xmlns][name]: list_.append(typ) # from very common...
for prop in stanza.props: for prop in stanza.props:
if prop in self.handlers[xmlns][name]: list_.append(prop) if prop in self.handlers[xmlns][name]: list_.append(prop)
if typ and typ+prop in self.handlers[xmlns][name]: list_.append(typ+prop) # ...to very particular if typ and typ+prop in self.handlers[xmlns][name]: list_.append(typ+prop) # ...to very particular
chain=self.handlers[xmlns]['default']['default'] chain=self.handlers[xmlns]['default']['default']
for key in list_: for key in list_:
if key: chain = chain + self.handlers[xmlns][name][key] if key: chain = chain + self.handlers[xmlns][name][key]
if ID in session._expected: if ID in session._expected:
user=0 user=0
if isinstance(session._expected[ID], tuple): if isinstance(session._expected[ID], tuple):
cb,args = session._expected[ID] cb,args = session._expected[ID]
session.DEBUG("Expected stanza arrived. Callback %s(%s) found!" % (cb, args), 'ok') session.DEBUG("Expected stanza arrived. Callback %s(%s) found!" % (cb, args), 'ok')
try: try:
cb(session,stanza,**args) cb(session,stanza,**args)
except Exception, typ: except Exception, typ:
if typ.__class__.__name__ !='NodeProcessed': raise if typ.__class__.__name__ !='NodeProcessed': raise
else: else:
session.DEBUG("Expected stanza arrived!",'ok') session.DEBUG("Expected stanza arrived!",'ok')
session._expected[ID]=stanza session._expected[ID]=stanza
else: else:
user=1 user=1
for handler in chain: for handler in chain:
if user or handler['system']: if user or handler['system']:
@ -358,9 +358,9 @@ class Dispatcher(PlugIn):
self._pendingExceptions.insert(0, sys.exc_info()) self._pendingExceptions.insert(0, sys.exc_info())
return return
user=0 user=0
if user and self._defaultHandler: if user and self._defaultHandler:
self._defaultHandler(session, stanza) self._defaultHandler(session, stanza)
def WaitForData(self, data): def WaitForData(self, data):
if data is None: if data is None:
return return
@ -382,10 +382,10 @@ class Dispatcher(PlugIn):
else: else:
resp(self._owner, self._expected[self._witid], **args) resp(self._owner, self._expected[self._witid], **args)
del self._expected[i] del self._expected[i]
def SendAndWaitForResponse(self, stanza, timeout=None, func=None, args=None): def SendAndWaitForResponse(self, stanza, timeout=None, func=None, args=None):
''' Put stanza on the wire and wait for recipient's response to it. ''' ''' Put stanza on the wire and wait for recipient's response to it. '''
if timeout is None: if timeout is None:
timeout = DEFAULT_TIMEOUT_SECONDS timeout = DEFAULT_TIMEOUT_SECONDS
self._witid = self.send(stanza) self._witid = self.send(stanza)
if func: if func:
@ -395,27 +395,27 @@ class Dispatcher(PlugIn):
self._owner.onreceive(self.WaitForData) self._owner.onreceive(self.WaitForData)
self._expected[self._witid] = None self._expected[self._witid] = None
return self._witid return self._witid
def SendAndCallForResponse(self, stanza, func=None, args=None): def SendAndCallForResponse(self, stanza, func=None, args=None):
''' Put stanza on the wire and call back when recipient replies. ''' Put stanza on the wire and call back when recipient replies.
Additional callback arguments can be specified in args. ''' Additional callback arguments can be specified in args. '''
self.SendAndWaitForResponse(stanza, 0, func, args) self.SendAndWaitForResponse(stanza, 0, func, args)
def send(self, stanza, is_message = False, now = False): def send(self, stanza, is_message = False, now = False):
''' Serialise stanza and put it on the wire. Assign an unique ID to it before send. ''' Serialise stanza and put it on the wire. Assign an unique ID to it before send.
Returns assigned ID.''' Returns assigned ID.'''
if isinstance(stanza, basestring): if isinstance(stanza, basestring):
return self._owner.Connection.send(stanza, now = now) return self._owner.Connection.send(stanza, now = now)
if not isinstance(stanza, Protocol): if not isinstance(stanza, Protocol):
_ID=None _ID=None
elif not stanza.getID(): elif not stanza.getID():
global ID global ID
ID+=1 ID+=1
_ID=repr(ID) _ID=repr(ID)
stanza.setID(_ID) stanza.setID(_ID)
else: else:
_ID=stanza.getID() _ID=stanza.getID()
if self._owner._registered_name and not stanza.getAttr('from'): if self._owner._registered_name and not stanza.getAttr('from'):
stanza.setAttr('from', self._owner._registered_name) stanza.setAttr('from', self._owner._registered_name)
if self._owner._component and stanza.getName() != 'bind': if self._owner._component and stanza.getName() != 'bind':
to=self._owner.Server to=self._owner.Server
@ -433,7 +433,7 @@ class Dispatcher(PlugIn):
else: else:
self._owner.Connection.send(stanza, now = now) self._owner.Connection.send(stanza, now = now)
return _ID return _ID
def disconnect(self): def disconnect(self):
''' Send a stream terminator. ''' ''' Send a stream terminator. '''
self._owner.Connection.send('</stream:stream>') self._owner.Connection.send('</stream:stream>')

View file

@ -1,4 +1,4 @@
## features.py ## features.py
## ##
## Copyright (C) 2003-2004 Alexey "Snake" Nezhdanov ## Copyright (C) 2003-2004 Alexey "Snake" Nezhdanov
## ##
@ -82,7 +82,7 @@ def discoverInfo(disp,jid,node=None):
def getRegInfo(disp,host,info={},sync=True): def getRegInfo(disp,host,info={},sync=True):
""" Gets registration form from remote host. """ Gets registration form from remote host.
You can pre-fill the info dictionary. You can pre-fill the info dictionary.
F.e. if you are requesting info on registering user joey than specify F.e. if you are requesting info on registering user joey than specify
info as {'username':'joey'}. See JEP-0077 for details. info as {'username':'joey'}. See JEP-0077 for details.
'disp' must be connected dispatcher instance.""" 'disp' must be connected dispatcher instance."""
iq=Iq('get',NS_REGISTER,to=host) iq=Iq('get',NS_REGISTER,to=host)

View file

@ -1,4 +1,4 @@
## features.py ## features.py
## ##
## Copyright (C) 2003-2004 Alexey "Snake" Nezhdanov ## Copyright (C) 2003-2004 Alexey "Snake" Nezhdanov
## Copyright (C) 2007 Julien Pivotto <roidelapluie@gmail.com> ## Copyright (C) 2007 Julien Pivotto <roidelapluie@gmail.com>
@ -20,7 +20,7 @@ from protocol import *
def _on_default_response(disp, iq, cb): def _on_default_response(disp, iq, cb):
def _on_response(resp): def _on_response(resp):
if isResultNode(resp): if isResultNode(resp):
if cb: if cb:
cb(1) cb(1)
elif cb: elif cb:
@ -33,22 +33,22 @@ def _discover(disp, ns, jid, node = None, fb2b=0, fb2a=1, cb=None):
and if it doesnt support browse (or fb2b is not true) fall back to agents protocol and if it doesnt support browse (or fb2b is not true) fall back to agents protocol
(if gb2a is true). Returns obtained info. Used internally. """ (if gb2a is true). Returns obtained info. Used internally. """
iq=Iq(to=jid, typ='get', queryNS=ns) iq=Iq(to=jid, typ='get', queryNS=ns)
if node: if node:
iq.setQuerynode(node) iq.setQuerynode(node)
def _on_resp1(resp): def _on_resp1(resp):
if fb2b and not isResultNode(resp): if fb2b and not isResultNode(resp):
# Fallback to browse # Fallback to browse
disp.SendAndCallForResponse(Iq(to=jid,typ='get',queryNS=NS_BROWSE), _on_resp2) disp.SendAndCallForResponse(Iq(to=jid,typ='get',queryNS=NS_BROWSE), _on_resp2)
else: else:
_on_resp2('') _on_resp2('')
def _on_resp2(resp): def _on_resp2(resp):
if fb2a and not isResultNode(resp): if fb2a and not isResultNode(resp):
# Fallback to agents # Fallback to agents
disp.SendAndCallForResponse(Iq(to=jid,typ='get',queryNS=NS_AGENTS), _on_result) disp.SendAndCallForResponse(Iq(to=jid,typ='get',queryNS=NS_AGENTS), _on_result)
else: else:
_on_result('') _on_result('')
def _on_result(resp): def _on_result(resp):
if isResultNode(resp): if isResultNode(resp):
if cb: if cb:
cb(resp.getQueryPayload()) cb(resp.getQueryPayload())
elif cb: elif cb:
@ -65,7 +65,7 @@ def discoverItems(disp,jid,node=None, cb=None):
def _on_response(result_array): def _on_response(result_array):
ret=[] ret=[]
for result in result_array: for result in result_array:
if result.getName()=='agent' and result.getTag('name'): if result.getName()=='agent' and result.getTag('name'):
result.setAttr('name', result.getTagData('name')) result.setAttr('name', result.getTagData('name'))
ret.append(result.attrs) ret.append(result.attrs)
if cb: if cb:
@ -82,39 +82,39 @@ def discoverInfo(disp,jid,node=None, cb=None):
def _on_response(result): def _on_response(result):
identities , features = [] , [] identities , features = [] , []
for i in result: for i in result:
if i.getName()=='identity': if i.getName()=='identity':
identities.append(i.attrs) identities.append(i.attrs)
elif i.getName()=='feature': elif i.getName()=='feature':
features.append(i.getAttr('var')) features.append(i.getAttr('var'))
elif i.getName()=='agent': elif i.getName()=='agent':
if i.getTag('name'): if i.getTag('name'):
i.setAttr('name',i.getTagData('name')) i.setAttr('name',i.getTagData('name'))
if i.getTag('description'): if i.getTag('description'):
i.setAttr('name',i.getTagData('description')) i.setAttr('name',i.getTagData('description'))
identities.append(i.attrs) identities.append(i.attrs)
if i.getTag('groupchat'): if i.getTag('groupchat'):
features.append(NS_GROUPCHAT) features.append(NS_GROUPCHAT)
if i.getTag('register'): if i.getTag('register'):
features.append(NS_REGISTER) features.append(NS_REGISTER)
if i.getTag('search'): if i.getTag('search'):
features.append(NS_SEARCH) features.append(NS_SEARCH)
if cb: if cb:
cb(identities , features) cb(identities , features)
_discover(disp, NS_DISCO_INFO, jid, node, _on_response) _discover(disp, NS_DISCO_INFO, jid, node, _on_response)
### Registration ### jabber:iq:register ### JEP-0077 ########################### ### Registration ### jabber:iq:register ### JEP-0077 ###########################
def getRegInfo(disp, host, info={}, sync=True): def getRegInfo(disp, host, info={}, sync=True):
""" Gets registration form from remote host. """ Gets registration form from remote host.
You can pre-fill the info dictionary. You can pre-fill the info dictionary.
F.e. if you are requesting info on registering user joey than specify F.e. if you are requesting info on registering user joey than specify
info as {'username':'joey'}. See JEP-0077 for details. info as {'username':'joey'}. See JEP-0077 for details.
'disp' must be connected dispatcher instance.""" 'disp' must be connected dispatcher instance."""
iq=Iq('get',NS_REGISTER,to=host) iq=Iq('get',NS_REGISTER,to=host)
for i in info.keys(): for i in info.keys():
iq.setTagData(i,info[i]) iq.setTagData(i,info[i])
if sync: if sync:
disp.SendAndCallForResponse(iq, lambda resp: _ReceivedRegInfo(disp.Dispatcher,resp, host)) disp.SendAndCallForResponse(iq, lambda resp: _ReceivedRegInfo(disp.Dispatcher,resp, host))
else: else:
disp.SendAndCallForResponse(iq, _ReceivedRegInfo, {'agent': host }) disp.SendAndCallForResponse(iq, _ReceivedRegInfo, {'agent': host })
def _ReceivedRegInfo(con, resp, agent): def _ReceivedRegInfo(con, resp, agent):
@ -208,7 +208,7 @@ def getPrivacyList(disp, listname):
""" Requests specific privacy list listname. Returns list of XML nodes (rules) """ Requests specific privacy list listname. Returns list of XML nodes (rules)
taken from the server responce.""" taken from the server responce."""
def _on_response(resp): def _on_response(resp):
if not isResultNode(resp): if not isResultNode(resp):
disp.Event(NS_PRIVACY, PRIVACY_LIST_RECEIVED, (False)) disp.Event(NS_PRIVACY, PRIVACY_LIST_RECEIVED, (False))
return return
disp.Event(NS_PRIVACY, PRIVACY_LIST_RECEIVED, (resp)) disp.Event(NS_PRIVACY, PRIVACY_LIST_RECEIVED, (resp))
@ -218,9 +218,9 @@ def getPrivacyList(disp, listname):
def setActivePrivacyList(disp, listname=None, typ='active', cb=None): def setActivePrivacyList(disp, listname=None, typ='active', cb=None):
""" Switches privacy list 'listname' to specified type. """ Switches privacy list 'listname' to specified type.
By default the type is 'active'. Returns true on success.""" By default the type is 'active'. Returns true on success."""
if listname: if listname:
attrs={'name':listname} attrs={'name':listname}
else: else:
attrs={} attrs={}
iq = Iq('set',NS_PRIVACY,payload=[Node(typ,attrs)]) iq = Iq('set',NS_PRIVACY,payload=[Node(typ,attrs)])
_on_default_response(disp, iq, cb) _on_default_response(disp, iq, cb)

View file

@ -1,4 +1,4 @@
## filetransfer.py ## filetransfer.py
## ##
## Copyright (C) 2004 Alexey "Snake" Nezhdanov ## Copyright (C) 2004 Alexey "Snake" Nezhdanov
## ##
@ -28,7 +28,7 @@ class IBB(PlugIn):
""" IBB used to transfer small-sized data chunk over estabilished xmpp connection. """ IBB used to transfer small-sized data chunk over estabilished xmpp connection.
Data is split into small blocks (by default 3000 bytes each), encoded as base 64 Data is split into small blocks (by default 3000 bytes each), encoded as base 64
and sent to another entity that compiles these blocks back into the data chunk. and sent to another entity that compiles these blocks back into the data chunk.
This is very inefficiend but should work under any circumstances. Note that This is very inefficiend but should work under any circumstances. Note that
using IBB normally should be the last resort. using IBB normally should be the last resort.
""" """
def __init__(self): def __init__(self):

View file

@ -19,42 +19,42 @@ class IdleObject:
''' '''
def __init__(self): def __init__(self):
self.fd = -1 self.fd = -1
def pollend(self): def pollend(self):
''' called on stream failure ''' ''' called on stream failure '''
pass pass
def pollin(self): def pollin(self):
''' called on new read event ''' ''' called on new read event '''
pass pass
def pollout(self): def pollout(self):
''' called on new write event (connect in sockets is a pollout) ''' ''' called on new write event (connect in sockets is a pollout) '''
pass pass
def read_timeout(self, fd): def read_timeout(self, fd):
''' called when timeout has happend ''' ''' called when timeout has happend '''
pass pass
class IdleQueue: class IdleQueue:
def __init__(self): def __init__(self):
self.queue = {} self.queue = {}
# when there is a timeout it executes obj.read_timeout() # when there is a timeout it executes obj.read_timeout()
# timeout is not removed automatically! # timeout is not removed automatically!
self.read_timeouts = {} self.read_timeouts = {}
# cb, which are executed after XX sec., alarms are removed automatically # cb, which are executed after XX sec., alarms are removed automatically
self.alarms = {} self.alarms = {}
self.init_idle() self.init_idle()
def init_idle(self): def init_idle(self):
self.selector = select.poll() self.selector = select.poll()
def remove_timeout(self, fd): def remove_timeout(self, fd):
if fd in self.read_timeouts: if fd in self.read_timeouts:
del(self.read_timeouts[fd]) del(self.read_timeouts[fd])
def set_alarm(self, alarm_cb, seconds): def set_alarm(self, alarm_cb, seconds):
''' set up a new alarm, to be called after alarm_cb sec. ''' ''' set up a new alarm, to be called after alarm_cb sec. '''
alarm_time = self.current_time() + seconds alarm_time = self.current_time() + seconds
@ -63,13 +63,13 @@ class IdleQueue:
self.alarms[alarm_time].append(alarm_cb) self.alarms[alarm_time].append(alarm_cb)
else: else:
self.alarms[alarm_time] = [alarm_cb] self.alarms[alarm_time] = [alarm_cb]
def set_read_timeout(self, fd, seconds): def set_read_timeout(self, fd, seconds):
''' set a new timeout, if it is not removed after 'seconds', ''' set a new timeout, if it is not removed after 'seconds',
then obj.read_timeout() will be called ''' then obj.read_timeout() will be called '''
timeout = self.current_time() + seconds timeout = self.current_time() + seconds
self.read_timeouts[fd] = timeout self.read_timeouts[fd] = timeout
def check_time_events(self): def check_time_events(self):
current_time = self.current_time() current_time = self.current_time()
for fd, timeout in self.read_timeouts.items(): for fd, timeout in self.read_timeouts.items():
@ -86,7 +86,7 @@ class IdleQueue:
for cb in self.alarms[alarm_time]: for cb in self.alarms[alarm_time]:
cb() cb()
del(self.alarms[alarm_time]) del(self.alarms[alarm_time])
def plug_idle(self, obj, writable = True, readable = True): def plug_idle(self, obj, writable = True, readable = True):
if obj.fd == -1: if obj.fd == -1:
return return
@ -105,43 +105,43 @@ class IdleQueue:
# when we paused a FT, we expect only a close event # when we paused a FT, we expect only a close event
flags = 16 flags = 16
self.add_idle(obj.fd, flags) self.add_idle(obj.fd, flags)
def add_idle(self, fd, flags): def add_idle(self, fd, flags):
self.selector.register(fd, flags) self.selector.register(fd, flags)
def unplug_idle(self, fd): def unplug_idle(self, fd):
if fd in self.queue: if fd in self.queue:
del(self.queue[fd]) del(self.queue[fd])
self.remove_idle(fd) self.remove_idle(fd)
def current_time(self): def current_time(self):
from time import time from time import time
return time() return time()
def remove_idle(self, fd): def remove_idle(self, fd):
self.selector.unregister(fd) self.selector.unregister(fd)
def process_events(self, fd, flags): def process_events(self, fd, flags):
obj = self.queue.get(fd) obj = self.queue.get(fd)
if obj is None: if obj is None:
self.unplug_idle(fd) self.unplug_idle(fd)
return False return False
if flags & 3: # waiting read event if flags & 3: # waiting read event
obj.pollin() obj.pollin()
return True return True
elif flags & 4: # waiting write event elif flags & 4: # waiting write event
obj.pollout() obj.pollout()
return True return True
elif flags & 16: # closed channel elif flags & 16: # closed channel
# io error, don't expect more events # io error, don't expect more events
self.remove_timeout(obj.fd) self.remove_timeout(obj.fd)
self.unplug_idle(obj.fd) self.unplug_idle(obj.fd)
obj.pollend() obj.pollend()
return False return False
def process(self): def process(self):
if not self.queue: if not self.queue:
# check for timeouts/alert also when there are no active fds # check for timeouts/alert also when there are no active fds
@ -159,7 +159,7 @@ class IdleQueue:
return True return True
class SelectIdleQueue(IdleQueue): class SelectIdleQueue(IdleQueue):
''' '''
Extends IdleQueue to use select.select() for polling Extends IdleQueue to use select.select() for polling
This class exisists for the sake of gtk2.8 on windows, which This class exisists for the sake of gtk2.8 on windows, which
doesn't seem to support io_add_watch properly (yet) doesn't seem to support io_add_watch properly (yet)
@ -171,7 +171,7 @@ class SelectIdleQueue(IdleQueue):
self.read_fds = {} self.read_fds = {}
self.write_fds = {} self.write_fds = {}
self.error_fds = {} self.error_fds = {}
def add_idle(self, fd, flags): def add_idle(self, fd, flags):
''' this method is called when we plug a new idle object. ''' this method is called when we plug a new idle object.
Remove descriptor to read/write/error lists, according flags Remove descriptor to read/write/error lists, according flags
@ -181,7 +181,7 @@ class SelectIdleQueue(IdleQueue):
if flags & 4: if flags & 4:
self.write_fds[fd] = fd self.write_fds[fd] = fd
self.error_fds[fd] = fd self.error_fds[fd] = fd
def remove_idle(self, fd): def remove_idle(self, fd):
''' this method is called when we unplug a new idle object. ''' this method is called when we unplug a new idle object.
Remove descriptor from read/write/error lists Remove descriptor from read/write/error lists
@ -192,13 +192,13 @@ class SelectIdleQueue(IdleQueue):
del(self.write_fds[fd]) del(self.write_fds[fd])
if fd in self.error_fds: if fd in self.error_fds:
del(self.error_fds[fd]) del(self.error_fds[fd])
def process(self): def process(self):
if not self.write_fds and not self.read_fds: if not self.write_fds and not self.read_fds:
self.check_time_events() self.check_time_events()
return True return True
try: try:
waiting_descriptors = select.select(self.read_fds.keys(), waiting_descriptors = select.select(self.read_fds.keys(),
self.write_fds.keys(), self.error_fds.keys(), 0) self.write_fds.keys(), self.error_fds.keys(), 0)
except select.error, e: except select.error, e:
waiting_descriptors = ((),(),()) waiting_descriptors = ((),(),())

View file

@ -1,4 +1,4 @@
## protocol.py ## protocol.py
## ##
## Copyright (C) 2003-2005 Alexey "Snake" Nezhdanov ## Copyright (C) 2003-2005 Alexey "Snake" Nezhdanov
## ##
@ -15,7 +15,7 @@
# $Id: protocol.py,v 1.52 2006/01/09 22:08:57 normanr Exp $ # $Id: protocol.py,v 1.52 2006/01/09 22:08:57 normanr Exp $
""" """
Protocol module contains tools that is needed for processing of Protocol module contains tools that is needed for processing of
xmpp-related data structures. xmpp-related data structures.
""" """
@ -162,7 +162,7 @@ remote-server-timeout -- 504 -- wait -- A remote server or service specified as
resource-constraint -- 500 -- wait -- The server or recipient lacks the system resources necessary to service the request. resource-constraint -- 500 -- wait -- The server or recipient lacks the system resources necessary to service the request.
service-unavailable -- 503 -- cancel -- The server or recipient does not currently provide the requested service. service-unavailable -- 503 -- cancel -- The server or recipient does not currently provide the requested service.
subscription-required -- 407 -- auth -- The requesting entity is not authorized to access the requested service because a subscription is required. subscription-required -- 407 -- auth -- The requesting entity is not authorized to access the requested service because a subscription is required.
undefined-condition -- 500 -- -- undefined-condition -- 500 -- -- Undefined Condition
unexpected-request -- 400 -- wait -- The recipient or server understood the request but was not expecting it at this time (e.g., the request was out of order).""" unexpected-request -- 400 -- wait -- The recipient or server understood the request but was not expecting it at this time (e.g., the request was out of order)."""
sasl_error_conditions=""" sasl_error_conditions="""
aborted -- -- -- The receiving entity acknowledges an <abort/> element sent by the initiating entity; sent in reply to the <abort/> element. aborted -- -- -- The receiving entity acknowledges an <abort/> element sent by the initiating entity; sent in reply to the <abort/> element.
@ -559,7 +559,7 @@ class Presence(Protocol):
attrs.append(child.getAttr('code')) attrs.append(child.getAttr('code'))
return attrs return attrs
class Iq(Protocol): class Iq(Protocol):
""" XMPP Iq object - get/set dialog mechanism. """ """ XMPP Iq object - get/set dialog mechanism. """
def __init__(self, typ=None, queryNS=None, attrs={}, to=None, frm=None, payload=[], xmlns=NS_CLIENT, node=None): def __init__(self, typ=None, queryNS=None, attrs={}, to=None, frm=None, payload=[], xmlns=NS_CLIENT, node=None):
""" Create Iq object. You can specify type, query namespace """ Create Iq object. You can specify type, query namespace
@ -638,7 +638,7 @@ class Error(Protocol):
class DataField(Node): class DataField(Node):
""" This class is used in the DataForm class to describe the single data item. """ This class is used in the DataForm class to describe the single data item.
If you are working with jabber:x:data (XEP-0004, XEP-0068, XEP-0122) If you are working with jabber:x:data (XEP-0004, XEP-0068, XEP-0122)
then you will need to work with instances of this class. """ then you will need to work with instances of this class. """
def __init__(self,name=None,value=None,typ=None,required=0,desc=None,options=[],node=None): def __init__(self,name=None,value=None,typ=None,required=0,desc=None,options=[],node=None):
""" Create new data field of specified name,value and type. """ Create new data field of specified name,value and type.

View file

@ -24,7 +24,7 @@ from client import PlugIn
class Roster(PlugIn): class Roster(PlugIn):
""" Defines a plenty of methods that will allow you to manage roster. """ Defines a plenty of methods that will allow you to manage roster.
Also automatically track presences from remote JIDs taking into Also automatically track presences from remote JIDs taking into
account that every JID can have multiple resources connected. Does not account that every JID can have multiple resources connected. Does not
currently support 'error' presences. currently support 'error' presences.
You can also use mapping interface for access to the internal representation of You can also use mapping interface for access to the internal representation of
@ -48,7 +48,7 @@ class Roster(PlugIn):
if request: self.Request() if request: self.Request()
def Request(self,force=0): def Request(self,force=0):
""" Request roster from server if it were not yet requested """ Request roster from server if it were not yet requested
(or if the 'force' argument is set). """ (or if the 'force' argument is set). """
if self.set is None: self.set=0 if self.set is None: self.set=0
elif not force: return elif not force: return
@ -187,7 +187,7 @@ class Roster(PlugIn):
""" Authorise JID 'jid'. Works only if these JID requested auth previously. """ """ Authorise JID 'jid'. Works only if these JID requested auth previously. """
self._owner.send(Presence(jid,'subscribed')) self._owner.send(Presence(jid,'subscribed'))
def Unauthorize(self,jid): def Unauthorize(self,jid):
""" Unauthorise JID 'jid'. Use for declining authorisation request """ Unauthorise JID 'jid'. Use for declining authorisation request
or for removing existing authorization. """ or for removing existing authorization. """
self._owner.send(Presence(jid,'unsubscribed')) self._owner.send(Presence(jid,'unsubscribed'))
def getRaw(self): def getRaw(self):

View file

@ -32,23 +32,23 @@ class NonBlockingRoster(Roster):
self._owner.RegisterHandler('iq', self.RosterIqHandler, 'result', NS_ROSTER, makefirst = 1) self._owner.RegisterHandler('iq', self.RosterIqHandler, 'result', NS_ROSTER, makefirst = 1)
self._owner.RegisterHandler('iq', self.RosterIqHandler, 'set', NS_ROSTER) self._owner.RegisterHandler('iq', self.RosterIqHandler, 'set', NS_ROSTER)
self._owner.RegisterHandler('presence', self.PresenceHandler) self._owner.RegisterHandler('presence', self.PresenceHandler)
if request: if request:
self.Request() self.Request()
def _on_roster_set(self, data): def _on_roster_set(self, data):
if data: if data:
self._owner.Dispatcher.ProcessNonBlocking(data) self._owner.Dispatcher.ProcessNonBlocking(data)
if not self.set: if not self.set:
return return
self._owner.onreceive(None) self._owner.onreceive(None)
if self.on_ready: if self.on_ready:
self.on_ready(self) self.on_ready(self)
self.on_ready = None self.on_ready = None
return True return True
def getRoster(self, on_ready=None): def getRoster(self, on_ready=None):
''' Requests roster from server if neccessary and returns self. ''' ''' Requests roster from server if neccessary and returns self. '''
if not self.set: if not self.set:
self.on_ready = on_ready self.on_ready = on_ready
self._owner.onreceive(self._on_roster_set) self._owner.onreceive(self._on_roster_set)
return return

View file

@ -46,7 +46,7 @@ SESSION_CLOSED =5
class Session: class Session:
""" """
The Session class instance is used for storing all session-related info like The Session class instance is used for storing all session-related info like
credentials, socket/xml stream/session state flags, roster items (in case of credentials, socket/xml stream/session state flags, roster items (in case of
client type connection) etc. client type connection) etc.
Session object have no means of discovering is any info is ready to be read. Session object have no means of discovering is any info is ready to be read.
@ -341,7 +341,7 @@ class Session:
def set_session_state(self,newstate): def set_session_state(self,newstate):
""" Change the session state. """ Change the session state.
Session starts with SESSION_NOT_AUTHED state Session starts with SESSION_NOT_AUTHED state
and then comes through and then comes through
SESSION_AUTHED, SESSION_BOUND, SESSION_OPENED and SESSION_CLOSED states. SESSION_AUTHED, SESSION_BOUND, SESSION_OPENED and SESSION_CLOSED states.
""" """
if self._session_state<newstate: if self._session_state<newstate:

View file

@ -53,14 +53,14 @@ class Node(object):
""" Takes "tag" argument as the name of node (prepended by namespace, if needed and separated from it """ Takes "tag" argument as the name of node (prepended by namespace, if needed and separated from it
by a space), attrs dictionary as the set of arguments, payload list as the set of textual strings by a space), attrs dictionary as the set of arguments, payload list as the set of textual strings
and child nodes that this node carries within itself and "parent" argument that is another node and child nodes that this node carries within itself and "parent" argument that is another node
that this one will be the child of. Also the __init__ can be provided with "node" argument that is that this one will be the child of. Also the __init__ can be provided with "node" argument that is
either a text string containing exactly one node or another Node instance to begin with. If both either a text string containing exactly one node or another Node instance to begin with. If both
"node" and other arguments is provided then the node initially created as replica of "node" "node" and other arguments is provided then the node initially created as replica of "node"
provided and then modified to be compliant with other arguments.""" provided and then modified to be compliant with other arguments."""
if node: if node:
if self.FORCE_NODE_RECREATION and isinstance(node, Node): if self.FORCE_NODE_RECREATION and isinstance(node, Node):
node=str(node) node=str(node)
if not isinstance(node, Node): if not isinstance(node, Node):
node=NodeBuilder(node,self) node=NodeBuilder(node,self)
node_built = True node_built = True
else: else:
@ -94,7 +94,7 @@ class Node(object):
for i in payload: for i in payload:
if isinstance(i, Node): self.addChild(node=i) if isinstance(i, Node): self.addChild(node=i)
else: self.data.append(ustr(i)) else: self.data.append(ustr(i))
def lookup_nsp(self,pfx=''): def lookup_nsp(self,pfx=''):
ns = self.nsd.get(pfx,None) ns = self.nsd.get(pfx,None)
if ns is None: if ns is None:
@ -119,7 +119,7 @@ class Node(object):
val = ustr(self.attrs[key]) val = ustr(self.attrs[key])
s = s + ' %s="%s"' % ( key, XMLescape(val) ) s = s + ' %s="%s"' % ( key, XMLescape(val) )
s = s + ">" s = s + ">"
cnt = 0 cnt = 0
if self.kids: if self.kids:
if fancy: s = s + "\n" if fancy: s = s + "\n"
for a in self.kids: for a in self.kids:
@ -196,7 +196,7 @@ class Node(object):
try: ret.append(self.kids[i]) try: ret.append(self.kids[i])
except IndexError: pass except IndexError: pass
return ret return ret
def getTag(self, name, attrs={}, namespace=None): def getTag(self, name, attrs={}, namespace=None):
""" Filters all child nodes using specified arguments as filter. """ Filters all child nodes using specified arguments as filter.
Returns the first found or None if not found. """ Returns the first found or None if not found. """
return self.getTags(name, attrs, namespace, one=1) return self.getTags(name, attrs, namespace, one=1)
@ -224,7 +224,7 @@ class Node(object):
else: nodes.append(node) else: nodes.append(node)
if one and nodes: return nodes[0] if one and nodes: return nodes[0]
if not one: return nodes if not one: return nodes
def iterTags(self, name, attrs={}, namespace=None): def iterTags(self, name, attrs={}, namespace=None):
""" Iterate over all children using specified arguments as filter. """ """ Iterate over all children using specified arguments as filter. """
for node in self.kids: for node in self.kids:
@ -248,8 +248,8 @@ class Node(object):
def setNamespace(self, namespace): def setNamespace(self, namespace):
""" Changes the node namespace. """ """ Changes the node namespace. """
self.namespace=namespace self.namespace=namespace
def setParent(self, node): def setParent(self, node):
""" Sets node's parent to "node". WARNING: do not checks if the parent already present """ Sets node's parent to "node". WARNING: do not checks if the parent already present
and not removes the node from the list of childs of previous parent. """ and not removes the node from the list of childs of previous parent. """
self.parent = node self.parent = node
def setPayload(self,payload,add=0): def setPayload(self,payload,add=0):
@ -320,7 +320,7 @@ DBG_NODEBUILDER = 'nodebuilder'
class NodeBuilder: class NodeBuilder:
""" Builds a Node class minidom from data parsed to it. This class used for two purposes: """ Builds a Node class minidom from data parsed to it. This class used for two purposes:
1. Creation an XML Node from a textual representation. F.e. reading a config file. See an XML2Node method. 1. Creation an XML Node from a textual representation. F.e. reading a config file. See an XML2Node method.
2. Handling an incoming XML stream. This is done by mangling 2. Handling an incoming XML stream. This is done by mangling
the __dispatch_depth parameter and redefining the dispatch method. the __dispatch_depth parameter and redefining the dispatch method.
You do not need to use this class directly if you do not designing your own XML handler.""" You do not need to use this class directly if you do not designing your own XML handler."""
def __init__(self,data=None,initial_node=None): def __init__(self,data=None,initial_node=None):
@ -331,7 +331,7 @@ class NodeBuilder:
"data" (if provided) feeded to parser immidiatedly after instance init. "data" (if provided) feeded to parser immidiatedly after instance init.
""" """
self.DEBUG(DBG_NODEBUILDER, "Preparing to handle incoming XML stream.", 'start') self.DEBUG(DBG_NODEBUILDER, "Preparing to handle incoming XML stream.", 'start')
self._parser = xml.parsers.expat.ParserCreate() self._parser = xml.parsers.expat.ParserCreate()
self._parser.StartElementHandler = self.starttag self._parser.StartElementHandler = self.starttag
self._parser.EndElementHandler = self.endtag self._parser.EndElementHandler = self.endtag
@ -339,7 +339,7 @@ class NodeBuilder:
self._parser.CharacterDataHandler = self.handle_cdata self._parser.CharacterDataHandler = self.handle_cdata
self._parser.buffer_text = True self._parser.buffer_text = True
self.Parse = self._parser.Parse self.Parse = self._parser.Parse
self.__depth = 0 self.__depth = 0
self.__last_depth = 0 self.__last_depth = 0
self.__max_depth = 0 self.__max_depth = 0
@ -352,13 +352,13 @@ class NodeBuilder:
self.data_buffer = None self.data_buffer = None
if data: if data:
self._parser.Parse(data,1) self._parser.Parse(data,1)
def check_data_buffer(self): def check_data_buffer(self):
if self.data_buffer: if self.data_buffer:
self._ptr.data.append(''.join(self.data_buffer)) self._ptr.data.append(''.join(self.data_buffer))
del self.data_buffer[:] del self.data_buffer[:]
self.data_buffer = None self.data_buffer = None
def destroy(self): def destroy(self):
""" Method used to allow class instance to be garbage-collected. """ """ Method used to allow class instance to be garbage-collected. """
self.check_data_buffer() self.check_data_buffer()
@ -373,9 +373,9 @@ class NodeBuilder:
self._inc_depth() self._inc_depth()
self.DEBUG(DBG_NODEBUILDER, "DEPTH -> %i , tag -> %s, attrs -> %s" % (self.__depth, tag, repr(attrs)), 'down') self.DEBUG(DBG_NODEBUILDER, "DEPTH -> %i , tag -> %s, attrs -> %s" % (self.__depth, tag, repr(attrs)), 'down')
if self.__depth == self._dispatch_depth: if self.__depth == self._dispatch_depth:
if not self._mini_dom : if not self._mini_dom :
self._mini_dom = Node(tag=tag, attrs=attrs, nsp = self._document_nsp, node_built=True) self._mini_dom = Node(tag=tag, attrs=attrs, nsp = self._document_nsp, node_built=True)
else: else:
Node.__init__(self._mini_dom,tag=tag, attrs=attrs, nsp = self._document_nsp, node_built=True) Node.__init__(self._mini_dom,tag=tag, attrs=attrs, nsp = self._document_nsp, node_built=True)
self._ptr = self._mini_dom self._ptr = self._mini_dom
elif self.__depth > self._dispatch_depth: elif self.__depth > self._dispatch_depth:
@ -398,7 +398,7 @@ class NodeBuilder:
except ValueError, e: except ValueError, e:
self._document_attrs = None self._document_attrs = None
raise ValueError(str(e)) raise ValueError(str(e))
if not self.last_is_data and self._ptr.parent: if not self.last_is_data and self._ptr.parent:
self._ptr.parent.data.append('') self._ptr.parent.data.append('')
self.last_is_data = 0 self.last_is_data = 0
def endtag(self, tag ): def endtag(self, tag ):
@ -414,7 +414,7 @@ class NodeBuilder:
self._dec_depth() self._dec_depth()
self.last_is_data = 0 self.last_is_data = 0
if self.__depth == 0: self.stream_footer_received() if self.__depth == 0: self.stream_footer_received()
def handle_cdata(self, data): def handle_cdata(self, data):
if self.last_is_data: if self.last_is_data:
if self.data_buffer: if self.data_buffer:
@ -422,7 +422,7 @@ class NodeBuilder:
elif self._ptr: elif self._ptr:
self.data_buffer = [data] self.data_buffer = [data]
self.last_is_data = 1 self.last_is_data = 1
def handle_namespace_start(self, prefix, uri): def handle_namespace_start(self, prefix, uri):
"""XML Parser callback. Used internally""" """XML Parser callback. Used internally"""
self.check_data_buffer() self.check_data_buffer()

View file

@ -1,6 +1,6 @@
## transports_nb.py ## transports_nb.py
## based on transports.py ## based on transports.py
## ##
## Copyright (C) 2003-2004 Alexey "Snake" Nezhdanov ## Copyright (C) 2003-2004 Alexey "Snake" Nezhdanov
## modified by Dimitur Kirov <dkirov@gmail.com> ## modified by Dimitur Kirov <dkirov@gmail.com>
## ##
@ -22,7 +22,7 @@ from simplexml import ustr
from client import PlugIn from client import PlugIn
from idlequeue import IdleObject from idlequeue import IdleObject
from protocol import * from protocol import *
from transports import * from transports import *
import sys import sys
import os import os
@ -53,7 +53,7 @@ except ImportError:
print >> sys.stderr, "PyOpenSSL not found, falling back to Python builtin SSL objects (insecure)." print >> sys.stderr, "PyOpenSSL not found, falling back to Python builtin SSL objects (insecure)."
print >> sys.stderr, "=" * 79 print >> sys.stderr, "=" * 79
# timeout to connect to the server socket, it doesn't include auth # timeout to connect to the server socket, it doesn't include auth
CONNECT_TIMEOUT_SECONDS = 30 CONNECT_TIMEOUT_SECONDS = 30
# how long to wait for a disconnect to complete # how long to wait for a disconnect to complete
@ -240,14 +240,14 @@ class NonBlockingTcp(PlugIn, IdleObject):
''' This class can be used instead of transports.Tcp in threadless implementations ''' ''' This class can be used instead of transports.Tcp in threadless implementations '''
def __init__(self, on_connect = None, on_connect_failure = None, server=None, use_srv = True): def __init__(self, on_connect = None, on_connect_failure = None, server=None, use_srv = True):
''' Cache connection point 'server'. 'server' is the tuple of (host, port) ''' Cache connection point 'server'. 'server' is the tuple of (host, port)
absolutely the same as standard tcp socket uses. absolutely the same as standard tcp socket uses.
on_connect - called when we connect to the socket on_connect - called when we connect to the socket
on_connect_failure - called if there was error connecting to socket on_connect_failure - called if there was error connecting to socket
''' '''
IdleObject.__init__(self) IdleObject.__init__(self)
PlugIn.__init__(self) PlugIn.__init__(self)
self.DBG_LINE='socket' self.DBG_LINE='socket'
self._exported_methods=[self.send, self.disconnect, self.onreceive, self.set_send_timeout, self._exported_methods=[self.send, self.disconnect, self.onreceive, self.set_send_timeout,
self.start_disconnect, self.set_timeout, self.remove_timeout] self.start_disconnect, self.set_timeout, self.remove_timeout]
self._server = server self._server = server
self._hostfqdn = server[0] self._hostfqdn = server[0]
@ -256,43 +256,43 @@ class NonBlockingTcp(PlugIn, IdleObject):
self.on_receive = None self.on_receive = None
self.on_disconnect = None self.on_disconnect = None
self.printed_error = False self.printed_error = False
# 0 - not connected # 0 - not connected
# 1 - connected # 1 - connected
# -1 - about to disconnect (when we wait for final events to complete) # -1 - about to disconnect (when we wait for final events to complete)
# -2 - disconnected # -2 - disconnected
self.state = 0 self.state = 0
# queue with messages to be send # queue with messages to be send
self.sendqueue = [] self.sendqueue = []
# bytes remained from the last send message # bytes remained from the last send message
self.sendbuff = '' self.sendbuff = ''
# time to wait for SOME stanza to come and then send keepalive # time to wait for SOME stanza to come and then send keepalive
self.sendtimeout = 0 self.sendtimeout = 0
# in case we want to something different than sending keepalives # in case we want to something different than sending keepalives
self.on_timeout = None self.on_timeout = None
# writable, readable - keep state of the last pluged flags # writable, readable - keep state of the last pluged flags
# This prevents replug of same object with the same flags # This prevents replug of same object with the same flags
self.writable = True self.writable = True
self.readable = False self.readable = False
self.ais = None self.ais = None
def plugin(self, owner): def plugin(self, owner):
''' Fire up connection. Return non-empty string on success. ''' Fire up connection. Return non-empty string on success.
Also registers self.disconnected method in the owner's dispatcher. Also registers self.disconnected method in the owner's dispatcher.
Called internally. ''' Called internally. '''
self.idlequeue = owner.idlequeue self.idlequeue = owner.idlequeue
self.printed_error = False self.printed_error = False
if not self._server: if not self._server:
self._server=(self._owner.Server,5222) self._server=(self._owner.Server,5222)
if self.connect(self._server) is False: if self.connect(self._server) is False:
return False return False
return True return True
def read_timeout(self): def read_timeout(self):
if self.state == 0: if self.state == 0:
self.idlequeue.unplug_idle(self.fd) self.idlequeue.unplug_idle(self.fd)
@ -307,7 +307,7 @@ class NonBlockingTcp(PlugIn, IdleObject):
''' Try to establish connection. ''' ''' Try to establish connection. '''
if not server: if not server:
server=self._server server=self._server
else: else:
self._server = server self._server = server
self._hostfqdn = self._server[0] self._hostfqdn = self._server[0]
self.printed_error = False self.printed_error = False
@ -338,23 +338,23 @@ class NonBlockingTcp(PlugIn, IdleObject):
writable = False writable = False
if self.writable != writable or self.readable != readable: if self.writable != writable or self.readable != readable:
self.idlequeue.plug_idle(self, writable, readable) self.idlequeue.plug_idle(self, writable, readable)
def pollout(self): def pollout(self):
if self.state == 0: if self.state == 0:
self._do_connect() self._do_connect()
return return
self._do_send() self._do_send()
def plugout(self): def plugout(self):
''' Disconnect from the remote server and unregister self.disconnected method from ''' Disconnect from the remote server and unregister self.disconnected method from
the owner's dispatcher. ''' the owner's dispatcher. '''
self.disconnect() self.disconnect()
self._owner.Connection = None self._owner.Connection = None
self._owner = None self._owner = None
def pollin(self): def pollin(self):
self._do_receive() self._do_receive()
def pollend(self, retry=False): def pollend(self, retry=False):
if not self.printed_error: if not self.printed_error:
self.printed_error = True self.printed_error = True
@ -366,13 +366,13 @@ class NonBlockingTcp(PlugIn, IdleObject):
self.disconnect() self.disconnect()
if conn_failure_cb: if conn_failure_cb:
conn_failure_cb(retry) conn_failure_cb(retry)
def disconnect(self): def disconnect(self):
if self.state == -2: # already disconnected if self.state == -2: # already disconnected
return return
self.state = -2 self.state = -2
self.sendqueue = None self.sendqueue = None
self.remove_timeout() self.remove_timeout()
try: try:
self._owner.disconnected() self._owner.disconnected()
except Exception: except Exception:
@ -394,12 +394,12 @@ class NonBlockingTcp(PlugIn, IdleObject):
if self.on_disconnect: if self.on_disconnect:
self.on_disconnect() self.on_disconnect()
self.on_connect_failure = None self.on_connect_failure = None
def end_disconnect(self): def end_disconnect(self):
''' force disconnect only if we are still trying to disconnect ''' ''' force disconnect only if we are still trying to disconnect '''
if self.state == -1: if self.state == -1:
self.disconnect() self.disconnect()
def start_disconnect(self, to_send, on_disconnect): def start_disconnect(self, to_send, on_disconnect):
self.on_disconnect = on_disconnect self.on_disconnect = on_disconnect
@ -412,19 +412,19 @@ class NonBlockingTcp(PlugIn, IdleObject):
self.send('</stream:stream>') self.send('</stream:stream>')
self.state = -1 # about to disconnect self.state = -1 # about to disconnect
self.idlequeue.set_alarm(self.end_disconnect, DISCONNECT_TIMEOUT_SECONDS) self.idlequeue.set_alarm(self.end_disconnect, DISCONNECT_TIMEOUT_SECONDS)
def set_timeout(self, timeout): def set_timeout(self, timeout):
if self.state >= 0 and self.fd > 0: if self.state >= 0 and self.fd > 0:
self.idlequeue.set_read_timeout(self.fd, timeout) self.idlequeue.set_read_timeout(self.fd, timeout)
def remove_timeout(self): def remove_timeout(self):
if self.fd: if self.fd:
self.idlequeue.remove_timeout(self.fd) self.idlequeue.remove_timeout(self.fd)
def onreceive(self, recv_handler): def onreceive(self, recv_handler):
''' Sets the on_receive callback. Do not confuse it with ''' Sets the on_receive callback. Do not confuse it with
on_receive() method, which is the callback itself. on_receive() method, which is the callback itself.
If recv_handler==None, it tries to set that callback assuming that If recv_handler==None, it tries to set that callback assuming that
our owner also has a Dispatcher object plugged in, to its our owner also has a Dispatcher object plugged in, to its
ProcessNonBlocking method.''' ProcessNonBlocking method.'''
@ -438,7 +438,7 @@ class NonBlockingTcp(PlugIn, IdleObject):
# make sure this cb is not overriden by recursive calls # make sure this cb is not overriden by recursive calls
if not recv_handler(None) and _tmp == self.on_receive: if not recv_handler(None) and _tmp == self.on_receive:
self.on_receive = recv_handler self.on_receive = recv_handler
def _do_receive(self, errors_only=False): def _do_receive(self, errors_only=False):
''' Reads all pending incoming data. Calls owner's disconnected() method if appropriate.''' ''' Reads all pending incoming data. Calls owner's disconnected() method if appropriate.'''
ERR_DISCONN = -2 # Misc error signifying that we got disconnected ERR_DISCONN = -2 # Misc error signifying that we got disconnected
@ -446,7 +446,7 @@ class NonBlockingTcp(PlugIn, IdleObject):
received = None received = None
errnum = 0 errnum = 0
errtxt = 'No Error Set' errtxt = 'No Error Set'
try: try:
# get as many bites, as possible, but not more than RECV_BUFSIZE # get as many bites, as possible, but not more than RECV_BUFSIZE
received = self._recv(RECV_BUFSIZE) received = self._recv(RECV_BUFSIZE)
except (socket.error, socket.herror, socket.gaierror), e: except (socket.error, socket.herror, socket.gaierror), e:
@ -515,7 +515,7 @@ class NonBlockingTcp(PlugIn, IdleObject):
if self.on_connect_failure: if self.on_connect_failure:
self.on_connect_failure() self.on_connect_failure()
return True return True
def _do_send(self): def _do_send(self):
if not self.sendbuff: if not self.sendbuff:
if not self.sendqueue: if not self.sendqueue:
@ -532,12 +532,12 @@ class NonBlockingTcp(PlugIn, IdleObject):
self._on_send() self._on_send()
self.disconnect() self.disconnect()
return return
# we are not waiting for write # we are not waiting for write
self._plug_idle() self._plug_idle()
self._on_send() self._on_send()
except socket.error, e: except socket.error, e:
if e[0] == socket.SSL_ERROR_WANT_WRITE: if e[0] == socket.SSL_ERROR_WANT_WRITE:
return True return True
log.error("_do_send:", exc_info=True) log.error("_do_send:", exc_info=True)
#traceback.print_exc() #traceback.print_exc()
if self.state < 0: if self.state < 0:
@ -563,7 +563,7 @@ class NonBlockingTcp(PlugIn, IdleObject):
self._server=ai[4] self._server=ai[4]
except socket.error, e: except socket.error, e:
errnum, errstr = e errnum, errstr = e
# Ignore "Socket already connected". # Ignore "Socket already connected".
# FIXME: This happens when we switch an already # FIXME: This happens when we switch an already
# connected socket to SSL (STARTTLS). Instead of # connected socket to SSL (STARTTLS). Instead of
@ -614,16 +614,16 @@ class NonBlockingTcp(PlugIn, IdleObject):
self.on_connect = None self.on_connect = None
def send(self, raw_data, now = False): def send(self, raw_data, now = False):
'''Append raw_data to the queue of messages to be send. '''Append raw_data to the queue of messages to be send.
If supplied data is unicode string, encode it to utf-8. If supplied data is unicode string, encode it to utf-8.
''' '''
if self.state <= 0: if self.state <= 0:
return return
r = raw_data r = raw_data
if isinstance(r, unicode): if isinstance(r, unicode):
r = r.encode('utf-8') r = r.encode('utf-8')
elif not isinstance(r, str): elif not isinstance(r, str):
r = ustr(r).encode('utf-8') r = ustr(r).encode('utf-8')
if now: if now:
self.sendqueue.insert(0, r) self.sendqueue.insert(0, r)
@ -639,25 +639,25 @@ class NonBlockingTcp(PlugIn, IdleObject):
if hasattr(self._owner, 'Dispatcher'): if hasattr(self._owner, 'Dispatcher'):
self._owner.Dispatcher.Event('', DATA_SENT, self.sent_data) self._owner.Dispatcher.Event('', DATA_SENT, self.sent_data)
self.sent_data = None self.sent_data = None
def _on_send_failure(self): def _on_send_failure(self):
self.DEBUG("Socket error while sending data",'error') self.DEBUG("Socket error while sending data",'error')
self._owner.disconnected() self._owner.disconnected()
self.sent_data = None self.sent_data = None
def set_send_timeout(self, timeout, on_timeout): def set_send_timeout(self, timeout, on_timeout):
self.sendtimeout = timeout self.sendtimeout = timeout
if self.sendtimeout > 0: if self.sendtimeout > 0:
self.on_timeout = on_timeout self.on_timeout = on_timeout
else: else:
self.on_timeout = None self.on_timeout = None
def renew_send_timeout(self): def renew_send_timeout(self):
if self.on_timeout and self.sendtimeout > 0: if self.on_timeout and self.sendtimeout > 0:
self.set_timeout(self.sendtimeout) self.set_timeout(self.sendtimeout)
else: else:
self.remove_timeout() self.remove_timeout()
def getHost(self): def getHost(self):
''' Return the 'host' value that is connection is [will be] made to.''' ''' Return the 'host' value that is connection is [will be] made to.'''
return self._server[0] return self._server[0]
@ -682,10 +682,10 @@ class NonBlockingTLS(PlugIn):
''' TLS connection used to encrypts already estabilished tcp connection.''' ''' TLS connection used to encrypts already estabilished tcp connection.'''
# from ssl.h (partial extract) # from ssl.h (partial extract)
ssl_h_bits = { "SSL_ST_CONNECT": 0x1000, "SSL_ST_ACCEPT": 0x2000, ssl_h_bits = { "SSL_ST_CONNECT": 0x1000, "SSL_ST_ACCEPT": 0x2000,
"SSL_CB_LOOP": 0x01, "SSL_CB_EXIT": 0x02, "SSL_CB_LOOP": 0x01, "SSL_CB_EXIT": 0x02,
"SSL_CB_READ": 0x04, "SSL_CB_WRITE": 0x08, "SSL_CB_READ": 0x04, "SSL_CB_WRITE": 0x08,
"SSL_CB_ALERT": 0x4000, "SSL_CB_ALERT": 0x4000,
"SSL_CB_HANDSHAKE_START": 0x10, "SSL_CB_HANDSHAKE_DONE": 0x20} "SSL_CB_HANDSHAKE_START": 0x10, "SSL_CB_HANDSHAKE_DONE": 0x20}
def PlugIn(self, owner, now=0, on_tls_start = None): def PlugIn(self, owner, now=0, on_tls_start = None):
@ -693,7 +693,7 @@ class NonBlockingTLS(PlugIn):
If 'now' in false then starts encryption as soon as TLS feature is If 'now' in false then starts encryption as soon as TLS feature is
declared by the server (if it were already declared - it is ok). declared by the server (if it were already declared - it is ok).
''' '''
if 'NonBlockingTLS' in owner.__dict__: if 'NonBlockingTLS' in owner.__dict__:
return # Already enabled. return # Already enabled.
PlugIn.PlugIn(self, owner) PlugIn.PlugIn(self, owner)
self.DBG_LINE = DBG_NONBLOCKINGTLS self.DBG_LINE = DBG_NONBLOCKINGTLS
@ -710,14 +710,14 @@ class NonBlockingTLS(PlugIn):
self.tls_start() self.tls_start()
return res return res
if self._owner.Dispatcher.Stream.features: if self._owner.Dispatcher.Stream.features:
try: try:
self.FeaturesHandler(self._owner.Dispatcher, self._owner.Dispatcher.Stream.features) self.FeaturesHandler(self._owner.Dispatcher, self._owner.Dispatcher.Stream.features)
except NodeProcessed: except NodeProcessed:
pass pass
else: else:
self._owner.RegisterHandlerOnce('features',self.FeaturesHandler, xmlns=NS_STREAMS) self._owner.RegisterHandlerOnce('features',self.FeaturesHandler, xmlns=NS_STREAMS)
self.starttls = None self.starttls = None
def plugout(self,now=0): def plugout(self,now=0):
''' Unregisters TLS handler's from owner's dispatcher. Take note that encription ''' Unregisters TLS handler's from owner's dispatcher. Take note that encription
can not be stopped once started. You can only break the connection and start over.''' can not be stopped once started. You can only break the connection and start over.'''
@ -731,7 +731,7 @@ class NonBlockingTLS(PlugIn):
if self.on_tls_start: if self.on_tls_start:
self.on_tls_start() self.on_tls_start()
self.on_tls_start = None self.on_tls_start = None
def FeaturesHandler(self, conn, feats): def FeaturesHandler(self, conn, feats):
''' Used to analyse server <features/> tag for TLS support. ''' Used to analyse server <features/> tag for TLS support.
If TLS is supported starts the encryption negotiation. Used internally ''' If TLS is supported starts the encryption negotiation. Used internally '''
@ -868,7 +868,7 @@ class NonBlockingTLS(PlugIn):
def StartTLSHandler(self, conn, starttls): def StartTLSHandler(self, conn, starttls):
''' Handle server reply if TLS is allowed to process. Behaves accordingly. ''' Handle server reply if TLS is allowed to process. Behaves accordingly.
Used internally.''' Used internally.'''
if starttls.getNamespace() != NS_TLS: if starttls.getNamespace() != NS_TLS:
return return
self.starttls = starttls.getName() self.starttls = starttls.getName()
if self.starttls == 'failure': if self.starttls == 'failure':
@ -890,15 +890,15 @@ class NBHTTPPROXYsocket(NonBlockingTcp):
''' This class can be used instead of transports.HTTPPROXYsocket ''' This class can be used instead of transports.HTTPPROXYsocket
HTTP (CONNECT) proxy connection class. Uses TCPsocket as the base class HTTP (CONNECT) proxy connection class. Uses TCPsocket as the base class
redefines only connect method. Allows to use HTTP proxies like squid with redefines only connect method. Allows to use HTTP proxies like squid with
(optionally) simple authentication (using login and password). (optionally) simple authentication (using login and password).
''' '''
def __init__(self, on_connect =None, on_proxy_failure=None, on_connect_failure = None,proxy = None,server = None,use_srv=True): def __init__(self, on_connect =None, on_proxy_failure=None, on_connect_failure = None,proxy = None,server = None,use_srv=True):
''' Caches proxy and target addresses. ''' Caches proxy and target addresses.
'proxy' argument is a dictionary with mandatory keys 'host' and 'port' (proxy address) 'proxy' argument is a dictionary with mandatory keys 'host' and 'port' (proxy address)
and optional keys 'user' and 'password' to use for authentication. and optional keys 'user' and 'password' to use for authentication.
'server' argument is a tuple of host and port - just like TCPsocket uses. ''' 'server' argument is a tuple of host and port - just like TCPsocket uses. '''
self.on_connect_proxy = on_connect self.on_connect_proxy = on_connect
self.on_proxy_failure = on_proxy_failure self.on_proxy_failure = on_proxy_failure
self.on_connect_failure = on_connect_failure self.on_connect_failure = on_connect_failure
NonBlockingTcp.__init__(self, self._on_tcp_connect, on_connect_failure, server, use_srv) NonBlockingTcp.__init__(self, self._on_tcp_connect, on_connect_failure, server, use_srv)
@ -916,7 +916,7 @@ class NBHTTPPROXYsocket(NonBlockingTcp):
(if were specified while creating instance). Instructs proxy to make (if were specified while creating instance). Instructs proxy to make
connection to the target server. Returns non-empty sting on success. ''' connection to the target server. Returns non-empty sting on success. '''
NonBlockingTcp.connect(self, (self.proxy['host'], self.proxy['port'])) NonBlockingTcp.connect(self, (self.proxy['host'], self.proxy['port']))
def _on_tcp_connect(self): def _on_tcp_connect(self):
self.DEBUG('Proxy server contacted, performing authentification','start') self.DEBUG('Proxy server contacted, performing authentification','start')
connector = ['CONNECT %s:%s HTTP/1.0'%self.server, connector = ['CONNECT %s:%s HTTP/1.0'%self.server,
@ -931,14 +931,14 @@ class NBHTTPPROXYsocket(NonBlockingTcp):
connector.append('\r\n') connector.append('\r\n')
self.onreceive(self._on_headers_sent) self.onreceive(self._on_headers_sent)
self.send('\r\n'.join(connector)) self.send('\r\n'.join(connector))
def _on_headers_sent(self, reply): def _on_headers_sent(self, reply):
if reply is None: if reply is None:
return return
self.reply = reply.replace('\r', '') self.reply = reply.replace('\r', '')
try: try:
proto, code, desc = reply.split('\n')[0].split(' ', 2) proto, code, desc = reply.split('\n')[0].split(' ', 2)
except Exception: except Exception:
log.error("_on_headers_sent:", exc_info=True) log.error("_on_headers_sent:", exc_info=True)
#traceback.print_exc() #traceback.print_exc()
self.on_proxy_failure('Invalid proxy reply') self.on_proxy_failure('Invalid proxy reply')
@ -951,7 +951,7 @@ class NBHTTPPROXYsocket(NonBlockingTcp):
if len(reply) != 2: if len(reply) != 2:
pass pass
self.onreceive(self._on_proxy_auth) self.onreceive(self._on_proxy_auth)
def _on_proxy_auth(self, reply): def _on_proxy_auth(self, reply):
if self.reply.find('\n\n') == -1: if self.reply.find('\n\n') == -1:
if reply is None: if reply is None:
@ -972,7 +972,7 @@ class NBHTTPPROXYsocket(NonBlockingTcp):
class NBSOCKS5PROXYsocket(NonBlockingTcp): class NBSOCKS5PROXYsocket(NonBlockingTcp):
'''SOCKS5 proxy connection class. Uses TCPsocket as the base class '''SOCKS5 proxy connection class. Uses TCPsocket as the base class
redefines only connect method. Allows to use SOCKS5 proxies with redefines only connect method. Allows to use SOCKS5 proxies with
(optionally) simple authentication (only USERNAME/PASSWORD auth). (optionally) simple authentication (only USERNAME/PASSWORD auth).
''' '''
def __init__(self, on_connect = None, on_proxy_failure = None, def __init__(self, on_connect = None, on_proxy_failure = None,
on_connect_failure = None, proxy = None, server = None, use_srv = True): on_connect_failure = None, proxy = None, server = None, use_srv = True):
@ -981,7 +981,7 @@ class NBSOCKS5PROXYsocket(NonBlockingTcp):
(proxy address) and optional keys 'user' and 'password' to use for (proxy address) and optional keys 'user' and 'password' to use for
authentication. 'server' argument is a tuple of host and port - authentication. 'server' argument is a tuple of host and port -
just like TCPsocket uses. ''' just like TCPsocket uses. '''
self.on_connect_proxy = on_connect self.on_connect_proxy = on_connect
self.on_proxy_failure = on_proxy_failure self.on_proxy_failure = on_proxy_failure
self.on_connect_failure = on_connect_failure self.on_connect_failure = on_connect_failure
NonBlockingTcp.__init__(self, self._on_tcp_connect, on_connect_failure, NonBlockingTcp.__init__(self, self._on_tcp_connect, on_connect_failure,
@ -1003,7 +1003,7 @@ class NBSOCKS5PROXYsocket(NonBlockingTcp):
connection to the target server. Returns non-empty sting on success. connection to the target server. Returns non-empty sting on success.
''' '''
NonBlockingTcp.connect(self, (self.proxy['host'], self.proxy['port'])) NonBlockingTcp.connect(self, (self.proxy['host'], self.proxy['port']))
def _on_tcp_connect(self): def _on_tcp_connect(self):
self.DEBUG('Proxy server contacted, performing authentification', 'start') self.DEBUG('Proxy server contacted, performing authentification', 'start')
if 'user' in self.proxy and 'password' in self.proxy: if 'user' in self.proxy and 'password' in self.proxy:

View file

@ -87,7 +87,7 @@ class MappingTableFromFunction:
self.map = map_table_function self.map = map_table_function
class EmptyMappingTable: class EmptyMappingTable:
__implements__ = IMappingTable __implements__ = IMappingTable
def __init__(self, in_table_function): def __init__(self, in_table_function):
@ -145,7 +145,7 @@ class Profile:
for c in string: for c in string:
if stringprep.in_table_a1(c): if stringprep.in_table_a1(c):
raise UnicodeError, "Unassigned code point %s" % repr(c) raise UnicodeError, "Unassigned code point %s" % repr(c)
def check_bidirectionals(self, string): def check_bidirectionals(self, string):
found_LCat = False found_LCat = False
found_RandALCat = False found_RandALCat = False
@ -229,12 +229,12 @@ if crippled:
prohibiteds=[LookupTable([u' ', u'"', u'&', u"'", u'/', prohibiteds=[LookupTable([u' ', u'"', u'&', u"'", u'/',
u':', u'<', u'>', u'@'])], u':', u'<', u'>', u'@'])],
check_unassigneds=False, check_unassigneds=False,
check_bidi=False) check_bidi=False)
resourceprep = Profile(normalize=False, resourceprep = Profile(normalize=False,
check_unassigneds=False, check_unassigneds=False,
check_bidi=False) check_bidi=False)
else: else:
C_11 = LookupTableFromFunction(stringprep.in_table_c11) C_11 = LookupTableFromFunction(stringprep.in_table_c11)
C_12 = LookupTableFromFunction(stringprep.in_table_c12) C_12 = LookupTableFromFunction(stringprep.in_table_c12)

View file

@ -6,7 +6,7 @@
## - Nikos Kouremenos <nkour@jabber.org> ## - Nikos Kouremenos <nkour@jabber.org>
## - Dimitur Kirov <dkirov@gmail.com> ## - Dimitur Kirov <dkirov@gmail.com>
## - Travis Shirk <travis@pobox.com> ## - Travis Shirk <travis@pobox.com>
## - Stefan Bethge <stefan@lanpartei.de> ## - Stefan Bethge <stefan@lanpartei.de>
## ##
## This file is part of Gajim. ## This file is part of Gajim.
## ##

View file

@ -49,7 +49,7 @@ class Roster:
diffs[key] = self._data[key]['status'] diffs[key] = self._data[key]['status']
#print 'roster_zeroconf.py: diffs:' + str(diffs) #print 'roster_zeroconf.py: diffs:' + str(diffs)
return diffs return diffs
def setItem(self, jid, name='', groups=''): def setItem(self, jid, name='', groups=''):
#print 'roster_zeroconf.py: setItem %s' % jid #print 'roster_zeroconf.py: setItem %s' % jid
contact = self.zeroconf.get_contact(jid) contact = self.zeroconf.get_contact(jid)
@ -80,7 +80,7 @@ class Roster:
self._data[jid]['name'] = nm self._data[jid]['name'] = nm
else: else:
self._data[jid]['name'] = jid self._data[jid]['name'] = jid
if status == 'avail': if status == 'avail':
status = 'online' status = 'online'
self._data[jid]['txt_dict'] = txt_dict self._data[jid]['txt_dict'] = txt_dict
if 'msg' not in self._data[jid]['txt_dict']: if 'msg' not in self._data[jid]['txt_dict']:
@ -92,7 +92,7 @@ class Roster:
#print 'roster_zeroconf.py: delItem %s' % jid #print 'roster_zeroconf.py: delItem %s' % jid
if jid in self._data: if jid in self._data:
del self._data[jid] del self._data[jid]
def getItem(self, jid): def getItem(self, jid):
#print 'roster_zeroconf.py: getItem: %s' % jid #print 'roster_zeroconf.py: getItem: %s' % jid
if jid in self._data: if jid in self._data:
@ -101,16 +101,16 @@ class Roster:
def __getitem__(self, jid): def __getitem__(self, jid):
#print 'roster_zeroconf.py: __getitem__' #print 'roster_zeroconf.py: __getitem__'
return self._data[jid] return self._data[jid]
def getItems(self): def getItems(self):
#print 'roster_zeroconf.py: getItems' #print 'roster_zeroconf.py: getItems'
# Return list of all [bare] JIDs that the roster currently tracks. # Return list of all [bare] JIDs that the roster currently tracks.
return self._data.keys() return self._data.keys()
def keys(self): def keys(self):
#print 'roster_zeroconf.py: keys' #print 'roster_zeroconf.py: keys'
return self._data.keys() return self._data.keys()
def getRaw(self): def getRaw(self):
#print 'roster_zeroconf.py: getRaw' #print 'roster_zeroconf.py: getRaw'
return self._data return self._data
@ -118,7 +118,7 @@ class Roster:
def getResources(self, jid): def getResources(self, jid):
#print 'roster_zeroconf.py: getResources(%s)' % jid #print 'roster_zeroconf.py: getResources(%s)' % jid
return {} return {}
def getGroups(self, jid): def getGroups(self, jid):
return self._data[jid]['groups'] return self._data[jid]['groups']
@ -147,10 +147,10 @@ class Roster:
def Subscribe(self, jid): def Subscribe(self, jid):
pass pass
def Unsubscribe(self, jid): def Unsubscribe(self, jid):
pass pass
def Authorize(self, jid): def Authorize(self, jid):
pass pass

View file

@ -27,24 +27,24 @@ except ImportError, e:
from common.zeroconf.zeroconf import C_BARE_NAME, C_INTERFACE, C_PROTOCOL, C_DOMAIN from common.zeroconf.zeroconf import C_BARE_NAME, C_INTERFACE, C_PROTOCOL, C_DOMAIN
class Zeroconf: class Zeroconf:
def __init__(self, new_serviceCB, remove_serviceCB, name_conflictCB, def __init__(self, new_serviceCB, remove_serviceCB, name_conflictCB,
disconnected_CB, error_CB, name, host, port): disconnected_CB, error_CB, name, host, port):
self.avahi = None self.avahi = None
self.domain = None # specific domain to browse self.domain = None # specific domain to browse
self.stype = '_presence._tcp' self.stype = '_presence._tcp'
self.port = port # listening port that gets announced self.port = port # listening port that gets announced
self.username = name self.username = name
self.host = host self.host = host
self.txt = {} # service data self.txt = {} # service data
#XXX these CBs should be set to None when we destroy the object #XXX these CBs should be set to None when we destroy the object
# (go offline), because they create a circular reference # (go offline), because they create a circular reference
self.new_serviceCB = new_serviceCB self.new_serviceCB = new_serviceCB
self.remove_serviceCB = remove_serviceCB self.remove_serviceCB = remove_serviceCB
self.name_conflictCB = name_conflictCB self.name_conflictCB = name_conflictCB
self.disconnected_CB = disconnected_CB self.disconnected_CB = disconnected_CB
self.error_CB = error_CB self.error_CB = error_CB
self.service_browser = None self.service_browser = None
self.domain_browser = None self.domain_browser = None
self.bus = None self.bus = None
@ -60,10 +60,10 @@ class Zeroconf:
def entrygroup_commit_error_CB(self, err): def entrygroup_commit_error_CB(self, err):
# left blank for possible later usage # left blank for possible later usage
pass pass
def error_callback1(self, err): def error_callback1(self, err):
gajim.log.debug('Error while resolving: ' + str(err)) gajim.log.debug('Error while resolving: ' + str(err))
def error_callback(self, err): def error_callback(self, err):
gajim.log.debug(str(err)) gajim.log.debug(str(err))
# timeouts are non-critical # timeouts are non-critical
@ -75,7 +75,7 @@ class Zeroconf:
gajim.log.debug('Found service %s in domain %s on %i.%i.' % (name, domain, interface, protocol)) gajim.log.debug('Found service %s in domain %s on %i.%i.' % (name, domain, interface, protocol))
if not self.connected: if not self.connected:
return return
# synchronous resolving # synchronous resolving
self.server.ResolveService( int(interface), int(protocol), name, stype, \ self.server.ResolveService( int(interface), int(protocol), name, stype, \
domain, self.avahi.PROTO_UNSPEC, dbus.UInt32(0), \ domain, self.avahi.PROTO_UNSPEC, dbus.UInt32(0), \
@ -93,13 +93,13 @@ class Zeroconf:
return return
def new_service_type(self, interface, protocol, stype, domain, flags): def new_service_type(self, interface, protocol, stype, domain, flags):
# Are we already browsing this domain for this type? # Are we already browsing this domain for this type?
if self.service_browser: if self.service_browser:
return return
object_path = self.server.ServiceBrowserNew(interface, protocol, \ object_path = self.server.ServiceBrowserNew(interface, protocol, \
stype, domain, dbus.UInt32(0)) stype, domain, dbus.UInt32(0))
self.service_browser = dbus.Interface(self.bus.get_object(self.avahi.DBUS_NAME, \ self.service_browser = dbus.Interface(self.bus.get_object(self.avahi.DBUS_NAME, \
object_path) , self.avahi.DBUS_INTERFACE_SERVICE_BROWSER) object_path) , self.avahi.DBUS_INTERFACE_SERVICE_BROWSER)
self.service_browser.connect_to_signal('ItemNew', self.new_service_callback) self.service_browser.connect_to_signal('ItemNew', self.new_service_callback)
@ -109,7 +109,7 @@ class Zeroconf:
def new_domain_callback(self,interface, protocol, domain, flags): def new_domain_callback(self,interface, protocol, domain, flags):
if domain != "local": if domain != "local":
self.browse_domain(interface, protocol, domain) self.browse_domain(interface, protocol, domain)
def txt_array_to_dict(self, txt_array): def txt_array_to_dict(self, txt_array):
txt_dict = {} txt_dict = {}
for els in txt_array: for els in txt_array:
@ -131,8 +131,8 @@ class Zeroconf:
val = '' val = ''
txt_dict[key] = val.decode('utf-8') txt_dict[key] = val.decode('utf-8')
return txt_dict return txt_dict
def service_resolved_callback(self, interface, protocol, name, stype, domain, host, aprotocol, address, port, txt, flags): def service_resolved_callback(self, interface, protocol, name, stype, domain, host, aprotocol, address, port, txt, flags):
gajim.log.debug('Service data for service %s in domain %s on %i.%i:' gajim.log.debug('Service data for service %s in domain %s on %i.%i:'
% (name, domain, interface, protocol)) % (name, domain, interface, protocol))
gajim.log.debug('Host %s (%s), port %i, TXT data: %s' % (host, address, port, gajim.log.debug('Host %s (%s), port %i, TXT data: %s' % (host, address, port,
@ -142,10 +142,10 @@ class Zeroconf:
bare_name = name bare_name = name
if name.find('@') == -1: if name.find('@') == -1:
name = name + '@' + name name = name + '@' + name
# we don't want to see ourselves in the list # we don't want to see ourselves in the list
if name != self.name: if name != self.name:
self.contacts[name] = (name, domain, interface, protocol, host, address, port, self.contacts[name] = (name, domain, interface, protocol, host, address, port,
bare_name, txt) bare_name, txt)
self.new_serviceCB(name) self.new_serviceCB(name)
else: else:
@ -230,14 +230,14 @@ class Zeroconf:
# create an EntryGroup for publishing # create an EntryGroup for publishing
self.entrygroup = dbus.Interface(self.bus.get_object(self.avahi.DBUS_NAME, self.server.EntryGroupNew()), self.avahi.DBUS_INTERFACE_ENTRY_GROUP) self.entrygroup = dbus.Interface(self.bus.get_object(self.avahi.DBUS_NAME, self.server.EntryGroupNew()), self.avahi.DBUS_INTERFACE_ENTRY_GROUP)
self.entrygroup.connect_to_signal('StateChanged', self.entrygroup_state_changed_callback) self.entrygroup.connect_to_signal('StateChanged', self.entrygroup_state_changed_callback)
txt = {} txt = {}
#remove empty keys #remove empty keys
for key,val in self.txt.iteritems(): for key,val in self.txt.iteritems():
if val: if val:
txt[key] = val txt[key] = val
txt['port.p2pj'] = self.port txt['port.p2pj'] = self.port
txt['version'] = 1 txt['version'] = 1
txt['txtvers'] = 1 txt['txtvers'] = 1
@ -256,16 +256,16 @@ class Zeroconf:
'', dbus.UInt16(self.port), self.avahi_txt(), '', dbus.UInt16(self.port), self.avahi_txt(),
reply_handler=self.service_added_callback, reply_handler=self.service_added_callback,
error_handler=self.service_add_fail_callback) error_handler=self.service_add_fail_callback)
self.entrygroup.Commit(reply_handler=self.service_committed_callback, self.entrygroup.Commit(reply_handler=self.service_committed_callback,
error_handler=self.entrygroup_commit_error_CB) error_handler=self.entrygroup_commit_error_CB)
return True return True
except dbus.DBusException, e: except dbus.DBusException, e:
gajim.log.debug(str(e)) gajim.log.debug(str(e))
return False return False
def announce(self): def announce(self):
if not self.connected: if not self.connected:
return False return False
@ -288,7 +288,7 @@ class Zeroconf:
self.entrygroup._obj = None self.entrygroup._obj = None
self.entrygroup = None self.entrygroup = None
self.announced = False self.announced = False
return True return True
else: else:
return False return False
@ -318,8 +318,8 @@ class Zeroconf:
return True return True
try: try:
self.bus = dbus.SystemBus() self.bus = dbus.SystemBus()
self.bus.add_signal_receiver(self.avahi_dbus_connect_cb, self.bus.add_signal_receiver(self.avahi_dbus_connect_cb,
"NameOwnerChanged", "org.freedesktop.DBus", "NameOwnerChanged", "org.freedesktop.DBus",
arg0="org.freedesktop.Avahi") arg0="org.freedesktop.Avahi")
except Exception, e: except Exception, e:
# System bus is not present # System bus is not present
@ -345,7 +345,7 @@ class Zeroconf:
try: try:
self.server = dbus.Interface(self.bus.get_object(self.avahi.DBUS_NAME, \ self.server = dbus.Interface(self.bus.get_object(self.avahi.DBUS_NAME, \
self.avahi.DBUS_PATH_SERVER), self.avahi.DBUS_INTERFACE_SERVER) self.avahi.DBUS_PATH_SERVER), self.avahi.DBUS_INTERFACE_SERVER)
self.server.connect_to_signal('StateChanged', self.server.connect_to_signal('StateChanged',
self.server_state_changed_callback) self.server_state_changed_callback)
except Exception, e: except Exception, e:
# Avahi service is not present # Avahi service is not present
@ -359,7 +359,7 @@ class Zeroconf:
self.name = self.username + '@' + self.host # service name self.name = self.username + '@' + self.host # service name
if not self.connect_avahi(): if not self.connect_avahi():
return False return False
self.connected = True self.connected = True
# start browsing # start browsing
if self.domain is None: if self.domain is None:
@ -375,7 +375,7 @@ class Zeroconf:
self.domain_browser.connect_to_signal('Failure', self.error_callback) self.domain_browser.connect_to_signal('Failure', self.error_callback)
else: else:
self.browse_domain(self.avahi.IF_UNSPEC, self.avahi.PROTO_UNSPEC, self.domain) self.browse_domain(self.avahi.IF_UNSPEC, self.avahi.PROTO_UNSPEC, self.domain)
return True return True
def disconnect(self): def disconnect(self):
@ -414,7 +414,7 @@ class Zeroconf:
if not jid in self.contacts: if not jid in self.contacts:
return None return None
return self.contacts[jid] return self.contacts[jid]
def update_txt(self, show = None): def update_txt(self, show = None):
if show: if show:
self.txt['status'] = self.replace_show(show) self.txt['status'] = self.replace_show(show)

View file

@ -31,23 +31,23 @@ except ImportError, e:
resolve_timeout = 1 resolve_timeout = 1
class Zeroconf: class Zeroconf:
def __init__(self, new_serviceCB, remove_serviceCB, name_conflictCB, def __init__(self, new_serviceCB, remove_serviceCB, name_conflictCB,
disconnected_CB, error_CB, name, host, port): disconnected_CB, error_CB, name, host, port):
self.domain = None # specific domain to browse self.domain = None # specific domain to browse
self.stype = '_presence._tcp' self.stype = '_presence._tcp'
self.port = port # listening port that gets announced self.port = port # listening port that gets announced
self.username = name self.username = name
self.host = host self.host = host
self.txt = pybonjour.TXTRecord() # service data self.txt = pybonjour.TXTRecord() # service data
# XXX these CBs should be set to None when we destroy the object # XXX these CBs should be set to None when we destroy the object
# (go offline), because they create a circular reference # (go offline), because they create a circular reference
self.new_serviceCB = new_serviceCB self.new_serviceCB = new_serviceCB
self.remove_serviceCB = remove_serviceCB self.remove_serviceCB = remove_serviceCB
self.name_conflictCB = name_conflictCB self.name_conflictCB = name_conflictCB
self.disconnected_CB = disconnected_CB self.disconnected_CB = disconnected_CB
self.error_CB = error_CB self.error_CB = error_CB
self.contacts = {} # all current local contacts with data self.contacts = {} # all current local contacts with data
self.connected = False self.connected = False
self.announced = False self.announced = False
@ -64,7 +64,7 @@ class Zeroconf:
if not (flags & pybonjour.kDNSServiceFlagsAdd): if not (flags & pybonjour.kDNSServiceFlagsAdd):
self.remove_service_callback(serviceName) self.remove_service_callback(serviceName)
return return
# asynchronous resolving # asynchronous resolving
resolve_sdRef = pybonjour.DNSServiceResolve(0, interfaceIndex, serviceName, regtype, replyDomain, self.service_resolved_callback) resolve_sdRef = pybonjour.DNSServiceResolve(0, interfaceIndex, serviceName, regtype, replyDomain, self.service_resolved_callback)
@ -100,9 +100,9 @@ class Zeroconf:
items = pybonjour.TXTRecord.parse(txt)._items items = pybonjour.TXTRecord.parse(txt)._items
return dict((v[0], v[1]) for v in items.values()) return dict((v[0], v[1]) for v in items.values())
def service_resolved_callback(self, sdRef, flags, interfaceIndex, errorCode, fullname, def service_resolved_callback(self, sdRef, flags, interfaceIndex, errorCode, fullname,
hosttarget, port, txtRecord): hosttarget, port, txtRecord):
# TODO: do proper decoding... # TODO: do proper decoding...
escaping= { escaping= {
r'\.': '.', r'\.': '.',
@ -114,7 +114,7 @@ class Zeroconf:
result = re.split('(?<!\\\\)\.', fullname) result = re.split('(?<!\\\\)\.', fullname)
name = result[0] name = result[0]
protocol, domain = result[2:4] protocol, domain = result[2:4]
# Replace the escaped values # Replace the escaped values
for src, trg in escaping.items(): for src, trg in escaping.items():
name = name.replace(src, trg) name = name.replace(src, trg)
@ -126,11 +126,11 @@ class Zeroconf:
if not self.connected: if not self.connected:
return return
bare_name = name bare_name = name
if '@' not in name: if '@' not in name:
name = name + '@' + name name = name + '@' + name
# we don't want to see ourselves in the list # we don't want to see ourselves in the list
if name != self.name: if name != self.name:
self.contacts[name] = (name, domain, interfaceIndex, protocol, hosttarget, hosttarget, port, bare_name, txtRecord) self.contacts[name] = (name, domain, interfaceIndex, protocol, hosttarget, hosttarget, port, bare_name, txtRecord)
@ -146,10 +146,10 @@ class Zeroconf:
self.resolved.append(True) self.resolved.append(True)
# different handler when resolving all contacts # different handler when resolving all contacts
def service_resolved_all_callback(self, sdRef, flags, interfaceIndex, errorCode, fullname, hosttarget, port, txtRecord): def service_resolved_all_callback(self, sdRef, flags, interfaceIndex, errorCode, fullname, hosttarget, port, txtRecord):
if not self.connected: if not self.connected:
return return
escaping= { escaping= {
r'\.': '.', r'\.': '.',
r'\032': ' ', r'\032': ' ',
@ -157,7 +157,7 @@ class Zeroconf:
} }
name, stype, protocol, domain, dummy = fullname.split('.') name, stype, protocol, domain, dummy = fullname.split('.')
# Replace the escaped values # Replace the escaped values
for src, trg in escaping.items(): for src, trg in escaping.items():
name = name.replace(src, trg) name = name.replace(src, trg)
@ -165,7 +165,7 @@ class Zeroconf:
bare_name = name bare_name = name
if name.find('@') == -1: if name.find('@') == -1:
name = name + '@' + name name = name + '@' + name
# we don't want to see ourselves in the list # we don't want to see ourselves in the list
if name != self.name: if name != self.name:
self.contacts[name] = (name, domain, interfaceIndex, protocol, hosttarget, hosttarget, port, bare_name, txtRecord) self.contacts[name] = (name, domain, interfaceIndex, protocol, hosttarget, hosttarget, port, bare_name, txtRecord)
@ -201,12 +201,12 @@ class Zeroconf:
def create_service(self): def create_service(self):
txt = {} txt = {}
#remove empty keys #remove empty keys
for key,val in self.txt: for key,val in self.txt:
if val: if val:
txt[key] = val txt[key] = val
txt['port.p2pj'] = self.port txt['port.p2pj'] = self.port
txt['version'] = 1 txt['version'] = 1
txt['txtvers'] = 1 txt['txtvers'] = 1
@ -218,7 +218,7 @@ class Zeroconf:
txt['status'] = 'avail' txt['status'] = 'avail'
self.txt = pybonjour.TXTRecord(txt, strict=True) self.txt = pybonjour.TXTRecord(txt, strict=True)
try: try:
sdRef = pybonjour.DNSServiceRegister(name = self.name, sdRef = pybonjour.DNSServiceRegister(name = self.name,
regtype = self.stype, port = self.port, txtRecord = self.txt, regtype = self.stype, port = self.port, txtRecord = self.txt,
@ -257,7 +257,7 @@ class Zeroconf:
self.name = self.username + '@' + self.host # service name self.name = self.username + '@' + self.host # service name
self.connected = True self.connected = True
# start browsing # start browsing
if self.domain is None: if self.domain is None:
# Explicitly browse .local # Explicitly browse .local
@ -268,7 +268,7 @@ class Zeroconf:
else: else:
self.browse_domain(self.domain) self.browse_domain(self.domain)
return True return True
def disconnect(self): def disconnect(self):
@ -276,8 +276,8 @@ class Zeroconf:
self.connected = False self.connected = False
self.browse_sdRef.close() self.browse_sdRef.close()
self.remove_announce() self.remove_announce()
def browse_domain(self, domain=None): def browse_domain(self, domain=None):
gajim.log.debug('starting to browse') gajim.log.debug('starting to browse')
try: try:
@ -320,7 +320,7 @@ class Zeroconf:
if not jid in self.contacts: if not jid in self.contacts:
return None return None
return self.contacts[jid] return self.contacts[jid]
def update_txt(self, show = None): def update_txt(self, show = None):
if show: if show:
self.txt['status'] = self.replace_show(show) self.txt['status'] = self.replace_show(show)

View file

@ -101,7 +101,7 @@ class PreferencesWindow:
# Display avatars in roster # Display avatars in roster
st = gajim.config.get('show_avatars_in_roster') st = gajim.config.get('show_avatars_in_roster')
self.xml.get_widget('show_avatars_in_roster_checkbutton'). \ self.xml.get_widget('show_avatars_in_roster_checkbutton'). \
set_active(st) set_active(st)
# Display status msg under contact name in roster # Display status msg under contact name in roster
st = gajim.config.get('show_status_msgs_in_roster') st = gajim.config.get('show_status_msgs_in_roster')
@ -222,7 +222,7 @@ class PreferencesWindow:
model.append([preview, l[i]]) model.append([preview, l[i]])
if gajim.config.get('iconset') == l[i]: if gajim.config.get('iconset') == l[i]:
self.iconset_combobox.set_active(i) self.iconset_combobox.set_active(i)
# Use transports iconsets # Use transports iconsets
st = gajim.config.get('use_transports_iconsets') st = gajim.config.get('use_transports_iconsets')
self.xml.get_widget('transports_iconsets_checkbutton').set_active(st) self.xml.get_widget('transports_iconsets_checkbutton').set_active(st)
@ -512,7 +512,7 @@ class PreferencesWindow:
self.theme_preferences = None self.theme_preferences = None
self.notebook.set_current_page(0) self.notebook.set_current_page(0)
self.window.show_all() self.window.show_all()
gtkgui_helpers.possibly_move_window_in_current_desktop(self.window) gtkgui_helpers.possibly_move_window_in_current_desktop(self.window)
@ -961,7 +961,7 @@ class PreferencesWindow:
def on_log_show_changes_checkbutton_toggled(self, widget): def on_log_show_changes_checkbutton_toggled(self, widget):
self.on_checkbutton_toggled(widget, 'log_contact_status_changes') self.on_checkbutton_toggled(widget, 'log_contact_status_changes')
def on_log_encrypted_chats_checkbutton_toggled(self, widget): def on_log_encrypted_chats_checkbutton_toggled(self, widget):
self.on_checkbutton_toggled(widget, 'log_encrypted_sessions') self.on_checkbutton_toggled(widget, 'log_encrypted_sessions')
@ -1042,7 +1042,7 @@ class PreferencesWindow:
model.set_sort_column_id(1, gtk.SORT_ASCENDING) model.set_sort_column_id(1, gtk.SORT_ASCENDING)
# NOTE: sounds_ui_names MUST have all items of # NOTE: sounds_ui_names MUST have all items of
# sounds = gajim.config.get_per('soundevents') as keys # sounds = gajim.config.get_per('soundevents') as keys
sounds_dict = { sounds_dict = {
'first_message_received': _('First Message Received'), 'first_message_received': _('First Message Received'),
'next_message_received_focused': _('Next Message Received Focused'), 'next_message_received_focused': _('Next Message Received Focused'),
@ -1377,7 +1377,7 @@ class AccountsWindow:
gajim.connections[self.current_account].connected > 0: gajim.connections[self.current_account].connected > 0:
def login(account, show_before, status_before): def login(account, show_before, status_before):
''' login with previous status''' ''' login with previous status'''
# first make sure connection is really closed, # first make sure connection is really closed,
# 0.5 may not be enough # 0.5 may not be enough
gajim.connections[account].disconnect(True) gajim.connections[account].disconnect(True)
gajim.interface.roster.send_status(account, show_before, gajim.interface.roster.send_status(account, show_before,
@ -2115,7 +2115,7 @@ class AccountsWindow:
gajim.interface.roster.setup_and_draw_roster() gajim.interface.roster.setup_and_draw_roster()
def on_enable_zeroconf_checkbutton2_toggled(self, widget): def on_enable_zeroconf_checkbutton2_toggled(self, widget):
# don't do anything if there is an account with the local name but is a # don't do anything if there is an account with the local name but is a
# normal account # normal account
if gajim.ZEROCONF_ACC_NAME in gajim.connections and not \ if gajim.ZEROCONF_ACC_NAME in gajim.connections and not \
gajim.connections[gajim.ZEROCONF_ACC_NAME].is_zeroconf: gajim.connections[gajim.ZEROCONF_ACC_NAME].is_zeroconf:
@ -3536,7 +3536,7 @@ class ManagePEPServicesWindow:
gajim.connections[self.account].send_pb_configure(our_jid, node, form) gajim.connections[self.account].send_pb_configure(our_jid, node, form)
window = dialogs.DataFormWindow(form, (on_ok, node)) window = dialogs.DataFormWindow(form, (on_ok, node))
title = "Configure %s" % node title = "Configure %s" % node
window.set_title(title) window.set_title(title)
window.show_all() window.show_all()
# vim: se ts=3: # vim: se ts=3:

View file

@ -667,7 +667,7 @@ class ConversationTextview:
def on_textview_populate_popup(self, textview, menu): def on_textview_populate_popup(self, textview, menu):
'''we override the default context menu and we prepend Clear '''we override the default context menu and we prepend Clear
(only if used_in_history_window is False) (only if used_in_history_window is False)
and if we have sth selected we show a submenu with actions on and if we have sth selected we show a submenu with actions on
the phrase (see on_conversation_textview_button_press_event)''' the phrase (see on_conversation_textview_button_press_event)'''
separator_menuitem_was_added = False separator_menuitem_was_added = False

View file

@ -110,7 +110,7 @@ class DataFormWidget(gtk.Alignment, object):
# "private" methods # "private" methods
# we have actually two different kinds of data forms: one is a simple form to fill, # we have actually two different kinds of data forms: one is a simple form to fill,
# second is a table with several records; # second is a table with several records;
def empty_method(self): def empty_method(self):
pass pass
@ -326,7 +326,7 @@ class SingleForm(gtk.Table, object):
if field.label is None: if field.label is None:
commonlabel = False commonlabel = False
leftattach = 0 leftattach = 0
commonwidget = False commonwidget = False
widget = gtk.Label(field.value) widget = gtk.Label(field.value)
widget.set_line_wrap(True) widget.set_line_wrap(True)

View file

@ -106,7 +106,7 @@ class EditGroupsDialog:
'''add group group to all contacts and all their brothers''' '''add group group to all contacts and all their brothers'''
for (contact, account) in self.list_: for (contact, account) in self.list_:
gajim.interface.roster.add_contact_to_groups(contact.jid, account, [group]) gajim.interface.roster.add_contact_to_groups(contact.jid, account, [group])
# FIXME: Ugly workaround. Maybe we haven't been in any group (defaults to General) # FIXME: Ugly workaround. Maybe we haven't been in any group (defaults to General)
gajim.interface.roster.draw_group(_('General'), account) gajim.interface.roster.draw_group(_('General'), account)
@ -487,7 +487,7 @@ class ChangeMoodDialog:
self.mood_buttons[mood].connect('clicked', self.mood_buttons[mood].connect('clicked',
self.on_mood_button_clicked, mood) self.on_mood_button_clicked, mood)
table.attach(self.mood_buttons[mood], x, x + 1, y, y + 1) table.attach(self.mood_buttons[mood], x, x + 1, y, y + 1)
# Calculate the next position # Calculate the next position
x += 1 x += 1
if x >= self.COLS: if x >= self.COLS:
@ -1036,7 +1036,7 @@ class AboutDialog:
dlg.set_logo(pixbuf) dlg.set_logo(pixbuf)
#here you write your name in the form Name FamilyName <someone@somewhere> #here you write your name in the form Name FamilyName <someone@somewhere>
dlg.set_translator_credits(_('translator-credits')) dlg.set_translator_credits(_('translator-credits'))
thanks_artists_file_path = self.get_path('THANKS.artists') thanks_artists_file_path = self.get_path('THANKS.artists')
if thanks_artists_file_path: if thanks_artists_file_path:
artists_text = open(thanks_artists_file_path).read() artists_text = open(thanks_artists_file_path).read()
@ -1690,7 +1690,7 @@ class JoinGroupchatWindow:
self._password_entry.set_text(password) self._password_entry.set_text(password)
self.xml.signal_autoconnect(self) self.xml.signal_autoconnect(self)
# now add us to open windows # now add us to open windows
gajim.interface.instances[account]['join_gc'] = self gajim.interface.instances[account]['join_gc'] = self
if len(gajim.connections) > 1: if len(gajim.connections) > 1:
title = _('Join Group Chat with account %s') % account title = _('Join Group Chat with account %s') % account
else: else:

View file

@ -522,7 +522,7 @@ _('Without a connection, you can not browse available services'))
bannerfont = gajim.config.get_per('themes', theme, 'bannerfont') bannerfont = gajim.config.get_per('themes', theme, 'bannerfont')
bannerfontattrs = gajim.config.get_per('themes', theme, bannerfontattrs = gajim.config.get_per('themes', theme,
'bannerfontattrs') 'bannerfontattrs')
if bannerfont: if bannerfont:
font = pango.FontDescription(bannerfont) font = pango.FontDescription(bannerfont)
else: else:
@ -533,10 +533,10 @@ _('Without a connection, you can not browse available services'))
font.set_weight(pango.WEIGHT_HEAVY) font.set_weight(pango.WEIGHT_HEAVY)
if 'I' in bannerfontattrs: if 'I' in bannerfontattrs:
font.set_style(pango.STYLE_ITALIC) font.set_style(pango.STYLE_ITALIC)
font_attrs = 'font_desc="%s"' % font.to_string() font_attrs = 'font_desc="%s"' % font.to_string()
font_size = font.get_size() font_size = font.get_size()
# in case there is no font specified we use x-large font size # in case there is no font specified we use x-large font size
if font_size == 0: if font_size == 0:
font_attrs = '%s size="large"' % font_attrs font_attrs = '%s size="large"' % font_attrs
@ -546,7 +546,7 @@ _('Without a connection, you can not browse available services'))
markup = '%s\n<span font_desc="%s" size="small">%s</span>' % \ markup = '%s\n<span font_desc="%s" size="small">%s</span>' % \
(markup, font.to_string(), text_after) (markup, font.to_string(), text_after)
self.banner.set_markup(markup) self.banner.set_markup(markup)
def paint_banner(self): def paint_banner(self):
'''Repaint the banner with theme color''' '''Repaint the banner with theme color'''
theme = gajim.config.get('roster_theme') theme = gajim.config.get('roster_theme')
@ -559,7 +559,7 @@ _('Without a connection, you can not browse available services'))
default_bg = False default_bg = False
else: else:
default_bg = True default_bg = True
if textcolor: if textcolor:
color = gtk.gdk.color_parse(textcolor) color = gtk.gdk.color_parse(textcolor)
self.banner.modify_fg(gtk.STATE_NORMAL, color) self.banner.modify_fg(gtk.STATE_NORMAL, color)
@ -570,22 +570,22 @@ _('Without a connection, you can not browse available services'))
self._on_style_set_event(self.banner, None, default_fg, default_bg) self._on_style_set_event(self.banner, None, default_fg, default_bg)
if self.browser: if self.browser:
self.browser.update_theme() self.browser.update_theme()
def disconnect_style_event(self): def disconnect_style_event(self):
if self.style_event_id: if self.style_event_id:
self.banner.disconnect(self.style_event_id) self.banner.disconnect(self.style_event_id)
self.style_event_id = 0 self.style_event_id = 0
def connect_style_event(self, set_fg = False, set_bg = False): def connect_style_event(self, set_fg = False, set_bg = False):
self.disconnect_style_event() self.disconnect_style_event()
self.style_event_id = self.banner.connect('style-set', self.style_event_id = self.banner.connect('style-set',
self._on_style_set_event, set_fg, set_bg) self._on_style_set_event, set_fg, set_bg)
def _on_style_set_event(self, widget, style, *opts): def _on_style_set_event(self, widget, style, *opts):
''' set style of widget from style class *.Frame.Eventbox ''' set style of widget from style class *.Frame.Eventbox
opts[0] == True -> set fg color opts[0] == True -> set fg color
opts[1] == True -> set bg color ''' opts[1] == True -> set bg color '''
self.disconnect_style_event() self.disconnect_style_event()
if opts[1]: if opts[1]:
bg_color = widget.style.bg[gtk.STATE_SELECTED] bg_color = widget.style.bg[gtk.STATE_SELECTED]
@ -595,7 +595,7 @@ _('Without a connection, you can not browse available services'))
self.banner.modify_fg(gtk.STATE_NORMAL, fg_color) self.banner.modify_fg(gtk.STATE_NORMAL, fg_color)
self.banner.ensure_style() self.banner.ensure_style()
self.connect_style_event(opts[0], opts[1]) self.connect_style_event(opts[0], opts[1])
def destroy(self, chain = False): def destroy(self, chain = False):
'''Close the browser. This can optionally close its children and '''Close the browser. This can optionally close its children and
propagate to the parent. This should happen on actions like register, propagate to the parent. This should happen on actions like register,
@ -808,7 +808,7 @@ class AgentBrowser:
if self.browse_button: if self.browse_button:
self.browse_button.destroy() self.browse_button.destroy()
self.browse_button = None self.browse_button = None
def _set_title(self, jid, node, identities, features, data): def _set_title(self, jid, node, identities, features, data):
'''Set the window title based on agent info.''' '''Set the window title based on agent info.'''
# Set the banner and window title # Set the banner and window title
@ -1945,14 +1945,14 @@ class DiscussionGroupsBrowser(AgentBrowser):
groupnode = model.get_value(iter_, 1) # 1 = groupnode groupnode = model.get_value(iter_, 1) # 1 = groupnode
gajim.connections[self.account].send_pb_subscribe(self.jid, groupnode, self._subscribeCB, groupnode) gajim.connections[self.account].send_pb_subscribe(self.jid, groupnode, self._subscribeCB, groupnode)
def on_unsubscribe_button_clicked(self, widget): def on_unsubscribe_button_clicked(self, widget):
'''Called when 'unsubscribe' button is pressed. Send unsubscription request.''' '''Called when 'unsubscribe' button is pressed. Send unsubscription request.'''
model, iter_ = self.window.services_treeview.get_selection().get_selected() model, iter_ = self.window.services_treeview.get_selection().get_selected()
if iter_ is None: return if iter_ is None: return
groupnode = model.get_value(iter_, 1) # 1 = groupnode groupnode = model.get_value(iter_, 1) # 1 = groupnode
gajim.connections[self.account].send_pb_unsubscribe(self.jid, groupnode, self._unsubscribeCB, groupnode) gajim.connections[self.account].send_pb_unsubscribe(self.jid, groupnode, self._unsubscribeCB, groupnode)
def _subscriptionsCB(self, conn, request): def _subscriptionsCB(self, conn, request):
@ -1961,7 +1961,7 @@ class DiscussionGroupsBrowser(AgentBrowser):
try: try:
subscriptions = request.getTag('pubsub').getTag('subscriptions') subscriptions = request.getTag('pubsub').getTag('subscriptions')
except Exception: except Exception:
return return
groups = set() groups = set()
for child in subscriptions.getTags('subscription'): for child in subscriptions.getTags('subscription'):

View file

@ -83,11 +83,11 @@ class FeaturesWindow:
_('Requires python-gnome2-extras or compilation of gtkspell module from Gajim sources.'), _('Requires python-gnome2-extras or compilation of gtkspell module from Gajim sources.'),
_('Feature not available under Windows.')), _('Feature not available under Windows.')),
_('Notification-daemon'): (self.notification_available, _('Notification-daemon'): (self.notification_available,
_('Passive popups notifying for new events.'), _('Passive popups notifying for new events.'),
_('Requires python-notify or instead python-dbus in conjunction with notification-daemon.'), _('Requires python-notify or instead python-dbus in conjunction with notification-daemon.'),
_('Feature not available under Windows.')), _('Feature not available under Windows.')),
_('Trayicon'): (self.trayicon_available, _('Trayicon'): (self.trayicon_available,
_('A icon in systemtray reflecting the current presence.'), _('A icon in systemtray reflecting the current presence.'),
_('Requires python-gnome2-extras or compiled trayicon module from Gajim sources.'), _('Requires python-gnome2-extras or compiled trayicon module from Gajim sources.'),
_('Requires PyGTK >= 2.10.')), _('Requires PyGTK >= 2.10.')),
_('Idle'): (self.idle_available, _('Idle'): (self.idle_available,

View file

@ -175,7 +175,7 @@ class FileTransfersWindow:
helpers.convert_bytes(file_props['size']) helpers.convert_bytes(file_props['size'])
if file_props['type'] == 'r': if file_props['type'] == 'r':
jid = unicode(file_props['sender']).split('/')[0] jid = unicode(file_props['sender']).split('/')[0]
sender_name = gajim.contacts.get_first_contact_from_jid( sender_name = gajim.contacts.get_first_contact_from_jid(
file_props['tt_account'], jid).get_shown_name() file_props['tt_account'], jid).get_shown_name()
sender = sender_name sender = sender_name
else: else:
@ -185,7 +185,7 @@ class FileTransfersWindow:
sectext += '\n\t' +_('Recipient: ') sectext += '\n\t' +_('Recipient: ')
if file_props['type'] == 's': if file_props['type'] == 's':
jid = unicode(file_props['receiver']).split('/')[0] jid = unicode(file_props['receiver']).split('/')[0]
receiver_name = gajim.contacts.get_first_contact_from_jid( receiver_name = gajim.contacts.get_first_contact_from_jid(
file_props['tt_account'], jid).get_shown_name() file_props['tt_account'], jid).get_shown_name()
recipient = receiver_name recipient = receiver_name
else: else:
@ -194,7 +194,7 @@ class FileTransfersWindow:
sectext += recipient sectext += recipient
if file_props['type'] == 'r': if file_props['type'] == 'r':
sectext += '\n\t' +_('Saved in: %s') % file_path sectext += '\n\t' +_('Saved in: %s') % file_path
dialog = dialogs.HigDialog(None, gtk.MESSAGE_INFO, gtk.BUTTONS_NONE, dialog = dialogs.HigDialog(None, gtk.MESSAGE_INFO, gtk.BUTTONS_NONE,
_('File transfer completed'), sectext) _('File transfer completed'), sectext)
if file_props['type'] == 'r': if file_props['type'] == 'r':
button = gtk.Button(_('_Open Containing Folder')) button = gtk.Button(_('_Open Containing Folder'))
@ -207,13 +207,13 @@ class FileTransfersWindow:
dialog.show_all() dialog.show_all()
def show_request_error(self, file_props): def show_request_error(self, file_props):
''' show error dialog to the recipient saying that transfer ''' show error dialog to the recipient saying that transfer
has been canceled''' has been canceled'''
dialogs.InformationDialog(_('File transfer cancelled'), _('Connection with peer cannot be established.')) dialogs.InformationDialog(_('File transfer cancelled'), _('Connection with peer cannot be established.'))
self.tree.get_selection().unselect_all() self.tree.get_selection().unselect_all()
def show_send_error(self, file_props): def show_send_error(self, file_props):
''' show error dialog to the sender saying that transfer ''' show error dialog to the sender saying that transfer
has been canceled''' has been canceled'''
dialogs.InformationDialog(_('File transfer cancelled'), dialogs.InformationDialog(_('File transfer cancelled'),
_('Connection with peer cannot be established.')) _('Connection with peer cannot be established.'))
@ -233,9 +233,9 @@ _('Connection with peer cannot be established.'))
self.tree.get_selection().unselect_all() self.tree.get_selection().unselect_all()
def show_file_send_request(self, account, contact): def show_file_send_request(self, account, contact):
desc_entry = gtk.Entry() desc_entry = gtk.Entry()
def on_ok(widget): def on_ok(widget):
file_dir = None file_dir = None
files_path_list = dialog.get_filenames() files_path_list = dialog.get_filenames()
@ -249,7 +249,7 @@ _('Connection with peer cannot be established.'))
gajim.config.set('last_send_dir', file_dir) gajim.config.set('last_send_dir', file_dir)
dialog.destroy() dialog.destroy()
dialog = dialogs.FileChooserDialog(_('Choose File to Send...'), dialog = dialogs.FileChooserDialog(_('Choose File to Send...'),
gtk.FILE_CHOOSER_ACTION_OPEN, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL), gtk.FILE_CHOOSER_ACTION_OPEN, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
gtk.RESPONSE_OK, gtk.RESPONSE_OK,
True, # select multiple true as we can select many files to send True, # select multiple true as we can select many files to send
@ -263,13 +263,13 @@ _('Connection with peer cannot be established.'))
# FIXME: add send icon to this button (JUMP_TO) # FIXME: add send icon to this button (JUMP_TO)
dialog.add_action_widget(btn, gtk.RESPONSE_OK) dialog.add_action_widget(btn, gtk.RESPONSE_OK)
dialog.set_default_response(gtk.RESPONSE_OK) dialog.set_default_response(gtk.RESPONSE_OK)
desc_hbox = gtk.HBox(False, 5) desc_hbox = gtk.HBox(False, 5)
desc_hbox.pack_start(gtk.Label(_('Description: ')),False,False,0) desc_hbox.pack_start(gtk.Label(_('Description: ')),False,False,0)
desc_hbox.pack_start(desc_entry,True,True,0) desc_hbox.pack_start(desc_entry,True,True,0)
dialog.vbox.pack_start(desc_hbox, False, False, 0) dialog.vbox.pack_start(desc_hbox, False, False, 0)
btn.show() btn.show()
desc_hbox.show_all() desc_hbox.show_all()
@ -287,7 +287,7 @@ _('Connection with peer cannot be established.'))
(jid, resource) = contact.split('/', 1) (jid, resource) = contact.split('/', 1)
contact = gajim.contacts.create_contact(jid=jid, resource=resource) contact = gajim.contacts.create_contact(jid=jid, resource=resource)
file_name = os.path.split(file_path)[1] file_name = os.path.split(file_path)[1]
file_props = self.get_send_file_props(account, contact, file_props = self.get_send_file_props(account, contact,
file_path, file_name, file_desc) file_path, file_name, file_desc)
if file_props is None: if file_props is None:
return False return False
@ -366,9 +366,9 @@ _('Connection with peer cannot be established.'))
gajim.connections[account].send_file_rejection(file_props) gajim.connections[account].send_file_rejection(file_props)
dialog2 = dialogs.FileChooserDialog( dialog2 = dialogs.FileChooserDialog(
title_text = _('Save File as...'), title_text = _('Save File as...'),
action = gtk.FILE_CHOOSER_ACTION_SAVE, action = gtk.FILE_CHOOSER_ACTION_SAVE,
buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
gtk.STOCK_SAVE, gtk.RESPONSE_OK), gtk.STOCK_SAVE, gtk.RESPONSE_OK),
default_response = gtk.RESPONSE_OK, default_response = gtk.RESPONSE_OK,
current_folder = gajim.config.get('last_save_dir'), current_folder = gajim.config.get('last_save_dir'),
@ -385,7 +385,7 @@ _('Connection with peer cannot be established.'))
dialog = dialogs.NonModalConfirmationDialog(prim_text, sec_text, dialog = dialogs.NonModalConfirmationDialog(prim_text, sec_text,
on_response_ok = (on_response_ok, account, contact, file_props), on_response_ok = (on_response_ok, account, contact, file_props),
on_response_cancel = (on_response_cancel, account, file_props)) on_response_cancel = (on_response_cancel, account, file_props))
dialog.connect('delete-event', lambda widget, event: dialog.connect('delete-event', lambda widget, event:
on_response_cancel(widget, account, file_props)) on_response_cancel(widget, account, file_props))
dialog.popup() dialog.popup()
@ -506,21 +506,21 @@ _('Connection with peer cannot be established.'))
# remaining time # remaining time
if 'offset' in file_props and file_props['offset']: if 'offset' in file_props and file_props['offset']:
transfered_size -= file_props['offset'] transfered_size -= file_props['offset']
full_size -= file_props['offset'] full_size -= file_props['offset']
if file_props['elapsed-time'] > 0: if file_props['elapsed-time'] > 0:
file_props['transfered_size'].append((file_props['last-time'], transfered_size)) file_props['transfered_size'].append((file_props['last-time'], transfered_size))
if len(file_props['transfered_size']) > 6: if len(file_props['transfered_size']) > 6:
file_props['transfered_size'].pop(0) file_props['transfered_size'].pop(0)
eta, speed = self._get_eta_and_speed(full_size, transfered_size, eta, speed = self._get_eta_and_speed(full_size, transfered_size,
file_props) file_props)
self.model.set(iter_, C_PROGRESS, text) self.model.set(iter_, C_PROGRESS, text)
self.model.set(iter_, C_PERCENT, int(percent)) self.model.set(iter_, C_PERCENT, int(percent))
text = self._format_time(eta) text = self._format_time(eta)
text += '\n' text += '\n'
#This should make the string Kb/s, #This should make the string Kb/s,
#where 'Kb' part is taken from %s. #where 'Kb' part is taken from %s.
#Only the 's' after / (which means second) should be translated. #Only the 's' after / (which means second) should be translated.
text += _('(%(filesize_unit)s/s)') % {'filesize_unit': text += _('(%(filesize_unit)s/s)') % {'filesize_unit':
@ -556,9 +556,9 @@ _('Connection with peer cannot be established.'))
def get_send_file_props(self, account, contact, file_path, file_name, def get_send_file_props(self, account, contact, file_path, file_name,
file_desc=''): file_desc=''):
''' create new file_props dict and set initial file transfer ''' create new file_props dict and set initial file transfer
properties in it''' properties in it'''
file_props = {'file-name' : file_path, 'name' : file_name, file_props = {'file-name' : file_path, 'name' : file_name,
'type' : 's', 'desc' : file_desc} 'type' : 's', 'desc' : file_desc}
if os.path.isfile(file_path): if os.path.isfile(file_path):
stat = os.stat(file_path) stat = os.stat(file_path)
@ -566,7 +566,7 @@ _('Connection with peer cannot be established.'))
dialogs.ErrorDialog(_('Invalid File'), _('File: ') + file_path) dialogs.ErrorDialog(_('Invalid File'), _('File: ') + file_path)
return None return None
if stat[6] == 0: if stat[6] == 0:
dialogs.ErrorDialog(_('Invalid File'), dialogs.ErrorDialog(_('Invalid File'),
_('It is not possible to send empty files')) _('It is not possible to send empty files'))
return None return None
file_props['elapsed-time'] = 0 file_props['elapsed-time'] = 0
@ -589,11 +589,11 @@ _('Connection with peer cannot be established.'))
file_props['elapsed-time'] = 0 file_props['elapsed-time'] = 0
self.files_props[file_props['type']][file_props['sid']] = file_props self.files_props[file_props['type']][file_props['sid']] = file_props
iter_ = self.model.append() iter_ = self.model.append()
text_labels = '<b>' + _('Name: ') + '</b>\n' text_labels = '<b>' + _('Name: ') + '</b>\n'
if file_props['type'] == 'r': if file_props['type'] == 'r':
text_labels += '<b>' + _('Sender: ') + '</b>' text_labels += '<b>' + _('Sender: ') + '</b>'
else: else:
text_labels += '<b>' + _('Recipient: ') + '</b>' text_labels += '<b>' + _('Recipient: ') + '</b>'
if file_props['type'] == 'r': if file_props['type'] == 'r':
file_name = os.path.split(file_props['file-name'])[1] file_name = os.path.split(file_props['file-name'])[1]
@ -644,7 +644,7 @@ _('Connection with peer cannot be established.'))
elif self.height_diff is 0: elif self.height_diff is 0:
return return
pointer = self.tree.get_pointer() pointer = self.tree.get_pointer()
props = self.tree.get_path_at_pos(pointer[0], props = self.tree.get_path_at_pos(pointer[0],
pointer[1] - self.height_diff) pointer[1] - self.height_diff)
if self.tooltip.timeout > 0: if self.tooltip.timeout > 0:
if not props or self.tooltip.id == props[0]: if not props or self.tooltip.id == props[0]:
@ -686,7 +686,7 @@ _('Connection with peer cannot be established.'))
return True return True
def set_cleanup_sensitivity(self): def set_cleanup_sensitivity(self):
''' check if there are transfer rows and set cleanup_button ''' check if there are transfer rows and set cleanup_button
sensitive, or insensitive if model is empty''' sensitive, or insensitive if model is empty'''
if len(self.model) == 0: if len(self.model) == 0:
self.cleanup_button.set_sensitive(False) self.cleanup_button.set_sensitive(False)
@ -705,7 +705,7 @@ _('Connection with peer cannot be established.'))
self.set_cleanup_sensitivity() self.set_cleanup_sensitivity()
def set_buttons_sensitive(self, path, is_row_selected): def set_buttons_sensitive(self, path, is_row_selected):
''' make buttons/menuitems sensitive as appropriate to ''' make buttons/menuitems sensitive as appropriate to
the state of file transfer located at path 'path' ''' the state of file transfer located at path 'path' '''
if path is None: if path is None:
self.set_all_insensitive() self.set_all_insensitive()
@ -743,7 +743,7 @@ _('Connection with peer cannot be established.'))
return True return True
def selection_changed(self, args): def selection_changed(self, args):
''' selection has changed - change the sensitivity of the ''' selection has changed - change the sensitivity of the
buttons/menuitems''' buttons/menuitems'''
selection = args selection = args
selected = selection.get_selected_rows() selected = selection.get_selected_rows()
@ -801,7 +801,7 @@ _('Connection with peer cannot be established.'))
def on_pause_restore_button_clicked(self, widget): def on_pause_restore_button_clicked(self, widget):
selected = self.tree.get_selection().get_selected() selected = self.tree.get_selection().get_selected()
if selected is None or selected[1] is None: if selected is None or selected[1] is None:
return return
s_iter = selected[1] s_iter = selected[1]
sid = self.model[s_iter][C_SID].decode('utf-8') sid = self.model[s_iter][C_SID].decode('utf-8')
file_props = self.files_props[sid[0]][sid[1:]] file_props = self.files_props[sid[0]][sid[1:]]
@ -822,12 +822,12 @@ _('Connection with peer cannot be established.'))
def on_cancel_button_clicked(self, widget): def on_cancel_button_clicked(self, widget):
selected = self.tree.get_selection().get_selected() selected = self.tree.get_selection().get_selected()
if selected is None or selected[1] is None: if selected is None or selected[1] is None:
return return
s_iter = selected[1] s_iter = selected[1]
sid = self.model[s_iter][C_SID].decode('utf-8') sid = self.model[s_iter][C_SID].decode('utf-8')
file_props = self.files_props[sid[0]][sid[1:]] file_props = self.files_props[sid[0]][sid[1:]]
if 'tt_account' not in file_props: if 'tt_account' not in file_props:
return return
account = file_props['tt_account'] account = file_props['tt_account']
if account not in gajim.connections: if account not in gajim.connections:
return return
@ -839,7 +839,7 @@ _('Connection with peer cannot be established.'))
self.tooltip.hide_tooltip() self.tooltip.hide_tooltip()
return return
pointer = self.tree.get_pointer() pointer = self.tree.get_pointer()
props = self.tree.get_path_at_pos(pointer[0], props = self.tree.get_path_at_pos(pointer[0],
pointer[1] - self.height_diff) pointer[1] - self.height_diff)
# check if the current pointer is at the same path # check if the current pointer is at the same path
# as it was before setting the timeout # as it was before setting the timeout
@ -851,13 +851,13 @@ _('Connection with peer cannot be established.'))
rect = self.tree.get_cell_area(props[0],props[1]) rect = self.tree.get_cell_area(props[0],props[1])
# position of the treeview on the screen # position of the treeview on the screen
position = widget.window.get_origin() position = widget.window.get_origin()
self.tooltip.show_tooltip(file_props , rect.height, self.tooltip.show_tooltip(file_props , rect.height,
position[1] + rect.y + self.height_diff) position[1] + rect.y + self.height_diff)
else: else:
self.tooltip.hide_tooltip() self.tooltip.hide_tooltip()
def on_notify_ft_complete_checkbox_toggled(self, widget): def on_notify_ft_complete_checkbox_toggled(self, widget):
gajim.config.set('notify_on_file_complete', gajim.config.set('notify_on_file_complete',
widget.get_active()) widget.get_active())
def on_file_transfers_dialog_delete_event(self, widget, event): def on_file_transfers_dialog_delete_event(self, widget, event):
@ -877,7 +877,7 @@ _('Connection with peer cannot be established.'))
event_button = gtkgui_helpers.get_possible_button_event(event) event_button = gtkgui_helpers.get_possible_button_event(event)
self.file_transfers_menu.show_all() self.file_transfers_menu.show_all()
self.file_transfers_menu.popup(None, self.tree, None, self.file_transfers_menu.popup(None, self.tree, None,
event_button, event.time) event_button, event.time)
def on_transfers_list_key_press_event(self, widget, event): def on_transfers_list_key_press_event(self, widget, event):
@ -930,7 +930,7 @@ _('Connection with peer cannot be established.'))
def on_open_folder_menuitem_activate(self, widget): def on_open_folder_menuitem_activate(self, widget):
selected = self.tree.get_selection().get_selected() selected = self.tree.get_selection().get_selected()
if selected is None or selected[1] is None: if selected is None or selected[1] is None:
return return
s_iter = selected[1] s_iter = selected[1]
sid = self.model[s_iter][C_SID].decode('utf-8') sid = self.model[s_iter][C_SID].decode('utf-8')
file_props = self.files_props[sid[0]][sid[1:]] file_props = self.files_props[sid[0]][sid[1:]]
@ -952,7 +952,7 @@ _('Connection with peer cannot be established.'))
def on_remove_menuitem_activate(self, widget): def on_remove_menuitem_activate(self, widget):
selected = self.tree.get_selection().get_selected() selected = self.tree.get_selection().get_selected()
if selected is None or selected[1] is None: if selected is None or selected[1] is None:
return return
s_iter = selected[1] s_iter = selected[1]
sid = self.model[s_iter][C_SID].decode('utf-8') sid = self.model[s_iter][C_SID].decode('utf-8')
file_props = self.files_props[sid[0]][sid[1:]] file_props = self.files_props[sid[0]][sid[1:]]

View file

@ -525,9 +525,9 @@ class PassphraseRequest:
class Interface: class Interface:
################################################################################ ################################################################################
### Methods handling events from connection ### Methods handling events from connection
################################################################################ ################################################################################
def handle_event_roster(self, account, data): def handle_event_roster(self, account, data):
#('ROSTER', account, array) #('ROSTER', account, array)
@ -805,7 +805,7 @@ class Interface:
if ji in jid_list: if ji in jid_list:
# Update existing iter and group counting # Update existing iter and group counting
self.roster.draw_contact(ji, account) self.roster.draw_contact(ji, account)
self.roster.draw_group(_('Transports'), account) self.roster.draw_group(_('Transports'), account)
if new_show > 1 and ji in gajim.transport_avatar[account]: if new_show > 1 and ji in gajim.transport_avatar[account]:
# transport just signed in. # transport just signed in.
# request avatars # request avatars
@ -1508,7 +1508,7 @@ class Interface:
re_draw = False re_draw = False
# If contact has changed (sub, ask or group) update roster # If contact has changed (sub, ask or group) update roster
# Mind about observer status changes: # Mind about observer status changes:
# According to xep 0162, a contact is not an observer anymore when # According to xep 0162, a contact is not an observer anymore when
# we asked for auth, so also remove him if ask changed # we asked for auth, so also remove him if ask changed
old_groups = contacts[0].groups old_groups = contacts[0].groups
if contacts[0].sub != sub or contacts[0].ask != ask\ if contacts[0].sub != sub or contacts[0].ask != ask\
@ -1587,8 +1587,8 @@ class Interface:
senders = ',\n '.join(reversed(gmessage['From'])) senders = ',\n '.join(reversed(gmessage['From']))
text += _('\n\nFrom: %(from_address)s\nSubject: %(subject)s\n%(snippet)s') % \ text += _('\n\nFrom: %(from_address)s\nSubject: %(subject)s\n%(snippet)s') % \
{'from_address': senders, 'subject': gmessage['Subject'], {'from_address': senders, 'subject': gmessage['Subject'],
'snippet': gmessage['Snippet']} 'snippet': gmessage['Snippet']}
cnt += 1 cnt += 1
if gajim.config.get_per('soundevents', 'gmail_received', 'enabled'): if gajim.config.get_per('soundevents', 'gmail_received', 'enabled'):
helpers.play_sound('gmail_received') helpers.play_sound('gmail_received')
@ -1920,7 +1920,7 @@ class Interface:
# If contact is a groupchat user # If contact is a groupchat user
jids = [contact.jid] jids = [contact.jid]
else: else:
jids = [contact.jid, contact.get_full_jid()] jids = [contact.jid, contact.get_full_jid()]
for jid in jids: for jid in jids:
ctrl = self.msg_win_mgr.get_control(jid, account) ctrl = self.msg_win_mgr.get_control(jid, account)
if ctrl: if ctrl:
@ -2206,7 +2206,7 @@ class Interface:
} }
gajim.handlers = self.handlers gajim.handlers = self.handlers
################################################################################ ################################################################################
### Methods dealing with gajim.events ### Methods dealing with gajim.events
################################################################################ ################################################################################
@ -2366,7 +2366,7 @@ class Interface:
tv = ctrl.conv_textview tv = ctrl.conv_textview
tv.scroll_to_end() tv.scroll_to_end()
################################################################################ ################################################################################
### Methods dealing with emoticons ### Methods dealing with emoticons
################################################################################ ################################################################################
@ -2390,7 +2390,7 @@ class Interface:
except AttributeError: except AttributeError:
self._basic_pattern_re = re.compile(self.basic_pattern, re.IGNORECASE) self._basic_pattern_re = re.compile(self.basic_pattern, re.IGNORECASE)
return self._basic_pattern_re return self._basic_pattern_re
@property @property
def emot_and_basic_re(self): def emot_and_basic_re(self):
try: try:
@ -2415,7 +2415,7 @@ class Interface:
except AttributeError: except AttributeError:
self._invalid_XML_chars_re = re.compile(self.invalid_XML_chars) self._invalid_XML_chars_re = re.compile(self.invalid_XML_chars)
return self._invalid_XML_chars_re return self._invalid_XML_chars_re
def make_regexps(self): def make_regexps(self):
# regexp meta characters are: . ^ $ * + ? { } [ ] \ | ( ) # regexp meta characters are: . ^ $ * + ? { } [ ] \ | ( )
# one escapes the metachars with \ # one escapes the metachars with \
@ -2462,7 +2462,7 @@ class Interface:
latex = r'|\$\$[^$\\]*?([\]\[0-9A-Za-z()|+*/-]|[\\][\]\[0-9A-Za-z()|{}$])(.*?[^\\])?\$\$' latex = r'|\$\$[^$\\]*?([\]\[0-9A-Za-z()|+*/-]|[\\][\]\[0-9A-Za-z()|{}$])(.*?[^\\])?\$\$'
basic_pattern = links + '|' + mail + '|' + legacy_prefixes basic_pattern = links + '|' + mail + '|' + legacy_prefixes
link_pattern = basic_pattern link_pattern = basic_pattern
self.link_pattern_re = re.compile(link_pattern, re.IGNORECASE) self.link_pattern_re = re.compile(link_pattern, re.IGNORECASE)
@ -2657,7 +2657,7 @@ class Interface:
# We are already in that groupchat # We are already in that groupchat
gc_control = self.msg_win_mgr.get_gc_control(room_jid, account) gc_control = self.msg_win_mgr.get_gc_control(room_jid, account)
gc_control.nick = nick gc_control.nick = nick
gc_control.parent_win.set_active_tab(gc_control) gc_control.parent_win.set_active_tab(gc_control)
else: else:
# We are already in this groupchat and it is minimized # We are already in this groupchat and it is minimized
minimized_control.nick = nick minimized_control.nick = nick
@ -2800,9 +2800,9 @@ class Interface:
if ctrl: if ctrl:
ctrl.got_disconnected() ctrl.got_disconnected()
################################################################################ ################################################################################
### Other Methods ### Other Methods
################################################################################ ################################################################################
def read_sleepy(self): def read_sleepy(self):
'''Check idle status and change that status if needed''' '''Check idle status and change that status if needed'''
@ -2852,7 +2852,7 @@ class Interface:
auto_message = auto_message.replace('$S','%(status)s') auto_message = auto_message.replace('$S','%(status)s')
auto_message = auto_message.replace('$T','%(time)s') auto_message = auto_message.replace('$T','%(time)s')
auto_message = auto_message % { auto_message = auto_message % {
'status': gajim.status_before_autoaway[account], 'status': gajim.status_before_autoaway[account],
'time': gajim.config.get('autoxatime') 'time': gajim.config.get('autoxatime')
} }
self.roster.send_status(account, 'xa', auto_message, auto=True) self.roster.send_status(account, 'xa', auto_message, auto=True)
@ -2993,7 +2993,7 @@ class Interface:
bm['password'], minimize = minimize) bm['password'], minimize = minimize)
elif jid in self.minimized_controls[account]: elif jid in self.minimized_controls[account]:
# more or less a hack: # more or less a hack:
# On disconnect the minimized gc contact instances # On disconnect the minimized gc contact instances
# were set to offline. Reconnect them to show up in the roster. # were set to offline. Reconnect them to show up in the roster.
self.roster.add_groupchat(jid, account) self.roster.add_groupchat(jid, account)

View file

@ -35,7 +35,7 @@ class GajimThemesWindow:
self.xml = gtkgui_helpers.get_glade('gajim_themes_window.glade') self.xml = gtkgui_helpers.get_glade('gajim_themes_window.glade')
self.window = self.xml.get_widget('gajim_themes_window') self.window = self.xml.get_widget('gajim_themes_window')
self.window.set_transient_for(gajim.interface.roster.window) self.window.set_transient_for(gajim.interface.roster.window)
self.options = ['account', 'group', 'contact', 'banner'] self.options = ['account', 'group', 'contact', 'banner']
self.options_combobox = self.xml.get_widget('options_combobox') self.options_combobox = self.xml.get_widget('options_combobox')
self.textcolor_checkbutton = self.xml.get_widget('textcolor_checkbutton') self.textcolor_checkbutton = self.xml.get_widget('textcolor_checkbutton')
@ -69,17 +69,17 @@ class GajimThemesWindow:
self.select_active_theme() self.select_active_theme()
self.current_option = self.options[0] self.current_option = self.options[0]
self.set_theme_options(self.current_theme, self.current_option) self.set_theme_options(self.current_theme, self.current_option)
self.xml.signal_autoconnect(self) self.xml.signal_autoconnect(self)
self.window.connect('delete-event', self.on_themese_window_delete_event) self.window.connect('delete-event', self.on_themese_window_delete_event)
self.themes_tree.get_selection().connect('changed', self.themes_tree.get_selection().connect('changed',
self.selection_changed) self.selection_changed)
self.window.show_all() self.window.show_all()
def on_themese_window_delete_event(self, widget, event): def on_themese_window_delete_event(self, widget, event):
self.window.hide() self.window.hide()
return True # do NOT destroy the window return True # do NOT destroy the window
def on_close_button_clicked(self, widget): def on_close_button_clicked(self, widget):
if 'preferences' in gajim.interface.instances: if 'preferences' in gajim.interface.instances:
gajim.interface.instances['preferences'].update_theme_list() gajim.interface.instances['preferences'].update_theme_list()
@ -138,7 +138,7 @@ class GajimThemesWindow:
self.xml.get_widget('remove_button').set_sensitive(False) self.xml.get_widget('remove_button').set_sensitive(False)
self.theme_options_vbox.set_sensitive(False) self.theme_options_vbox.set_sensitive(False)
self.theme_options_table.set_sensitive(False) self.theme_options_table.set_sensitive(False)
else: else:
self.xml.get_widget('remove_button').set_sensitive(True) self.xml.get_widget('remove_button').set_sensitive(True)
self.theme_options_vbox.set_sensitive(True) self.theme_options_vbox.set_sensitive(True)
self.theme_options_table.set_sensitive(True) self.theme_options_table.set_sensitive(True)
@ -159,7 +159,7 @@ class GajimThemesWindow:
self.xml.get_widget('remove_button').set_sensitive(False) self.xml.get_widget('remove_button').set_sensitive(False)
self.theme_options_vbox.set_sensitive(False) self.theme_options_vbox.set_sensitive(False)
self.theme_options_table.set_sensitive(False) self.theme_options_table.set_sensitive(False)
else: else:
self.xml.get_widget('remove_button').set_sensitive(True) self.xml.get_widget('remove_button').set_sensitive(True)
self.theme_options_vbox.set_sensitive(True) self.theme_options_vbox.set_sensitive(True)
self.theme_options_table.set_sensitive(True) self.theme_options_table.set_sensitive(True)
@ -194,7 +194,7 @@ class GajimThemesWindow:
self.xml.get_widget('remove_button').set_sensitive(False) self.xml.get_widget('remove_button').set_sensitive(False)
gajim.config.del_per('themes', self.current_theme) gajim.config.del_per('themes', self.current_theme)
model.remove(iter_) model.remove(iter_)
def set_theme_options(self, theme, option = 'account'): def set_theme_options(self, theme, option = 'account'):
self.no_update = True self.no_update = True
self.options_combobox.set_active(self.options.index(option)) self.options_combobox.set_active(self.options.index(option))
@ -215,7 +215,7 @@ class GajimThemesWindow:
state = False state = False
self.background_checkbutton.set_active(state) self.background_checkbutton.set_active(state)
self.background_colorbutton.set_sensitive(state) self.background_colorbutton.set_sensitive(state)
# get the font name before we set widgets and it will not be overriden # get the font name before we set widgets and it will not be overriden
font_name = gajim.config.get_per('themes', theme, option + 'font') font_name = gajim.config.get_per('themes', theme, option + 'font')
font_attrs = gajim.config.get_per('themes', theme, option + 'fontattrs') font_attrs = gajim.config.get_per('themes', theme, option + 'fontattrs')
@ -235,32 +235,32 @@ class GajimThemesWindow:
color = gajim.config.get_per('themes', theme, 'state_' + chatstate + \ color = gajim.config.get_per('themes', theme, 'state_' + chatstate + \
'_color') '_color')
self.colorbuttons[chatstate].set_color(gtk.gdk.color_parse(color)) self.colorbuttons[chatstate].set_color(gtk.gdk.color_parse(color))
def on_textcolor_checkbutton_toggled(self, widget): def on_textcolor_checkbutton_toggled(self, widget):
state = widget.get_active() state = widget.get_active()
self.text_colorbutton.set_sensitive(state) self.text_colorbutton.set_sensitive(state)
self._set_color(state, self.text_colorbutton, self._set_color(state, self.text_colorbutton,
'textcolor') 'textcolor')
def on_background_checkbutton_toggled(self, widget): def on_background_checkbutton_toggled(self, widget):
state = widget.get_active() state = widget.get_active()
self.background_colorbutton.set_sensitive(state) self.background_colorbutton.set_sensitive(state)
self._set_color(state, self.background_colorbutton, self._set_color(state, self.background_colorbutton,
'bgcolor') 'bgcolor')
def on_textfont_checkbutton_toggled(self, widget): def on_textfont_checkbutton_toggled(self, widget):
self.text_fontbutton.set_sensitive(widget.get_active()) self.text_fontbutton.set_sensitive(widget.get_active())
self._set_font() self._set_font()
def on_text_colorbutton_color_set(self, widget): def on_text_colorbutton_color_set(self, widget):
self._set_color(True, widget, 'textcolor') self._set_color(True, widget, 'textcolor')
def on_background_colorbutton_color_set(self, widget): def on_background_colorbutton_color_set(self, widget):
self._set_color(True, widget, 'bgcolor') self._set_color(True, widget, 'bgcolor')
def on_text_fontbutton_font_set(self, widget): def on_text_fontbutton_font_set(self, widget):
self._set_font() self._set_font()
def on_options_combobox_changed(self, widget): def on_options_combobox_changed(self, widget):
index = self.options_combobox.get_active() index = self.options_combobox.get_active()
if index == -1: if index == -1:
@ -268,15 +268,15 @@ class GajimThemesWindow:
self.current_option = self.options[index] self.current_option = self.options[index]
self.set_theme_options(self.current_theme, self.set_theme_options(self.current_theme,
self.current_option) self.current_option)
def on_bold_togglebutton_toggled(self, widget): def on_bold_togglebutton_toggled(self, widget):
if not self.no_update: if not self.no_update:
self._set_font() self._set_font()
def on_italic_togglebutton_toggled(self, widget): def on_italic_togglebutton_toggled(self, widget):
if not self.no_update: if not self.no_update:
self._set_font() self._set_font()
def _set_color(self, state, widget, option): def _set_color(self, state, widget, option):
''' set color value in prefs and update the UI ''' ''' set color value in prefs and update the UI '''
if state: if state:
@ -287,7 +287,7 @@ class GajimThemesWindow:
begin_option = '' begin_option = ''
if not option.startswith('state'): if not option.startswith('state'):
begin_option = self.current_option begin_option = self.current_option
gajim.config.set_per('themes', self.current_theme, gajim.config.set_per('themes', self.current_theme,
begin_option + option, color_string) begin_option + option, color_string)
# use faster functions for this # use faster functions for this
if self.current_option == 'banner': if self.current_option == 'banner':
@ -298,7 +298,7 @@ class GajimThemesWindow:
return return
gajim.interface.roster.change_roster_style(self.current_option) gajim.interface.roster.change_roster_style(self.current_option)
gajim.interface.save_config() gajim.interface.save_config()
def _set_font(self): def _set_font(self):
''' set font value in prefs and update the UI ''' ''' set font value in prefs and update the UI '''
state = self.textfont_checkbutton.get_active() state = self.textfont_checkbutton.get_active()
@ -306,10 +306,10 @@ class GajimThemesWindow:
font_string = self.text_fontbutton.get_font_name() font_string = self.text_fontbutton.get_font_name()
else: else:
font_string = '' font_string = ''
gajim.config.set_per('themes', self.current_theme, gajim.config.set_per('themes', self.current_theme,
self.current_option + 'font', font_string) self.current_option + 'font', font_string)
font_attrs = self._get_font_attrs() font_attrs = self._get_font_attrs()
gajim.config.set_per('themes', self.current_theme, gajim.config.set_per('themes', self.current_theme,
self.current_option + 'fontattrs', font_attrs) self.current_option + 'fontattrs', font_attrs)
# use faster functions for this # use faster functions for this
if self.current_option == 'banner': if self.current_option == 'banner':
@ -318,14 +318,14 @@ class GajimThemesWindow:
return return
gajim.interface.roster.change_roster_style(self.current_option) gajim.interface.roster.change_roster_style(self.current_option)
gajim.interface.save_config() gajim.interface.save_config()
def _toggle_font_widgets(self, font_props): def _toggle_font_widgets(self, font_props):
''' toggle font buttons with the bool values of font_props tuple''' ''' toggle font buttons with the bool values of font_props tuple'''
self.bold_togglebutton.set_active(font_props[0]) self.bold_togglebutton.set_active(font_props[0])
self.italic_togglebutton.set_active(font_props[1]) self.italic_togglebutton.set_active(font_props[1])
def _get_font_description(self): def _get_font_description(self):
''' return a FontDescription from togglebuttons ''' return a FontDescription from togglebuttons
states''' states'''
fd = pango.FontDescription() fd = pango.FontDescription()
if self.bold_togglebutton.get_active(): if self.bold_togglebutton.get_active():
@ -333,7 +333,7 @@ class GajimThemesWindow:
if self.italic_togglebutton.get_active(): if self.italic_togglebutton.get_active():
fd.set_style(pango.STYLE_ITALIC) fd.set_style(pango.STYLE_ITALIC)
return fd return fd
def _set_font_widgets(self, font_attrs): def _set_font_widgets(self, font_attrs):
''' set the correct toggle state of font style buttons by ''' set the correct toggle state of font style buttons by
a font string of type 'BI' ''' a font string of type 'BI' '''
@ -344,7 +344,7 @@ class GajimThemesWindow:
if font_attrs.find('I') != -1: if font_attrs.find('I') != -1:
font_props[1] = True font_props[1] = True
self._toggle_font_widgets(font_props) self._toggle_font_widgets(font_props)
def _get_font_attrs(self): def _get_font_attrs(self):
''' get a string with letters of font attribures: 'BI' ''' ''' get a string with letters of font attribures: 'BI' '''
attrs = '' attrs = ''
@ -353,7 +353,7 @@ class GajimThemesWindow:
if self.italic_togglebutton.get_active(): if self.italic_togglebutton.get_active():
attrs += 'I' attrs += 'I'
return attrs return attrs
def _get_font_props(self, font_name): def _get_font_props(self, font_name):
''' get tuple of font properties: Weight, Style ''' ''' get tuple of font properties: Weight, Style '''

View file

@ -208,27 +208,26 @@ class GroupchatControl(ChatControlBase):
id_ = widget.connect('row_expanded', self.on_list_treeview_row_expanded) id_ = widget.connect('row_expanded', self.on_list_treeview_row_expanded)
self.handlers[id_] = widget self.handlers[id_] = widget
id_ = widget.connect('row_collapsed', id_ = widget.connect('row_collapsed', self.on_list_treeview_row_collapsed)
self.on_list_treeview_row_collapsed)
self.handlers[id_] = widget self.handlers[id_] = widget
id_ = widget.connect('row_activated', id_ = widget.connect('row_activated',
self.on_list_treeview_row_activated) self.on_list_treeview_row_activated)
self.handlers[id_] = widget self.handlers[id_] = widget
id_ = widget.connect('button_press_event', id_ = widget.connect('button_press_event',
self.on_list_treeview_button_press_event) self.on_list_treeview_button_press_event)
self.handlers[id_] = widget self.handlers[id_] = widget
id_ = widget.connect('key_press_event', id_ = widget.connect('key_press_event',
self.on_list_treeview_key_press_event) self.on_list_treeview_key_press_event)
self.handlers[id_] = widget self.handlers[id_] = widget
id_ = widget.connect('motion_notify_event', id_ = widget.connect('motion_notify_event',
self.on_list_treeview_motion_notify_event) self.on_list_treeview_motion_notify_event)
self.handlers[id_] = widget self.handlers[id_] = widget
id_ = widget.connect('leave_notify_event', id_ = widget.connect('leave_notify_event',
self.on_list_treeview_leave_notify_event) self.on_list_treeview_leave_notify_event)
self.handlers[id_] = widget self.handlers[id_] = widget
@ -270,7 +269,7 @@ class GroupchatControl(ChatControlBase):
# nickname coloring # nickname coloring
self.gc_count_nicknames_colors = 0 self.gc_count_nicknames_colors = 0
self.gc_custom_colors = {} self.gc_custom_colors = {}
self.number_of_colors = len(gajim.config.get('gc_nicknames_colors').\ self.number_of_colors = len(gajim.config.get('gc_nicknames_colors').\
split(':')) split(':'))
@ -327,7 +326,7 @@ class GroupchatControl(ChatControlBase):
self.list_treeview = self.xml.get_widget('list_treeview') self.list_treeview = self.xml.get_widget('list_treeview')
selection = self.list_treeview.get_selection() selection = self.list_treeview.get_selection()
id_ = selection.connect('changed', id_ = selection.connect('changed',
self.on_list_treeview_selection_changed) self.on_list_treeview_selection_changed)
self.handlers[id_] = selection self.handlers[id_] = selection
id_ = self.list_treeview.connect('style-set', id_ = self.list_treeview.connect('style-set',
@ -365,7 +364,7 @@ class GroupchatControl(ChatControlBase):
renderer_image.set_property('width', 26) renderer_image.set_property('width', 26)
column.pack_start(renderer_image, expand = False) column.pack_start(renderer_image, expand = False)
column.add_attribute(renderer_image, 'image', C_IMG) column.add_attribute(renderer_image, 'image', C_IMG)
column.set_cell_data_func(renderer_image, tree_cell_data_func, column.set_cell_data_func(renderer_image, tree_cell_data_func,
self.list_treeview) self.list_treeview)
renderer_text = gtk.CellRendererText() # nickname renderer_text = gtk.CellRendererText() # nickname
@ -606,8 +605,8 @@ class GroupchatControl(ChatControlBase):
return title return title
def draw_banner_text(self): def draw_banner_text(self):
'''Draw the text in the fat line at the top of the window that '''Draw the text in the fat line at the top of the window that
houses the room jid, subject. houses the room jid, subject.
''' '''
self.name_label.set_ellipsize(pango.ELLIPSIZE_END) self.name_label.set_ellipsize(pango.ELLIPSIZE_END)
self.banner_status_label.set_ellipsize(pango.ELLIPSIZE_END) self.banner_status_label.set_ellipsize(pango.ELLIPSIZE_END)
@ -827,7 +826,7 @@ class GroupchatControl(ChatControlBase):
else: else:
self.gc_count_nicknames_colors += 1 self.gc_count_nicknames_colors += 1
if self.gc_count_nicknames_colors == self.number_of_colors: if self.gc_count_nicknames_colors == self.number_of_colors:
self.gc_count_nicknames_colors = 0 self.gc_count_nicknames_colors = 0
self.gc_custom_colors[contact] = \ self.gc_custom_colors[contact] = \
self.gc_count_nicknames_colors self.gc_count_nicknames_colors
other_tags_for_name.append('gc_nickname_color_' + \ other_tags_for_name.append('gc_nickname_color_' + \
@ -846,7 +845,7 @@ class GroupchatControl(ChatControlBase):
elif len(self.attention_list) > 6: elif len(self.attention_list) > 6:
self.attention_list.pop(0) # remove older self.attention_list.pop(0) # remove older
self.attention_list.append(contact) self.attention_list.append(contact)
if sound == 'received': if sound == 'received':
helpers.play_sound('muc_message_received') helpers.play_sound('muc_message_received')
elif sound == 'highlight': elif sound == 'highlight':
@ -940,17 +939,17 @@ class GroupchatControl(ChatControlBase):
# This is A->Z, a->z or 0-9, we can be sure our nick is the # This is A->Z, a->z or 0-9, we can be sure our nick is the
# beginning of a real word, do not highlight for this one. # beginning of a real word, do not highlight for this one.
break break
else: else:
return True return True
else: # Special word == word, no char after in word else: # Special word == word, no char after in word
return True return True
for special_word in special_words: for special_word in special_words:
if special_word.find(' ') > -1: if special_word.find(' ') > -1:
# There is a space in this special word, do a global search # There is a space in this special word, do a global search
# without splitting by words as previously # without splitting by words as previously
# We don't search this in all cases so we don't loose time # We don't search this in all cases so we don't loose time
if text.find(special_word) > -1: if text.find(special_word) > -1:
return True return True
return False return False
def set_subject(self, subject): def set_subject(self, subject):
@ -1162,9 +1161,9 @@ class GroupchatControl(ChatControlBase):
else: else:
s = _('%(nick)s is now known as %(new_nick)s') % { s = _('%(nick)s is now known as %(new_nick)s') % {
'nick': nick, 'new_nick': new_nick} 'nick': nick, 'new_nick': new_nick}
# We add new nick to muc roster here, so we don't see # We add new nick to muc roster here, so we don't see
# that "new_nick has joined the room" when he just changed nick. # that "new_nick has joined the room" when he just changed nick.
# add_contact_to_roster will be called a second time # add_contact_to_roster will be called a second time
# after that, but that doesn't hurt # after that, but that doesn't hurt
self.add_contact_to_roster(new_nick, show, role, affiliation, self.add_contact_to_roster(new_nick, show, role, affiliation,
status, jid) status, jid)
@ -1361,7 +1360,7 @@ class GroupchatControl(ChatControlBase):
role_iter = self.get_role_iter(role) role_iter = self.get_role_iter(role)
if not role_iter: if not role_iter:
role_iter = model.append(None, role_iter = model.append(None,
(gajim.interface.jabber_state_images['16']['closed'], role, (gajim.interface.jabber_state_images['16']['closed'], role,
'role', role_name, None)) 'role', role_name, None))
self.draw_all_roles() self.draw_all_roles()
iter_ = model.append(role_iter, (None, nick, 'contact', name, None)) iter_ = model.append(role_iter, (None, nick, 'contact', name, None))
@ -1771,7 +1770,7 @@ class GroupchatControl(ChatControlBase):
# destroy banner tooltip - bug #pygtk for that! # destroy banner tooltip - bug #pygtk for that!
self.subject_tooltip.destroy() self.subject_tooltip.destroy()
if gajim.gc_connected[self.account][self.room_jid]: if gajim.gc_connected[self.account][self.room_jid]:
# Tell connection to note the date we disconnect to avoid duplicate # Tell connection to note the date we disconnect to avoid duplicate
# logs. We do it only when connected because if connection was lost # logs. We do it only when connected because if connection was lost
# there may be new messages since disconnection. # there may be new messages since disconnection.
gajim.connections[self.account].gc_got_disconnected(self.room_jid) gajim.connections[self.account].gc_got_disconnected(self.room_jid)
@ -1915,8 +1914,8 @@ class GroupchatControl(ChatControlBase):
gajim.interface.add_gc_bookmark(self.account, self.name, self.room_jid, \ gajim.interface.add_gc_bookmark(self.account, self.name, self.room_jid, \
'0', '0', password, self.nick) '0', '0', password, self.nick)
def _on_drag_data_received(self, widget, context, x, y, selection, def _on_drag_data_received(self, widget, context, x, y, selection,
target_type, timestamp): target_type, timestamp):
# Invite contact to groupchat # Invite contact to groupchat
treeview = gajim.interface.roster.tree treeview = gajim.interface.roster.tree
model = treeview.get_model() model = treeview.get_model()
@ -2014,7 +2013,7 @@ class GroupchatControl(ChatControlBase):
list_nick = gajim.contacts.get_nick_list(self.account, list_nick = gajim.contacts.get_nick_list(self.account,
self.room_jid) self.room_jid)
list_nick.sort(key=unicode.lower) # case-insensitive sort list_nick.sort(key=unicode.lower) # case-insensitive sort
if begin == '': if begin == '':
# empty message, show lasts nicks that highlighted us first # empty message, show lasts nicks that highlighted us first
for nick in self.attention_list: for nick in self.attention_list:
if nick in list_nick: if nick in list_nick:
@ -2027,7 +2026,7 @@ class GroupchatControl(ChatControlBase):
# the word is the begining of a nick # the word is the begining of a nick
self.nick_hits.append(nick) self.nick_hits.append(nick)
if len(self.nick_hits): if len(self.nick_hits):
if len(splitted_text) < 2 or with_refer_to_nick_char: if len(splitted_text) < 2 or with_refer_to_nick_char:
# This is the 1st word of the line or no word or we are cycling # This is the 1st word of the line or no word or we are cycling
# at the beginning, possibly with a space in one nick # at the beginning, possibly with a space in one nick
add = gc_refer_to_nick_char + ' ' add = gc_refer_to_nick_char + ' '
@ -2117,7 +2116,7 @@ class GroupchatControl(ChatControlBase):
(user_affiliation=='member' and target_affiliation!='none') or \ (user_affiliation=='member' and target_affiliation!='none') or \
target_affiliation in ('admin', 'owner'): target_affiliation in ('admin', 'owner'):
item.set_sensitive(False) item.set_sensitive(False)
id_ = item.connect('activate', self.on_voice_checkmenuitem_activate, id_ = item.connect('activate', self.on_voice_checkmenuitem_activate,
nick) nick)
self.handlers[id_] = item self.handlers[id_] = item
@ -2129,7 +2128,7 @@ class GroupchatControl(ChatControlBase):
id_ = item.connect('activate', self.on_moderator_checkmenuitem_activate, id_ = item.connect('activate', self.on_moderator_checkmenuitem_activate,
nick) nick)
self.handlers[id_] = item self.handlers[id_] = item
item = xml.get_widget('ban_menuitem') item = xml.get_widget('ban_menuitem')
if not user_affiliation in ('admin', 'owner') or \ if not user_affiliation in ('admin', 'owner') or \
(target_affiliation in ('admin', 'owner') and\ (target_affiliation in ('admin', 'owner') and\
@ -2143,10 +2142,9 @@ class GroupchatControl(ChatControlBase):
if not user_affiliation in ('admin', 'owner') or \ if not user_affiliation in ('admin', 'owner') or \
(user_affiliation != 'owner' and target_affiliation in ('admin','owner')): (user_affiliation != 'owner' and target_affiliation in ('admin','owner')):
item.set_sensitive(False) item.set_sensitive(False)
id_ = item.connect('activate', self.on_member_checkmenuitem_activate, id_ = item.connect('activate', self.on_member_checkmenuitem_activate, jid)
jid)
self.handlers[id_] = item self.handlers[id_] = item
item = xml.get_widget('admin_checkmenuitem') item = xml.get_widget('admin_checkmenuitem')
item.set_active(target_affiliation in ('admin', 'owner')) item.set_active(target_affiliation in ('admin', 'owner'))
if not user_affiliation == 'owner': if not user_affiliation == 'owner':
@ -2336,7 +2334,7 @@ class GroupchatControl(ChatControlBase):
if props and self.tooltip.id == props[0]: if props and self.tooltip.id == props[0]:
rect = self.list_treeview.get_cell_area(props[0],props[1]) rect = self.list_treeview.get_cell_area(props[0],props[1])
position = self.list_treeview.window.get_origin() position = self.list_treeview.window.get_origin()
self.tooltip.show_tooltip(contact, rect.height, self.tooltip.show_tooltip(contact, rect.height,
position[1] + rect.y) position[1] + rect.y)
else: else:
self.tooltip.hide_tooltip() self.tooltip.hide_tooltip()

View file

@ -42,11 +42,11 @@ def _info(type_, value, tb):
_excepthook_save(type_, value, tb) _excepthook_save(type_, value, tb)
return return
dialog = dialogs.HigDialog(None, gtk.MESSAGE_WARNING, gtk.BUTTONS_NONE, dialog = dialogs.HigDialog(None, gtk.MESSAGE_WARNING, gtk.BUTTONS_NONE,
_('A programming error has been detected'), _('A programming error has been detected'),
_('It probably is not fatal, but should be reported ' _('It probably is not fatal, but should be reported '
'to the developers nonetheless.')) 'to the developers nonetheless.'))
dialog.set_modal(False) dialog.set_modal(False)
#FIXME: add icon to this button #FIXME: add icon to this button
RESPONSE_REPORT_BUG = 42 RESPONSE_REPORT_BUG = 42
@ -92,7 +92,7 @@ def _info(type_, value, tb):
dialog.show_all() dialog.show_all()
_exception_in_progress.release() _exception_in_progress.release()
# gdb/kdm etc if we use startx this is not True # gdb/kdm etc if we use startx this is not True
if os.name == 'nt' or not sys.stderr.isatty(): if os.name == 'nt' or not sys.stderr.isatty():
#FIXME: maybe always show dialog? #FIXME: maybe always show dialog?

View file

@ -55,7 +55,7 @@ from common import i18n
from common import gajim from common import gajim
from common import helpers from common import helpers
gtk.glade.bindtextdomain(i18n.APP, i18n.DIR) gtk.glade.bindtextdomain(i18n.APP, i18n.DIR)
gtk.glade.textdomain(i18n.APP) gtk.glade.textdomain(i18n.APP)
screen_w = gtk.gdk.screen_width() screen_w = gtk.gdk.screen_width()
@ -71,11 +71,11 @@ def get_completion_liststore(entry):
completion list consists of (Pixbuf, Text) rows''' completion list consists of (Pixbuf, Text) rows'''
completion = gtk.EntryCompletion() completion = gtk.EntryCompletion()
liststore = gtk.ListStore(gtk.gdk.Pixbuf, str) liststore = gtk.ListStore(gtk.gdk.Pixbuf, str)
render_pixbuf = gtk.CellRendererPixbuf() render_pixbuf = gtk.CellRendererPixbuf()
completion.pack_start(render_pixbuf, expand = False) completion.pack_start(render_pixbuf, expand = False)
completion.add_attribute(render_pixbuf, 'pixbuf', 0) completion.add_attribute(render_pixbuf, 'pixbuf', 0)
render_text = gtk.CellRendererText() render_text = gtk.CellRendererText()
completion.pack_start(render_text, expand = True) completion.pack_start(render_text, expand = True)
completion.add_attribute(render_text, 'text', 1) completion.add_attribute(render_text, 'text', 1)
@ -83,15 +83,15 @@ def get_completion_liststore(entry):
completion.set_model(liststore) completion.set_model(liststore)
entry.set_completion(completion) entry.set_completion(completion)
return liststore return liststore
def popup_emoticons_under_button(menu, button, parent_win): def popup_emoticons_under_button(menu, button, parent_win):
''' pops emoticons menu under button, which is in parent_win''' ''' pops emoticons menu under button, which is in parent_win'''
window_x1, window_y1 = parent_win.get_origin() window_x1, window_y1 = parent_win.get_origin()
def position_menu_under_button(menu): def position_menu_under_button(menu):
# inline function, which will not keep refs, when used as CB # inline function, which will not keep refs, when used as CB
button_x, button_y = button.allocation.x, button.allocation.y button_x, button_y = button.allocation.x, button.allocation.y
# now convert them to X11-relative # now convert them to X11-relative
window_x, window_y = window_x1, window_y1 window_x, window_y = window_x1, window_y1
x = window_x + button_x x = window_x + button_x
@ -113,7 +113,7 @@ def popup_emoticons_under_button(menu, button, parent_win):
return (x, y, push_in) return (x, y, push_in)
menu.popup(None, None, position_menu_under_button, 1, 0) menu.popup(None, None, position_menu_under_button, 1, 0)
def get_theme_font_for_option(theme, option): def get_theme_font_for_option(theme, option):
'''return string description of the font, stored in '''return string description of the font, stored in
theme preferences''' theme preferences'''
@ -128,12 +128,12 @@ def get_theme_font_for_option(theme, option):
fd = pango.FontDescription(font_name) fd = pango.FontDescription(font_name)
fd.merge(font_desc, True) fd.merge(font_desc, True)
return fd.to_string() return fd.to_string()
def get_default_font(): def get_default_font():
'''Get the desktop setting for application font '''Get the desktop setting for application font
first check for GNOME, then Xfce and last KDE first check for GNOME, then Xfce and last KDE
it returns None on failure or else a string 'Font Size' ''' it returns None on failure or else a string 'Font Size' '''
try: try:
import gconf import gconf
# in try because daemon may not be there # in try because daemon may not be there
@ -150,11 +150,11 @@ def get_default_font():
# and http://freedesktop.org/Standards/basedir-spec # and http://freedesktop.org/Standards/basedir-spec
xdg_config_home = os.environ.get('XDG_CONFIG_HOME', '') xdg_config_home = os.environ.get('XDG_CONFIG_HOME', '')
if xdg_config_home == '': if xdg_config_home == '':
xdg_config_home = os.path.expanduser('~/.config') # default xdg_config_home = os.path.expanduser('~/.config') # default
xfce_config_file = os.path.join(xdg_config_home, 'xfce4/mcs_settings/gtk.xml') xfce_config_file = os.path.join(xdg_config_home, 'xfce4/mcs_settings/gtk.xml')
kde_config_file = os.path.expanduser('~/.kde/share/config/kdeglobals') kde_config_file = os.path.expanduser('~/.kde/share/config/kdeglobals')
if os.path.exists(xfce_config_file): if os.path.exists(xfce_config_file):
try: try:
for line in open(xfce_config_file): for line in open(xfce_config_file):
@ -164,7 +164,7 @@ def get_default_font():
except Exception: except Exception:
#we talk about file #we talk about file
print >> sys.stderr, _('Error: cannot open %s for reading') % xfce_config_file print >> sys.stderr, _('Error: cannot open %s for reading') % xfce_config_file
elif os.path.exists(kde_config_file): elif os.path.exists(kde_config_file):
try: try:
for line in open(kde_config_file): for line in open(kde_config_file):
@ -179,9 +179,9 @@ def get_default_font():
except Exception: except Exception:
#we talk about file #we talk about file
print >> sys.stderr, _('Error: cannot open %s for reading') % kde_config_file print >> sys.stderr, _('Error: cannot open %s for reading') % kde_config_file
return None return None
def autodetect_browser_mailer(): def autodetect_browser_mailer():
# recognize the environment and set appropriate browser/mailer # recognize the environment and set appropriate browser/mailer
if user_runs_gnome(): if user_runs_gnome():
@ -241,7 +241,7 @@ def get_running_processes():
# list of processes # list of processes
processes = [os.path.basename(os.readlink('/proc/' + f +'/exe')) for f in files] processes = [os.path.basename(os.readlink('/proc/' + f +'/exe')) for f in files]
return processes return processes
return [] return []
@ -376,12 +376,12 @@ def get_abspath_for_script(scriptname, want_type = False):
if scriptname == 'gajim-remote': if scriptname == 'gajim-remote':
path_to_script = cwd + '/gajim-remote.py' path_to_script = cwd + '/gajim-remote.py'
elif scriptname == 'gajim': elif scriptname == 'gajim':
script = '#!/bin/sh\n' # the script we may create script = '#!/bin/sh\n' # the script we may create
script += 'cd %s' % cwd script += 'cd %s' % cwd
path_to_script = cwd + '/../scripts/gajim_sm_script' path_to_script = cwd + '/../scripts/gajim_sm_script'
try: try:
if os.path.exists(path_to_script): if os.path.exists(path_to_script):
os.remove(path_to_script) os.remove(path_to_script)
@ -400,8 +400,8 @@ def get_abspath_for_script(scriptname, want_type = False):
type_ = 'install' type_ = 'install'
# always make it like '/usr/local/bin/gajim' # always make it like '/usr/local/bin/gajim'
path_to_script = helpers.is_in_path(scriptname, True) path_to_script = helpers.is_in_path(scriptname, True)
if want_type: if want_type:
return path_to_script, type_ return path_to_script, type_
else: else:
@ -458,7 +458,7 @@ def possibly_move_window_in_current_desktop(window):
root_window = gtk.gdk.screen_get_default().get_root_window() root_window = gtk.gdk.screen_get_default().get_root_window()
# current user's vd # current user's vd
current_virtual_desktop_no = get_current_desktop(root_window) current_virtual_desktop_no = get_current_desktop(root_window)
# vd roster window is in # vd roster window is in
window_virtual_desktop = get_current_desktop(window.window) window_virtual_desktop = get_current_desktop(window.window)
@ -476,13 +476,13 @@ def file_is_locked(path_to_file):
'''returns True if file is locked (WINDOWS ONLY)''' '''returns True if file is locked (WINDOWS ONLY)'''
if os.name != 'nt': # just in case if os.name != 'nt': # just in case
return return
if not HAS_PYWIN32: if not HAS_PYWIN32:
return return
secur_att = pywintypes.SECURITY_ATTRIBUTES() secur_att = pywintypes.SECURITY_ATTRIBUTES()
secur_att.Initialize() secur_att.Initialize()
try: try:
# try make a handle for READING the file # try make a handle for READING the file
hfile = win32file.CreateFile( hfile = win32file.CreateFile(
@ -523,7 +523,7 @@ def _get_fade_color(treeview, selected, focused):
def get_scaled_pixbuf(pixbuf, kind): def get_scaled_pixbuf(pixbuf, kind):
'''returns scaled pixbuf, keeping ratio etc or None '''returns scaled pixbuf, keeping ratio etc or None
kind is either "chat", "roster", "notification", "tooltip", "vcard"''' kind is either "chat", "roster", "notification", "tooltip", "vcard"'''
# resize to a width / height for the avatar not to have distortion # resize to a width / height for the avatar not to have distortion
# (keep aspect ratio) # (keep aspect ratio)
width = gajim.config.get(kind + '_avatar_width') width = gajim.config.get(kind + '_avatar_width')
@ -629,7 +629,7 @@ def get_path_to_generic_or_avatar(generic, jid = None, suffix = None):
for extension in ('.png', '.jpeg'): for extension in ('.png', '.jpeg'):
path_to_local_file_full = path_to_local_file + extension path_to_local_file_full = path_to_local_file + extension
if os.path.exists(path_to_local_file_full): if os.path.exists(path_to_local_file_full):
return path_to_local_file_full return path_to_local_file_full
for extension in ('.png', '.jpeg'): for extension in ('.png', '.jpeg'):
path_to_file_full = path_to_file + extension path_to_file_full = path_to_file + extension
if os.path.exists(path_to_file_full): if os.path.exists(path_to_file_full):
@ -641,7 +641,7 @@ def decode_filechooser_file_paths(file_paths):
ask sys.getfilesystemencoding() in POSIX ask sys.getfilesystemencoding() in POSIX
file_paths MUST be LIST''' file_paths MUST be LIST'''
file_paths_list = list() file_paths_list = list()
if os.name == 'nt': # decode as UTF-8 under Windows if os.name == 'nt': # decode as UTF-8 under Windows
for file_path in file_paths: for file_path in file_paths:
file_path = file_path.decode('utf8') file_path = file_path.decode('utf8')
@ -656,14 +656,14 @@ def decode_filechooser_file_paths(file_paths):
except Exception: except Exception:
pass pass
file_paths_list.append(file_path) file_paths_list.append(file_path)
return file_paths_list return file_paths_list
def possibly_set_gajim_as_xmpp_handler(): def possibly_set_gajim_as_xmpp_handler():
'''registers (by default only the first time) xmmp: to Gajim.''' '''registers (by default only the first time) xmmp: to Gajim.'''
path_to_dot_kde = os.path.expanduser('~/.kde') path_to_dot_kde = os.path.expanduser('~/.kde')
if os.path.exists(path_to_dot_kde): if os.path.exists(path_to_dot_kde):
path_to_kde_file = os.path.join(path_to_dot_kde, path_to_kde_file = os.path.join(path_to_dot_kde,
'share/services/xmpp.protocol') 'share/services/xmpp.protocol')
else: else:
path_to_kde_file = None path_to_kde_file = None
@ -814,7 +814,7 @@ default_name = ''):
# check if we have write permissions # check if we have write permissions
if not os.access(file_path, os.W_OK): if not os.access(file_path, os.W_OK):
file_name = os.path.basename(file_path) file_name = os.path.basename(file_path)
dialogs.ErrorDialog(_('Cannot overwrite existing file "%s"' % dialogs.ErrorDialog(_('Cannot overwrite existing file "%s"' %
file_name), file_name),
_('A file with this name already exists and you do not have ' _('A file with this name already exists and you do not have '
'permission to overwrite it.')) 'permission to overwrite it.'))
@ -837,7 +837,7 @@ default_name = ''):
def on_cancel(widget): def on_cancel(widget):
dialog.destroy() dialog.destroy()
dialog = dialogs.FileChooserDialog(title_text=_('Save Image as...'), dialog = dialogs.FileChooserDialog(title_text=_('Save Image as...'),
action=gtk.FILE_CHOOSER_ACTION_SAVE, buttons=(gtk.STOCK_CANCEL, action=gtk.FILE_CHOOSER_ACTION_SAVE, buttons=(gtk.STOCK_CANCEL,
gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK), gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK),
default_response=gtk.RESPONSE_OK, default_response=gtk.RESPONSE_OK,

View file

@ -55,7 +55,7 @@ import time
import locale import locale
from common import i18n from common import i18n
import common.configpaths import common.configpaths
common.configpaths.gajimpaths.init() common.configpaths.gajimpaths.init()
common.configpaths.gajimpaths.init_profile() common.configpaths.gajimpaths.init_profile()
from common import exceptions from common import exceptions
@ -63,9 +63,9 @@ import dialogs
import gtkgui_helpers import gtkgui_helpers
from common.logger import LOG_DB_PATH, constants from common.logger import LOG_DB_PATH, constants
#FIXME: constants should implement 2 way mappings #FIXME: constants should implement 2 way mappings
status = dict((constants.__dict__[i], i[5:].lower()) for i in \ status = dict((constants.__dict__[i], i[5:].lower()) for i in \
constants.__dict__.keys() if i.startswith('SHOW_')) constants.__dict__.keys() if i.startswith('SHOW_'))
from common import gajim from common import gajim
from common import helpers from common import helpers
@ -92,12 +92,12 @@ class HistoryManager:
path_to_file = os.path.join(gajim.DATA_DIR, 'pixmaps/gajim.png') path_to_file = os.path.join(gajim.DATA_DIR, 'pixmaps/gajim.png')
pix = gtk.gdk.pixbuf_new_from_file(path_to_file) pix = gtk.gdk.pixbuf_new_from_file(path_to_file)
gtk.window_set_default_icon(pix) # set the icon to all newly opened windows gtk.window_set_default_icon(pix) # set the icon to all newly opened windows
if not os.path.exists(LOG_DB_PATH): if not os.path.exists(LOG_DB_PATH):
dialogs.ErrorDialog(_('Cannot find history logs database'), dialogs.ErrorDialog(_('Cannot find history logs database'),
'%s does not exist.' % LOG_DB_PATH) '%s does not exist.' % LOG_DB_PATH)
sys.exit() sys.exit()
xml = gtkgui_helpers.get_glade('history_manager.glade') xml = gtkgui_helpers.get_glade('history_manager.glade')
self.window = xml.get_widget('history_manager_window') self.window = xml.get_widget('history_manager_window')
self.jids_listview = xml.get_widget('jids_listview') self.jids_listview = xml.get_widget('jids_listview')
@ -111,7 +111,7 @@ class HistoryManager:
self.jids_already_in = [] # holds jids that we already have in DB self.jids_already_in = [] # holds jids that we already have in DB
self.AT_LEAST_ONE_DELETION_DONE = False self.AT_LEAST_ONE_DELETION_DONE = False
self.con = sqlite.connect(LOG_DB_PATH, timeout = 20.0, self.con = sqlite.connect(LOG_DB_PATH, timeout = 20.0,
isolation_level = 'IMMEDIATE') isolation_level = 'IMMEDIATE')
self.cur = self.con.cursor() self.cur = self.con.cursor()
@ -119,15 +119,15 @@ class HistoryManager:
self._init_jids_listview() self._init_jids_listview()
self._init_logs_listview() self._init_logs_listview()
self._init_search_results_listview() self._init_search_results_listview()
self._fill_jids_listview() self._fill_jids_listview()
self.search_entry.grab_focus() self.search_entry.grab_focus()
self.window.show_all() self.window.show_all()
xml.signal_autoconnect(self) xml.signal_autoconnect(self)
def _init_jids_listview(self): def _init_jids_listview(self):
self.jids_liststore = gtk.ListStore(str, str) # jid, jid_id self.jids_liststore = gtk.ListStore(str, str) # jid, jid_id
self.jids_listview.set_model(self.jids_liststore) self.jids_listview.set_model(self.jids_liststore)
@ -136,7 +136,7 @@ class HistoryManager:
renderer_text = gtk.CellRendererText() # holds jid renderer_text = gtk.CellRendererText() # holds jid
col = gtk.TreeViewColumn(_('Contacts'), renderer_text, text = 0) col = gtk.TreeViewColumn(_('Contacts'), renderer_text, text = 0)
self.jids_listview.append_column(col) self.jids_listview.append_column(col)
self.jids_listview.get_selection().connect('changed', self.jids_listview.get_selection().connect('changed',
self.on_jids_listview_selection_changed) self.on_jids_listview_selection_changed)
@ -151,7 +151,7 @@ class HistoryManager:
col.set_sort_column_id(C_UNIXTIME) # user can click this header and sort col.set_sort_column_id(C_UNIXTIME) # user can click this header and sort
col.set_resizable(True) col.set_resizable(True)
self.logs_listview.append_column(col) self.logs_listview.append_column(col)
renderer_text = gtk.CellRendererText() # holds nickname renderer_text = gtk.CellRendererText() # holds nickname
col = gtk.TreeViewColumn(_('Nickname'), renderer_text, text = C_NICKNAME) col = gtk.TreeViewColumn(_('Nickname'), renderer_text, text = C_NICKNAME)
col.set_sort_column_id(C_NICKNAME) # user can click this header and sort col.set_sort_column_id(C_NICKNAME) # user can click this header and sort
@ -179,13 +179,13 @@ class HistoryManager:
# log_line_id (HIDDEN), jid, time, message, subject, nickname # log_line_id (HIDDEN), jid, time, message, subject, nickname
self.search_results_liststore = gtk.ListStore(str, str, str, str, str, str) self.search_results_liststore = gtk.ListStore(str, str, str, str, str, str)
self.search_results_listview.set_model(self.search_results_liststore) self.search_results_listview.set_model(self.search_results_liststore)
renderer_text = gtk.CellRendererText() # holds JID (who said this) renderer_text = gtk.CellRendererText() # holds JID (who said this)
col = gtk.TreeViewColumn(_('JID'), renderer_text, text = 1) col = gtk.TreeViewColumn(_('JID'), renderer_text, text = 1)
col.set_sort_column_id(1) # user can click this header and sort col.set_sort_column_id(1) # user can click this header and sort
col.set_resizable(True) col.set_resizable(True)
self.search_results_listview.append_column(col) self.search_results_listview.append_column(col)
renderer_text = gtk.CellRendererText() # holds time renderer_text = gtk.CellRendererText() # holds time
col = gtk.TreeViewColumn(_('Date'), renderer_text, text = C_UNIXTIME) col = gtk.TreeViewColumn(_('Date'), renderer_text, text = C_UNIXTIME)
col.set_sort_column_id(C_UNIXTIME) # user can click this header and sort col.set_sort_column_id(C_UNIXTIME) # user can click this header and sort
@ -203,13 +203,13 @@ class HistoryManager:
col.set_sort_column_id(C_SUBJECT) # user can click this header and sort col.set_sort_column_id(C_SUBJECT) # user can click this header and sort
col.set_resizable(True) col.set_resizable(True)
self.search_results_listview.append_column(col) self.search_results_listview.append_column(col)
renderer_text = gtk.CellRendererText() # holds nickname renderer_text = gtk.CellRendererText() # holds nickname
col = gtk.TreeViewColumn(_('Nickname'), renderer_text, text = C_NICKNAME) col = gtk.TreeViewColumn(_('Nickname'), renderer_text, text = C_NICKNAME)
col.set_sort_column_id(C_NICKNAME) # user can click this header and sort col.set_sort_column_id(C_NICKNAME) # user can click this header and sort
col.set_resizable(True) col.set_resizable(True)
self.search_results_listview.append_column(col) self.search_results_listview.append_column(col)
def on_history_manager_window_delete_event(self, widget, event): def on_history_manager_window_delete_event(self, widget, event):
if self.AT_LEAST_ONE_DELETION_DONE: if self.AT_LEAST_ONE_DELETION_DONE:
def on_yes(clicked): def on_yes(clicked):
@ -229,9 +229,9 @@ class HistoryManager:
'\n\nIn case you click YES, please wait...'), '\n\nIn case you click YES, please wait...'),
on_response_yes=on_yes, on_response_no=on_no) on_response_yes=on_yes, on_response_no=on_no)
return return
gtk.main_quit() gtk.main_quit()
def _fill_jids_listview(self): def _fill_jids_listview(self):
# get those jids that have at least one entry in logs # get those jids that have at least one entry in logs
self.cur.execute('SELECT jid, jid_id FROM jids WHERE jid_id IN (SELECT ' self.cur.execute('SELECT jid, jid_id FROM jids WHERE jid_id IN (SELECT '
@ -240,7 +240,7 @@ class HistoryManager:
for row in rows: for row in rows:
self.jids_already_in.append(row[0]) # jid self.jids_already_in.append(row[0]) # jid
self.jids_liststore.append(row) # jid, jid_id self.jids_liststore.append(row) # jid, jid_id
def on_jids_listview_selection_changed(self, widget, data = None): def on_jids_listview_selection_changed(self, widget, data = None):
liststore, list_of_paths = self.jids_listview.get_selection()\ liststore, list_of_paths = self.jids_listview.get_selection()\
.get_selected_rows() .get_selected_rows()
@ -249,7 +249,7 @@ class HistoryManager:
return return
self.logs_liststore.clear() # clear the store self.logs_liststore.clear() # clear the store
self.welcome_vbox.hide() self.welcome_vbox.hide()
self.search_results_scrolledwindow.hide() self.search_results_scrolledwindow.hide()
self.logs_scrolledwindow.show() self.logs_scrolledwindow.show()
@ -257,14 +257,14 @@ class HistoryManager:
list_of_rowrefs = [] list_of_rowrefs = []
for path in list_of_paths: # make them treerowrefs (it's needed) for path in list_of_paths: # make them treerowrefs (it's needed)
list_of_rowrefs.append(gtk.TreeRowReference(liststore, path)) list_of_rowrefs.append(gtk.TreeRowReference(liststore, path))
for rowref in list_of_rowrefs: # FILL THE STORE, for all rows selected for rowref in list_of_rowrefs: # FILL THE STORE, for all rows selected
path = rowref.get_path() path = rowref.get_path()
if path is None: if path is None:
continue continue
jid = liststore[path][0] # jid jid = liststore[path][0] # jid
self._fill_logs_listview(jid) self._fill_logs_listview(jid)
def _get_jid_id(self, jid): def _get_jid_id(self, jid):
'''jids table has jid and jid_id '''jids table has jid and jid_id
logs table has log_id, jid_id, contact_name, time, kind, show, message logs table has log_id, jid_id, contact_name, time, kind, show, message
@ -295,9 +295,9 @@ class HistoryManager:
pm (so higly unlikely) and if we fail we do not go chaos pm (so higly unlikely) and if we fail we do not go chaos
(user will see the first pm as if it was message in room's public chat) (user will see the first pm as if it was message in room's public chat)
and after that all okay''' and after that all okay'''
possible_room_jid = jid.split('/', 1)[0] possible_room_jid = jid.split('/', 1)[0]
self.cur.execute('SELECT jid_id FROM jids WHERE jid = ? AND type = ?', self.cur.execute('SELECT jid_id FROM jids WHERE jid = ? AND type = ?',
(possible_room_jid, constants.JID_ROOM_TYPE)) (possible_room_jid, constants.JID_ROOM_TYPE))
row = self.cur.fetchone() row = self.cur.fetchone()
@ -317,7 +317,7 @@ class HistoryManager:
return True return True
else: # normal type else: # normal type
return False return False
def _fill_logs_listview(self, jid): def _fill_logs_listview(self, jid):
'''fill the listview with all messages that user sent to or '''fill the listview with all messages that user sent to or
received from JID''' received from JID'''
@ -332,7 +332,7 @@ class HistoryManager:
''', (jid_id,)) ''', (jid_id,))
results = self.cur.fetchall() results = self.cur.fetchall()
if self._jid_is_room_type(jid): # is it room? if self._jid_is_room_type(jid): # is it room?
self.nickname_col_for_logs.set_visible(True) self.nickname_col_for_logs.set_visible(True)
self.subject_col_for_logs.set_visible(False) self.subject_col_for_logs.set_visible(False)
@ -367,7 +367,7 @@ class HistoryManager:
if message is None: if message is None:
message = '' message = ''
else: else:
message = ' : ' + message message = ' : ' + message
message = helpers.get_uf_show(gajim.SHOW_LIST[show]) + message message = helpers.get_uf_show(gajim.SHOW_LIST[show]) + message
message_ = '<span' message_ = '<span'
@ -388,7 +388,7 @@ class HistoryManager:
WHERE message LIKE ? OR subject LIKE ? WHERE message LIKE ? OR subject LIKE ?
ORDER BY time ORDER BY time
''', (like_sql, like_sql)) ''', (like_sql, like_sql))
results = self.cur.fetchall() results = self.cur.fetchall()
for row in results: for row in results:
# exposed in UI (TreeViewColumns) are only # exposed in UI (TreeViewColumns) are only
@ -403,7 +403,7 @@ class HistoryManager:
pass pass
else: else:
jid = self._get_jid_from_jid_id(jid_id) jid = self._get_jid_from_jid_id(jid_id)
self.search_results_liststore.append((log_line_id, jid, time_, self.search_results_liststore.append((log_line_id, jid, time_,
message, subject, nickname)) message, subject, nickname))
@ -412,7 +412,7 @@ class HistoryManager:
.get_selected_rows() .get_selected_rows()
if event.keyval == gtk.keysyms.Delete: if event.keyval == gtk.keysyms.Delete:
self._delete_logs(liststore, list_of_paths) self._delete_logs(liststore, list_of_paths)
def on_listview_button_press_event(self, widget, event): def on_listview_button_press_event(self, widget, event):
if event.button == 3: # right click if event.button == 3: # right click
xml = gtkgui_helpers.get_glade('history_manager.glade', 'context_menu') xml = gtkgui_helpers.get_glade('history_manager.glade', 'context_menu')
@ -420,7 +420,7 @@ class HistoryManager:
xml.get_widget('export_menuitem').hide() xml.get_widget('export_menuitem').hide()
xml.get_widget('delete_menuitem').connect('activate', xml.get_widget('delete_menuitem').connect('activate',
self.on_delete_menuitem_activate, widget) self.on_delete_menuitem_activate, widget)
xml.signal_autoconnect(self) xml.signal_autoconnect(self)
xml.get_widget('context_menu').popup(None, None, None, xml.get_widget('context_menu').popup(None, None, None,
event.button, event.time) event.button, event.time)
@ -429,21 +429,21 @@ class HistoryManager:
def on_export_menuitem_activate(self, widget): def on_export_menuitem_activate(self, widget):
xml = gtkgui_helpers.get_glade('history_manager.glade', 'filechooserdialog') xml = gtkgui_helpers.get_glade('history_manager.glade', 'filechooserdialog')
xml.signal_autoconnect(self) xml.signal_autoconnect(self)
dlg = xml.get_widget('filechooserdialog') dlg = xml.get_widget('filechooserdialog')
dlg.set_title(_('Exporting History Logs...')) dlg.set_title(_('Exporting History Logs...'))
dlg.set_current_folder(gajim.HOME_DIR) dlg.set_current_folder(gajim.HOME_DIR)
dlg.props.do_overwrite_confirmation = True dlg.props.do_overwrite_confirmation = True
response = dlg.run() response = dlg.run()
if response == gtk.RESPONSE_OK: # user want us to export ;) if response == gtk.RESPONSE_OK: # user want us to export ;)
liststore, list_of_paths = self.jids_listview.get_selection()\ liststore, list_of_paths = self.jids_listview.get_selection()\
.get_selected_rows() .get_selected_rows()
path_to_file = dlg.get_filename() path_to_file = dlg.get_filename()
self._export_jids_logs_to_file(liststore, list_of_paths, path_to_file) self._export_jids_logs_to_file(liststore, list_of_paths, path_to_file)
dlg.destroy() dlg.destroy()
def on_delete_menuitem_activate(self, widget, listview): def on_delete_menuitem_activate(self, widget, listview):
liststore, list_of_paths = listview.get_selection().get_selected_rows() liststore, list_of_paths = listview.get_selection().get_selected_rows()
if listview.name == 'jids_listview': if listview.name == 'jids_listview':
@ -467,7 +467,7 @@ class HistoryManager:
list_of_rowrefs = [] list_of_rowrefs = []
for path in list_of_paths: # make them treerowrefs (it's needed) for path in list_of_paths: # make them treerowrefs (it's needed)
list_of_rowrefs.append(gtk.TreeRowReference(liststore, path)) list_of_rowrefs.append(gtk.TreeRowReference(liststore, path))
for rowref in list_of_rowrefs: for rowref in list_of_rowrefs:
path = rowref.get_path() path = rowref.get_path()
if path is None: if path is None:
@ -508,7 +508,7 @@ class HistoryManager:
file_.write(_('%(who)s on %(time)s said: %(message)s\n') % {'who': who, file_.write(_('%(who)s on %(time)s said: %(message)s\n') % {'who': who,
'time': time_, 'message': message}) 'time': time_, 'message': message})
def _delete_jid_logs(self, liststore, list_of_paths): def _delete_jid_logs(self, liststore, list_of_paths):
paths_len = len(list_of_paths) paths_len = len(list_of_paths)
if paths_len == 0: # nothing is selected if paths_len == 0: # nothing is selected
@ -577,7 +577,7 @@ class HistoryManager:
self.AT_LEAST_ONE_DELETION_DONE = True self.AT_LEAST_ONE_DELETION_DONE = True
pri_text = i18n.ngettext( pri_text = i18n.ngettext(
'Do you really want to delete the selected message?', 'Do you really want to delete the selected message?',
'Do you really want to delete the selected messages?', paths_len) 'Do you really want to delete the selected messages?', paths_len)
@ -593,7 +593,7 @@ class HistoryManager:
self.welcome_vbox.hide() self.welcome_vbox.hide()
self.logs_scrolledwindow.hide() self.logs_scrolledwindow.hide()
self.search_results_scrolledwindow.show() self.search_results_scrolledwindow.show()
self._fill_search_results_listview(text) self._fill_search_results_listview(text)
def on_search_results_listview_row_activated(self, widget, path, column): def on_search_results_listview_row_activated(self, widget, path, column):
@ -603,28 +603,28 @@ class HistoryManager:
# make it string as in gtk liststores I have them all as strings # make it string as in gtk liststores I have them all as strings
# as this is what db returns so I don't have to fight with types # as this is what db returns so I don't have to fight with types
jid_id = self._get_jid_id(jid) jid_id = self._get_jid_id(jid)
iter_ = self.jids_liststore.get_iter_root() iter_ = self.jids_liststore.get_iter_root()
while iter_: while iter_:
# self.jids_liststore[iter_][1] holds jid_ids # self.jids_liststore[iter_][1] holds jid_ids
if self.jids_liststore[iter_][1] == jid_id: if self.jids_liststore[iter_][1] == jid_id:
break break
iter_ = self.jids_liststore.iter_next(iter_) iter_ = self.jids_liststore.iter_next(iter_)
if iter_ is None: if iter_ is None:
return return
path = self.jids_liststore.get_path(iter_) path = self.jids_liststore.get_path(iter_)
self.jids_listview.set_cursor(path) self.jids_listview.set_cursor(path)
iter_ = self.logs_liststore.get_iter_root() iter_ = self.logs_liststore.get_iter_root()
while iter_: while iter_:
# self.logs_liststore[iter_][0] holds lon_line_ids # self.logs_liststore[iter_][0] holds lon_line_ids
if self.logs_liststore[iter_][0] == log_line_id: if self.logs_liststore[iter_][0] == log_line_id:
break break
iter_ = self.logs_liststore.iter_next(iter_) iter_ = self.logs_liststore.iter_next(iter_)
path = self.logs_liststore.get_path(iter_) path = self.logs_liststore.get_path(iter_)
self.logs_listview.scroll_to_cell(path) self.logs_listview.scroll_to_cell(path)

View file

@ -80,7 +80,7 @@ class HistoryWindow:
self.query_combobox.set_active(0) self.query_combobox.set_active(0)
self.results_treeview = xml.get_widget('results_treeview') self.results_treeview = xml.get_widget('results_treeview')
self.results_window = xml.get_widget('results_scrolledwindow') self.results_window = xml.get_widget('results_scrolledwindow')
# contact_name, date, message, time # contact_name, date, message, time
model = gtk.ListStore(str, str, str, str, str) model = gtk.ListStore(str, str, str, str, str)
self.results_treeview.set_model(model) self.results_treeview.set_model(model)
@ -91,7 +91,7 @@ class HistoryWindow:
col.set_attributes(renderer, text = C_CONTACT_NAME) col.set_attributes(renderer, text = C_CONTACT_NAME)
col.set_sort_column_id(C_CONTACT_NAME) # user can click this header and sort col.set_sort_column_id(C_CONTACT_NAME) # user can click this header and sort
col.set_resizable(True) col.set_resizable(True)
col = gtk.TreeViewColumn(_('Date')) col = gtk.TreeViewColumn(_('Date'))
self.results_treeview.append_column(col) self.results_treeview.append_column(col)
renderer = gtk.CellRendererText() renderer = gtk.CellRendererText()
@ -99,14 +99,14 @@ class HistoryWindow:
col.set_attributes(renderer, text = C_UNIXTIME) col.set_attributes(renderer, text = C_UNIXTIME)
col.set_sort_column_id(C_UNIXTIME) # user can click this header and sort col.set_sort_column_id(C_UNIXTIME) # user can click this header and sort
col.set_resizable(True) col.set_resizable(True)
col = gtk.TreeViewColumn(_('Message')) col = gtk.TreeViewColumn(_('Message'))
self.results_treeview.append_column(col) self.results_treeview.append_column(col)
renderer = gtk.CellRendererText() renderer = gtk.CellRendererText()
col.pack_start(renderer) col.pack_start(renderer)
col.set_attributes(renderer, text = C_MESSAGE) col.set_attributes(renderer, text = C_MESSAGE)
col.set_resizable(True) col.set_resizable(True)
self.jid = None # The history we are currently viewing self.jid = None # The history we are currently viewing
self.account = None self.account = None
self.completion_dict = {} self.completion_dict = {}
@ -117,7 +117,7 @@ class HistoryWindow:
gobject.idle_add(self._fill_completion_dict().next) gobject.idle_add(self._fill_completion_dict().next)
if jid: if jid:
self.jid_entry.set_text(jid) self.jid_entry.set_text(jid)
gtkgui_helpers.resize_window(self.window, gtkgui_helpers.resize_window(self.window,
gajim.config.get('history_window_width'), gajim.config.get('history_window_width'),
@ -125,17 +125,17 @@ class HistoryWindow:
gtkgui_helpers.move_window(self.window, gtkgui_helpers.move_window(self.window,
gajim.config.get('history_window_x-position'), gajim.config.get('history_window_x-position'),
gajim.config.get('history_window_y-position')) gajim.config.get('history_window_y-position'))
xml.signal_autoconnect(self) xml.signal_autoconnect(self)
self.window.show_all() self.window.show_all()
def _fill_completion_dict(self): def _fill_completion_dict(self):
'''Fill completion_dict for key auto completion. Then load history for '''Fill completion_dict for key auto completion. Then load history for
current jid (by calling another function). current jid (by calling another function).
Key will be either jid or full_completion_name Key will be either jid or full_completion_name
(contact name or long description like "pm-contact from groupchat....") (contact name or long description like "pm-contact from groupchat....")
{key : (jid, account, nick_name, full_completion_name} {key : (jid, account, nick_name, full_completion_name}
this is a generator and does pseudo-threading via idle_add() this is a generator and does pseudo-threading via idle_add()
''' '''
@ -144,19 +144,19 @@ class HistoryWindow:
# Add all jids in logs.db: # Add all jids in logs.db:
db_jids = gajim.logger.get_jids_in_db() db_jids = gajim.logger.get_jids_in_db()
self.completion_dict = dict.fromkeys(db_jids) self.completion_dict = dict.fromkeys(db_jids)
self.accounts_seen_online = gajim.contacts.get_accounts()[:] self.accounts_seen_online = gajim.contacts.get_accounts()[:]
# Enhance contacts of online accounts with contact. Needed for mapping below # Enhance contacts of online accounts with contact. Needed for mapping below
for account in self.accounts_seen_online: for account in self.accounts_seen_online:
self.completion_dict.update( self.completion_dict.update(
helpers.get_contact_dict_for_account(account)) helpers.get_contact_dict_for_account(account))
muc_active_img = gtkgui_helpers.load_icon('muc_active') muc_active_img = gtkgui_helpers.load_icon('muc_active')
contact_img = gajim.interface.jabber_state_images['16']['online'] contact_img = gajim.interface.jabber_state_images['16']['online']
muc_active_pix = muc_active_img.get_pixbuf() muc_active_pix = muc_active_img.get_pixbuf()
contact_pix = contact_img.get_pixbuf() contact_pix = contact_img.get_pixbuf()
keys = self.completion_dict.keys() keys = self.completion_dict.keys()
# Move the actual jid at first so we load history faster # Move the actual jid at first so we load history faster
actual_jid = self.jid_entry.get_text().decode('utf-8') actual_jid = self.jid_entry.get_text().decode('utf-8')
@ -166,7 +166,7 @@ class HistoryWindow:
if None in keys: if None in keys:
keys.remove(None) keys.remove(None)
# Map jid to info tuple # Map jid to info tuple
# Warning : This for is time critical with big DB # Warning : This for is time critical with big DB
for key in keys: for key in keys:
completed = key completed = key
contact = self.completion_dict[completed] contact = self.completion_dict[completed]
@ -179,9 +179,9 @@ class HistoryWindow:
info_name = completed.split('@')[0] info_name = completed.split('@')[0]
info_completion = completed info_completion = completed
info_jid = completed info_jid = completed
info_acc = self._get_account_for_jid(info_jid) info_acc = self._get_account_for_jid(info_jid)
if gajim.logger.jid_is_room_jid(completed) or\ if gajim.logger.jid_is_room_jid(completed) or\
gajim.logger.jid_is_from_pm(completed): gajim.logger.jid_is_from_pm(completed):
pix = muc_active_pix pix = muc_active_pix
@ -204,7 +204,7 @@ class HistoryWindow:
yield True yield True
keys.sort() keys.sort()
yield False yield False
def _get_account_for_jid(self, jid): def _get_account_for_jid(self, jid):
'''Return the corresponding account of the jid. '''Return the corresponding account of the jid.
May be None if an account could not be found''' May be None if an account could not be found'''
@ -245,8 +245,8 @@ class HistoryWindow:
widget.select_region(0, -1) # select text widget.select_region(0, -1) # select text
def _load_history(self, jid_or_name, account = None): def _load_history(self, jid_or_name, account = None):
'''Load history for the given jid/name and show it''' '''Load history for the given jid/name and show it'''
if jid_or_name and jid_or_name in self.completion_dict: if jid_or_name and jid_or_name in self.completion_dict:
# a full qualified jid or a contact name was entered # a full qualified jid or a contact name was entered
info_jid, info_account, info_name, info_completion = self.completion_dict[jid_or_name] info_jid, info_account, info_name, info_completion = self.completion_dict[jid_or_name]
self.jids_to_search = [info_jid] self.jids_to_search = [info_jid]
@ -256,7 +256,7 @@ class HistoryWindow:
self.account = account self.account = account
else: else:
self.account = info_account self.account = info_account
if self.account is None: if self.account is None:
# We don't know account. Probably a gc not opened or an # We don't know account. Probably a gc not opened or an
# account not connected. # account not connected.
# Disable possibility to say if we want to log or not # Disable possibility to say if we want to log or not
@ -275,7 +275,7 @@ class HistoryWindow:
log = False log = False
self.checkbutton.set_active(log) self.checkbutton.set_active(log)
self.checkbutton.set_sensitive(True) self.checkbutton.set_sensitive(True)
self.jids_to_search = [info_jid] self.jids_to_search = [info_jid]
# select logs for last date we have logs with contact # select logs for last date we have logs with contact
@ -289,7 +289,7 @@ class HistoryWindow:
gtk_month = gtkgui_helpers.make_python_month_gtk_month(m) gtk_month = gtkgui_helpers.make_python_month_gtk_month(m)
self.calendar.select_month(gtk_month, y) self.calendar.select_month(gtk_month, y)
self.calendar.select_day(d) self.calendar.select_day(d)
self.query_entry.set_sensitive(True) self.query_entry.set_sensitive(True)
self.query_entry.grab_focus() self.query_entry.grab_focus()
@ -301,7 +301,7 @@ class HistoryWindow:
# we have got nothing to show or to search in # we have got nothing to show or to search in
self.jid = None self.jid = None
self.account = None self.account = None
self.history_buffer.set_text('') # clear the buffer self.history_buffer.set_text('') # clear the buffer
self.query_entry.set_sensitive(False) self.query_entry.set_sensitive(False)
@ -310,7 +310,7 @@ class HistoryWindow:
self.calendar.clear_marks() self.calendar.clear_marks()
self.results_window.set_property('visible', False) self.results_window.set_property('visible', False)
title = _('Conversation History') title = _('Conversation History')
self.window.set_title(title) self.window.set_title(title)
@ -320,9 +320,9 @@ class HistoryWindow:
year, month, day = widget.get_date() # integers year, month, day = widget.get_date() # integers
month = gtkgui_helpers.make_gtk_month_python_month(month) month = gtkgui_helpers.make_gtk_month_python_month(month)
self._add_lines_for_date(year, month, day) self._add_lines_for_date(year, month, day)
def on_calendar_month_changed(self, widget): def on_calendar_month_changed(self, widget):
'''asks for days in this month if they have logs it bolds them (marks '''asks for days in this month if they have logs it bolds them (marks
them) them)
''' '''
if not self.jid: if not self.jid:
@ -371,7 +371,7 @@ class HistoryWindow:
# line[0] is contact_name, line[1] is time of message # line[0] is contact_name, line[1] is time of message
# line[2] is kind, line[3] is show, line[4] is message # line[2] is kind, line[3] is show, line[4] is message
self._add_new_line(line[0], line[1], line[2], line[3], line[4]) self._add_new_line(line[0], line[1], line[2], line[3], line[4])
def _add_new_line(self, contact_name, tim, kind, show, message): def _add_new_line(self, contact_name, tim, kind, show, message):
'''add a new line in textbuffer''' '''add a new line in textbuffer'''
if not message and kind not in (constants.KIND_STATUS, if not message and kind not in (constants.KIND_STATUS,
@ -379,7 +379,7 @@ class HistoryWindow:
return return
buf = self.history_buffer buf = self.history_buffer
end_iter = buf.get_end_iter() end_iter = buf.get_end_iter()
if gajim.config.get('print_time') == 'always': if gajim.config.get('print_time') == 'always':
timestamp_str = gajim.config.get('time_stamp') timestamp_str = gajim.config.get('time_stamp')
timestamp_str = helpers.from_one_line(timestamp_str) timestamp_str = helpers.from_one_line(timestamp_str)
@ -397,9 +397,9 @@ class HistoryWindow:
tag_name = '' tag_name = ''
tag_msg = '' tag_msg = ''
show = self._get_string_show_from_constant_int(show) show = self._get_string_show_from_constant_int(show)
if kind == constants.KIND_GC_MSG: if kind == constants.KIND_GC_MSG:
tag_name = 'incoming' tag_name = 'incoming'
elif kind in (constants.KIND_SINGLE_MSG_RECV, elif kind in (constants.KIND_SINGLE_MSG_RECV,
@ -410,10 +410,10 @@ class HistoryWindow:
constants.KIND_CHAT_MSG_SENT): constants.KIND_CHAT_MSG_SENT):
if self.account: if self.account:
contact_name = gajim.nicks[self.account] contact_name = gajim.nicks[self.account]
else: else:
# we don't have roster, we don't know our own nick, use first # we don't have roster, we don't know our own nick, use first
# account one (urk!) # account one (urk!)
account = gajim.contacts.get_accounts()[0] account = gajim.contacts.get_accounts()[0]
contact_name = gajim.nicks[account] contact_name = gajim.nicks[account]
tag_name = 'outgoing' tag_name = 'outgoing'
elif kind == constants.KIND_GCSTATUS: elif kind == constants.KIND_GCSTATUS:
@ -458,7 +458,7 @@ class HistoryWindow:
model = self.results_treeview.get_model() model = self.results_treeview.get_model()
model.clear() model.clear()
if text == '': if text == '':
self.results_window.set_property('visible', False) self.results_window.set_property('visible', False)
return return
else: else:
self.results_window.set_property('visible', True) self.results_window.set_property('visible', True)
@ -493,7 +493,7 @@ class HistoryWindow:
local_time = time.localtime(tim) local_time = time.localtime(tim)
date = time.strftime('%Y-%m-%d', local_time) date = time.strftime('%Y-%m-%d', local_time)
# jid (to which log is assigned to), name, date, message, # jid (to which log is assigned to), name, date, message,
# time (full unix time) # time (full unix time)
model.append((jid, contact_name, date, message, tim)) model.append((jid, contact_name, date, message, tim))
@ -513,14 +513,14 @@ class HistoryWindow:
# Groupchat Histories # Groupchat Histories
self.query_entry.set_sensitive(True) self.query_entry.set_sensitive(True)
self.query_entry.grab_focus() self.query_entry.grab_focus()
self.jids_to_search = (jid for jid in gajim.logger.get_jids_in_db() self.jids_to_search = (jid for jid in gajim.logger.get_jids_in_db()
if gajim.logger.jid_is_room_jid(jid)) if gajim.logger.jid_is_room_jid(jid))
if self.query_combobox.get_active() == 2: if self.query_combobox.get_active() == 2:
# All Chat Histories # All Chat Histories
self.query_entry.set_sensitive(True) self.query_entry.set_sensitive(True)
self.query_entry.grab_focus() self.query_entry.grab_focus()
self.jids_to_search = gajim.logger.get_jids_in_db() self.jids_to_search = gajim.logger.get_jids_in_db()
def on_results_treeview_row_activated(self, widget, path, column): def on_results_treeview_row_activated(self, widget, path, column):
'''a row was double clicked, get date from row, and select it in calendar '''a row was double clicked, get date from row, and select it in calendar
which results to showing conversation logs for that date''' which results to showing conversation logs for that date'''
@ -534,7 +534,7 @@ class HistoryWindow:
gtk_month = tim[1] gtk_month = tim[1]
month = gtkgui_helpers.make_python_month_gtk_month(gtk_month) month = gtkgui_helpers.make_python_month_gtk_month(gtk_month)
day = tim[2] day = tim[2]
# switch to belonging logfile if necessary # switch to belonging logfile if necessary
log_jid = model[path][C_LOG_JID] log_jid = model[path][C_LOG_JID]
if log_jid != self.jid: if log_jid != self.jid:
@ -543,7 +543,7 @@ class HistoryWindow:
# avoid reruning mark days algo if same month and year! # avoid reruning mark days algo if same month and year!
if year != cur_year or gtk_month != cur_month: if year != cur_year or gtk_month != cur_month:
self.calendar.select_month(month, year) self.calendar.select_month(month, year)
self.calendar.select_day(day) self.calendar.select_day(day)
unix_time = model[path][C_TIME] unix_time = model[path][C_TIME]
self._scroll_to_result(unix_time) self._scroll_to_result(unix_time)
@ -564,7 +564,7 @@ class HistoryWindow:
match_end_iter.forward_line() # highlight all message not just time match_end_iter.forward_line() # highlight all message not just time
self.history_buffer.apply_tag_by_name('highlight', match_start_iter, self.history_buffer.apply_tag_by_name('highlight', match_start_iter,
match_end_iter) match_end_iter)
match_start_mark = self.history_buffer.create_mark('match_start', match_start_mark = self.history_buffer.create_mark('match_start',
match_start_iter, True) match_start_iter, True)
self.history_textview.tv.scroll_to_mark(match_start_mark, 0, True) self.history_textview.tv.scroll_to_mark(match_start_mark, 0, True)
@ -593,7 +593,7 @@ class HistoryWindow:
gobject.idle_add(self._fill_completion_dict().next) gobject.idle_add(self._fill_completion_dict().next)
else: else:
# Only in that case because it's called by self._fill_completion_dict() # Only in that case because it's called by self._fill_completion_dict()
# otherwise # otherwise
self._load_history(jid, account) self._load_history(jid, account)
self.results_window.set_property('visible', False) self.results_window.set_property('visible', False)

View file

@ -241,7 +241,7 @@ def _parse_css_color(color):
def style_iter(style): def style_iter(style):
return (map(lambda x:x.strip(),item.split(':', 1)) for item in style.split(';') if len(item.strip())) return (map(lambda x:x.strip(),item.split(':', 1)) for item in style.split(';') if len(item.strip()))
class HtmlHandler(xml.sax.handler.ContentHandler): class HtmlHandler(xml.sax.handler.ContentHandler):
"""A handler to display html to a gtk textview. """A handler to display html to a gtk textview.
@ -280,9 +280,9 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
self.iter.get_attributes(attrs) self.iter.get_attributes(attrs)
self.iter.forward_char() self.iter.forward_char()
return attrs return attrs
else: else:
# Workaround http://bugzilla.gnome.org/show_bug.cgi?id=317455 # Workaround http://bugzilla.gnome.org/show_bug.cgi?id=317455
def _get_current_style_attr(self, propname, comb_oper=None): def _get_current_style_attr(self, propname, comb_oper=None):
tags = [tag for tag in self.styles if tag is not None] tags = [tag for tag in self.styles if tag is not None]
@ -326,7 +326,7 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
sign = cmp(val,0) sign = cmp(val,0)
# limits: 1% to 500% # limits: 1% to 500%
val = sign*max(1,min(abs(val),500)) val = sign*max(1,min(abs(val),500))
frac = val/100 frac = val/100
if font_relative: if font_relative:
attrs = self._get_current_attributes() attrs = self._get_current_attributes()
font_size = attrs.font.get_size() / pango.SCALE font_size = attrs.font.get_size() / pango.SCALE
@ -378,7 +378,7 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
callback(val, *args) callback(val, *args)
except Exception: except Exception:
warnings.warn('Unable to parse length value "%s"' % value) warnings.warn('Unable to parse length value "%s"' % value)
def __parse_font_size_cb(length, tag): def __parse_font_size_cb(length, tag):
tag.set_property('size-points', length/display_resolution) tag.set_property('size-points', length/display_resolution)
__parse_font_size_cb = staticmethod(__parse_font_size_cb) __parse_font_size_cb = staticmethod(__parse_font_size_cb)
@ -432,7 +432,7 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
length += styles[-1].get_property(propname) length += styles[-1].get_property(propname)
tag.set_property(propname, length) tag.set_property(propname, length)
#__frac_length_tag_cb = staticmethod(__frac_length_tag_cb) #__frac_length_tag_cb = staticmethod(__frac_length_tag_cb)
def _parse_style_margin_left(self, tag, value): def _parse_style_margin_left(self, tag, value):
# block relative # block relative
self._parse_length(value, False, True, 1, 1000, self.__frac_length_tag_cb, self._parse_length(value, False, True, 1, 1000, self.__frac_length_tag_cb,
@ -479,7 +479,7 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
warnings.warn('Invalid text-align:%s requested' % value) warnings.warn('Invalid text-align:%s requested' % value)
else: else:
tag.set_property('justification', align) tag.set_property('justification', align)
def _parse_style_text_decoration(self, tag, value): def _parse_style_text_decoration(self, tag, value):
values = value.split(' ') values = value.split(' ')
if 'none' in values: if 'none' in values:
@ -497,7 +497,7 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
warnings.warn('text-decoration:blink not implemented') warnings.warn('text-decoration:blink not implemented')
if 'overline' in values: if 'overline' in values:
warnings.warn('text-decoration:overline not implemented') warnings.warn('text-decoration:overline not implemented')
def _parse_style_white_space(self, tag, value): def _parse_style_white_space(self, tag, value):
if value == 'pre': if value == 'pre':
tag.set_property('wrap_mode', gtk.WRAP_NONE) tag.set_property('wrap_mode', gtk.WRAP_NONE)
@ -511,7 +511,7 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
tag.set_property(propname, value) tag.set_property(propname, value)
except Exception: except Exception:
gajim.log.warn( "Error with prop: " + propname + " for tag: " + str(tag)) gajim.log.warn( "Error with prop: " + propname + " for tag: " + str(tag))
def _parse_style_width(self, tag, value): def _parse_style_width(self, tag, value):
if value == 'auto': if value == 'auto':
@ -523,8 +523,8 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
return return
self._parse_length(value, False, False, 1, 1000, self.__length_tag_cb, self._parse_length(value, False, False, 1, 1000, self.__length_tag_cb,
tag, "height") tag, "height")
# build a dictionary mapping styles to methods, for greater speed # build a dictionary mapping styles to methods, for greater speed
__style_methods = dict() __style_methods = dict()
for style in ('background-color', 'color', 'font-family', 'font-size', for style in ('background-color', 'color', 'font-family', 'font-size',
@ -562,20 +562,20 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
'''Process a img tag. '''Process a img tag.
''' '''
try: try:
# Wait maximum 1s for connection # Wait maximum 1s for connection
socket.setdefaulttimeout(1) socket.setdefaulttimeout(1)
try: try:
f = urllib2.urlopen(attrs['src']) f = urllib2.urlopen(attrs['src'])
except Exception, ex: except Exception, ex:
gajim.log.debug('Error loading image %s ' % attrs['src'] + str(ex)) gajim.log.debug('Error loading image %s ' % attrs['src'] + str(ex))
pixbuf = None pixbuf = None
alt = attrs.get('alt', 'Broken image') alt = attrs.get('alt', 'Broken image')
else: else:
# Wait 0.1s between each byte # Wait 0.1s between each byte
try: try:
f.fp._sock.fp._sock.settimeout(0.5) f.fp._sock.fp._sock.settimeout(0.5)
except Exception: except Exception:
pass pass
# Max image size = 2 MB (to try to prevent DoS) # Max image size = 2 MB (to try to prevent DoS)
mem = '' mem = ''
deadline = time.time() + 3 deadline = time.time() + 3
@ -717,7 +717,7 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
def _starts_line(self): def _starts_line(self):
return self.starting or self.iter.starts_line() return self.starting or self.iter.starts_line()
def _flush_text(self): def _flush_text(self):
if not self.text: return if not self.text: return
text, self.text = self.text, '' text, self.text = self.text, ''
@ -762,7 +762,7 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
img = gtk.Image() img = gtk.Image()
img.set_from_file(self.textview.interface.emoticons[emot_ascii]) img.set_from_file(self.textview.interface.emoticons[emot_ascii])
img.show() img.show()
# TODO: add alt/tooltip with the special_text (a11y) # TODO: add alt/tooltip with the special_text (a11y)
self.textview.add_child_at_anchor(img, anchor) self.textview.add_child_at_anchor(img, anchor)
elif af: elif af:
# now print it # now print it
@ -779,7 +779,7 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
self.endElement('i') self.endElement('i')
if index < len(text): if index < len(text):
self._insert_text(text[index:]) self._insert_text(text[index:])
def characters(self, content): def characters(self, content):
if self.preserve: if self.preserve:
self.text += content self.text += content
@ -804,7 +804,7 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
#FIXME: if we want to use id, it needs to be unique across #FIXME: if we want to use id, it needs to be unique across
# the whole textview, so we need to add something like the # the whole textview, so we need to add something like the
# message-id to it. # message-id to it.
#id_ = attrs.get('id',None) #id_ = attrs.get('id',None)
id_ = None id_ = None
if name == 'a': if name == 'a':
#TODO: accesskey, charset, hreflang, rel, rev, tabindex, type #TODO: accesskey, charset, hreflang, rel, rev, tabindex, type
@ -827,11 +827,11 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
tag = self._process_img(attrs) tag = self._process_img(attrs)
if name in element_styles: if name in element_styles:
style += element_styles[name] style += element_styles[name]
# so that explicit styles override implicit ones, # so that explicit styles override implicit ones,
# we add the attribute last # we add the attribute last
style += ";"+attrs.get('style','') style += ";"+attrs.get('style','')
if style == '': if style == '':
style = None style = None
self._begin_span(style, tag, id_) self._begin_span(style, tag, id_)
if name == 'br': if name == 'br':
@ -917,7 +917,7 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
# self.text = ' ' # self.text = ' '
class HtmlTextView(gtk.TextView): class HtmlTextView(gtk.TextView):
def __init__(self): def __init__(self):
gobject.GObject.__init__(self) gobject.GObject.__init__(self)
self.set_wrap_mode(gtk.WRAP_CHAR) self.set_wrap_mode(gtk.WRAP_CHAR)
@ -992,7 +992,7 @@ class HtmlTextView(gtk.TextView):
parser = xml.sax.make_parser() parser = xml.sax.make_parser()
parser.setContentHandler(HtmlHandler(self, eob)) parser.setContentHandler(HtmlHandler(self, eob))
parser.parse(StringIO(html)) parser.parse(StringIO(html))
# too much space after :) # too much space after :)
#if not eob.starts_line(): #if not eob.starts_line():
# buffer_.insert(eob, '\n') # buffer_.insert(eob, '\n')
@ -1075,7 +1075,7 @@ if __name__ == '__main__':
htmlview.display_html('<hr />') htmlview.display_html('<hr />')
htmlview.display_html(''' htmlview.display_html('''
<p style='font-size:large'> <p style='font-size:large'>
<span style='font-style: italic'>O<span style='font-size:larger'>M</span>G</span>, <span style='font-style: italic'>O<span style='font-size:larger'>M</span>G</span>,
I&apos;m <span style='color:green'>green</span> I&apos;m <span style='color:green'>green</span>
with <span style='font-weight: bold'>envy</span>! with <span style='font-weight: bold'>envy</span>!
</p> </p>
@ -1094,8 +1094,8 @@ if __name__ == '__main__':
<body xmlns='http://www.w3.org/1999/xhtml'> <body xmlns='http://www.w3.org/1999/xhtml'>
<p style='text-align:center'>Hey, are you licensed to <a href='http://www.jabber.org/'>Jabber</a>?</p> <p style='text-align:center'>Hey, are you licensed to <a href='http://www.jabber.org/'>Jabber</a>?</p>
<p style='text-align:right'><img src='http://www.jabber.org/images/psa-license.jpg' <p style='text-align:right'><img src='http://www.jabber.org/images/psa-license.jpg'
alt='A License to Jabber' alt='A License to Jabber'
width='50%' height='50%' width='50%' height='50%'
/></p> /></p>
</body> </body>
''') ''')
@ -1107,7 +1107,7 @@ if __name__ == '__main__':
<li> Two </li> <li> Two </li>
<li> Three </li> <li> Three </li>
</ul><hr /><pre style="background-color:rgb(120,120,120)">def fac(n): </ul><hr /><pre style="background-color:rgb(120,120,120)">def fac(n):
def faciter(n,acc): def faciter(n,acc):
if n==0: return acc if n==0: return acc
return faciter(n-1, acc*n) return faciter(n-1, acc*n)
if n&lt;0: raise ValueError('Must be non-negative') if n&lt;0: raise ValueError('Must be non-negative')

View file

@ -37,8 +37,8 @@ Provides IPython console widget.
@copyright: Copyright (c) 2007 IBM Corporation @copyright: Copyright (c) 2007 IBM Corporation
@license: BSD @license: BSD
All rights reserved. This program and the accompanying materials are made All rights reserved. This program and the accompanying materials are made
available under the terms of the BSD which accompanies this distribution, and available under the terms of the BSD which accompanies this distribution, and
is available at U{http://www.opensource.org/licenses/bsd-license.php} is available at U{http://www.opensource.org/licenses/bsd-license.php}
''' '''
@ -57,7 +57,7 @@ except ImportError:
class IterableIPShell: class IterableIPShell:
''' '''
Create an IPython instance. Does not start a blocking event loop, Create an IPython instance. Does not start a blocking event loop,
instead allow single iterations. This allows embedding in GTK+ instead allow single iterations. This allows embedding in GTK+
without blockage. without blockage.
@ivar IP: IPython instance. @ivar IP: IPython instance.
@ -65,17 +65,17 @@ class IterableIPShell:
@ivar iter_more: Indicates if the line executed was a complete command, @ivar iter_more: Indicates if the line executed was a complete command,
or we should wait for more. or we should wait for more.
@type iter_more: integer @type iter_more: integer
@ivar history_level: The place in history where we currently are @ivar history_level: The place in history where we currently are
when pressing up/down. when pressing up/down.
@type history_level: integer @type history_level: integer
@ivar complete_sep: Seperation delimeters for completion function. @ivar complete_sep: Seperation delimeters for completion function.
@type complete_sep: _sre.SRE_Pattern @type complete_sep: _sre.SRE_Pattern
''' '''
def __init__(self,argv=[],user_ns=None,user_global_ns=None, def __init__(self,argv=[],user_ns=None,user_global_ns=None,
cin=None, cout=None,cerr=None, input_func=None): cin=None, cout=None,cerr=None, input_func=None):
''' '''
@param argv: Command line options for IPython @param argv: Command line options for IPython
@type argv: list @type argv: list
@param user_ns: User namespace. @param user_ns: User namespace.
@ -85,7 +85,7 @@ class IterableIPShell:
@param cin: Console standard input. @param cin: Console standard input.
@type cin: IO stream @type cin: IO stream
@param cout: Console standard output. @param cout: Console standard output.
@type cout: IO stream @type cout: IO stream
@param cerr: Console standard error. @param cerr: Console standard error.
@type cerr: IO stream @type cerr: IO stream
@param input_func: Replacement for builtin raw_input() @param input_func: Replacement for builtin raw_input()
@ -100,13 +100,13 @@ class IterableIPShell:
if cerr: if cerr:
IPython.Shell.Term.cerr = cerr IPython.Shell.Term.cerr = cerr
# This is to get rid of the blockage that accurs during # This is to get rid of the blockage that accurs during
# IPython.Shell.InteractiveShell.user_setup() # IPython.Shell.InteractiveShell.user_setup()
IPython.iplib.raw_input = lambda x: None IPython.iplib.raw_input = lambda x: None
self.term = IPython.genutils.IOTerm(cin=cin, cout=cout, cerr=cerr) self.term = IPython.genutils.IOTerm(cin=cin, cout=cout, cerr=cerr)
os.environ['TERM'] = 'dumb' os.environ['TERM'] = 'dumb'
excepthook = sys.excepthook excepthook = sys.excepthook
self.IP = IPython.Shell.make_IPython( self.IP = IPython.Shell.make_IPython(
argv,user_ns=user_ns, argv,user_ns=user_ns,
user_global_ns=user_global_ns, user_global_ns=user_global_ns,
@ -136,7 +136,7 @@ class IterableIPShell:
self.IP.resetbuffer() self.IP.resetbuffer()
# keep cache in sync with the prompt counter: # keep cache in sync with the prompt counter:
self.IP.outputcache.prompt_count -= 1 self.IP.outputcache.prompt_count -= 1
if self.IP.autoindent: if self.IP.autoindent:
self.IP.indent_current_nsp = 0 self.IP.indent_current_nsp = 0
self.iter_more = 0 self.iter_more = 0
@ -158,27 +158,27 @@ class IterableIPShell:
def historyBack(self): def historyBack(self):
''' '''
Provides one history command back. Provides one history command back.
@return: The command string. @return: The command string.
@rtype: string @rtype: string
''' '''
self.history_level -= 1 self.history_level -= 1
return self._getHistory() return self._getHistory()
def historyForward(self): def historyForward(self):
''' '''
Provides one history command forward. Provides one history command forward.
@return: The command string. @return: The command string.
@rtype: string @rtype: string
''' '''
self.history_level += 1 self.history_level += 1
return self._getHistory() return self._getHistory()
def _getHistory(self): def _getHistory(self):
''' '''
Get's the command string of the current history level. Get's the command string of the current history level.
@return: Historic command string. @return: Historic command string.
@rtype: string @rtype: string
''' '''
@ -192,7 +192,7 @@ class IterableIPShell:
def updateNamespace(self, ns_dict): def updateNamespace(self, ns_dict):
''' '''
Add the current dictionary to the shell namespace. Add the current dictionary to the shell namespace.
@param ns_dict: A dictionary of symbol-values. @param ns_dict: A dictionary of symbol-values.
@type ns_dict: dictionary @type ns_dict: dictionary
''' '''
@ -201,11 +201,11 @@ class IterableIPShell:
def complete(self, line): def complete(self, line):
''' '''
Returns an auto completed line and/or posibilities for completion. Returns an auto completed line and/or posibilities for completion.
@param line: Given line so far. @param line: Given line so far.
@type line: string @type line: string
@return: Line completed as for as possible, @return: Line completed as for as possible,
and possible further completions. and possible further completions.
@rtype: tuple @rtype: tuple
''' '''
@ -230,12 +230,12 @@ class IterableIPShell:
else: else:
completed = line completed = line
return completed, possibilities return completed, possibilities
def shell(self, cmd,verbose=0,debug=0,header=''): def shell(self, cmd,verbose=0,debug=0,header=''):
''' '''
Replacement method to allow shell commands without them blocking. Replacement method to allow shell commands without them blocking.
@param cmd: Shell command to execute. @param cmd: Shell command to execute.
@type cmd: string @type cmd: string
@param verbose: Verbosity @param verbose: Verbosity
@ -286,28 +286,28 @@ class ConsoleView(gtk.TextView):
self.modify_font(pango.FontDescription('Mono')) self.modify_font(pango.FontDescription('Mono'))
self.set_cursor_visible(True) self.set_cursor_visible(True)
self.text_buffer = self.get_buffer() self.text_buffer = self.get_buffer()
self.mark = self.text_buffer.create_mark('scroll_mark', self.mark = self.text_buffer.create_mark('scroll_mark',
self.text_buffer.get_end_iter(), self.text_buffer.get_end_iter(),
False) False)
for code in self.ANSI_COLORS: for code in self.ANSI_COLORS:
self.text_buffer.create_tag(code, self.text_buffer.create_tag(code,
foreground=self.ANSI_COLORS[code], foreground=self.ANSI_COLORS[code],
weight=700) weight=700)
self.text_buffer.create_tag('0') self.text_buffer.create_tag('0')
self.text_buffer.create_tag('notouch', editable=False) self.text_buffer.create_tag('notouch', editable=False)
self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?') self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
self.line_start = \ self.line_start = \
self.text_buffer.create_mark('line_start', self.text_buffer.create_mark('line_start',
self.text_buffer.get_end_iter(), True) self.text_buffer.get_end_iter(), True)
self.connect('key-press-event', self.onKeyPress) self.connect('key-press-event', self.onKeyPress)
def write(self, text, editable=False): def write(self, text, editable=False):
gobject.idle_add(self._write, text, editable) gobject.idle_add(self._write, text, editable)
def _write(self, text, editable=False): def _write(self, text, editable=False):
''' '''
Write given text to buffer. Write given text to buffer.
@param text: Text to append. @param text: Text to append.
@type text: string @type text: string
@param editable: If true, added text is editable. @param editable: If true, added text is editable.
@ -315,8 +315,8 @@ class ConsoleView(gtk.TextView):
''' '''
segments = self.color_pat.split(text) segments = self.color_pat.split(text)
segment = segments.pop(0) segment = segments.pop(0)
start_mark = self.text_buffer.create_mark(None, start_mark = self.text_buffer.create_mark(None,
self.text_buffer.get_end_iter(), self.text_buffer.get_end_iter(),
True) True)
self.text_buffer.insert(self.text_buffer.get_end_iter(), segment) self.text_buffer.insert(self.text_buffer.get_end_iter(), segment)
@ -341,7 +341,7 @@ class ConsoleView(gtk.TextView):
def _showPrompt(self, prompt): def _showPrompt(self, prompt):
''' '''
Prints prompt at start of line. Prints prompt at start of line.
@param prompt: Prompt to print. @param prompt: Prompt to print.
@type prompt: string @type prompt: string
''' '''
@ -355,7 +355,7 @@ class ConsoleView(gtk.TextView):
def _changeLine(self, text): def _changeLine(self, text):
''' '''
Replace currently entered command line with given text. Replace currently entered command line with given text.
@param text: Text to use as replacement. @param text: Text to use as replacement.
@type text: string @type text: string
''' '''
@ -367,7 +367,7 @@ class ConsoleView(gtk.TextView):
def getCurrentLine(self): def getCurrentLine(self):
''' '''
Get text in current command line. Get text in current command line.
@return: Text of current command line. @return: Text of current command line.
@rtype: string @rtype: string
''' '''
@ -382,14 +382,14 @@ class ConsoleView(gtk.TextView):
def _showReturned(self, text): def _showReturned(self, text):
''' '''
Show returned text from last command and print new prompt. Show returned text from last command and print new prompt.
@param text: Text to show. @param text: Text to show.
@type text: string @type text: string
''' '''
iter_ = self.text_buffer.get_iter_at_mark(self.line_start) iter_ = self.text_buffer.get_iter_at_mark(self.line_start)
iter_.forward_to_line_end() iter_.forward_to_line_end()
self.text_buffer.apply_tag_by_name( self.text_buffer.apply_tag_by_name(
'notouch', 'notouch',
self.text_buffer.get_iter_at_mark(self.line_start), self.text_buffer.get_iter_at_mark(self.line_start),
iter_) iter_)
self._write('\n'+text) self._write('\n'+text)
@ -401,15 +401,15 @@ class ConsoleView(gtk.TextView):
def onKeyPress(self, widget, event): def onKeyPress(self, widget, event):
''' '''
Key press callback used for correcting behavior for console-like Key press callback used for correcting behavior for console-like
interfaces. For example 'home' should go to prompt, not to begining of interfaces. For example 'home' should go to prompt, not to begining of
line. line.
@param widget: Widget that key press accored in. @param widget: Widget that key press accored in.
@type widget: gtk.Widget @type widget: gtk.Widget
@param event: Event object @param event: Event object
@type event: gtk.gdk.Event @type event: gtk.gdk.Event
@return: Return True if event should not trickle. @return: Return True if event should not trickle.
@rtype: boolean @rtype: boolean
''' '''
@ -419,7 +419,7 @@ class ConsoleView(gtk.TextView):
selection_iter = self.text_buffer.get_iter_at_mark(selection_mark) selection_iter = self.text_buffer.get_iter_at_mark(selection_mark)
start_iter = self.text_buffer.get_iter_at_mark(self.line_start) start_iter = self.text_buffer.get_iter_at_mark(self.line_start)
if event.keyval == gtk.keysyms.Home: if event.keyval == gtk.keysyms.Home:
if event.state == 0: if event.state == 0:
self.text_buffer.place_cursor(start_iter) self.text_buffer.place_cursor(start_iter)
return True return True
elif event.state == gtk.gdk.SHIFT_MASK: elif event.state == gtk.gdk.SHIFT_MASK:
@ -440,7 +440,7 @@ class ConsoleView(gtk.TextView):
elif insert_iter.compare(selection_iter) < 0: elif insert_iter.compare(selection_iter) < 0:
self.text_buffer.move_mark(insert_mark, start_iter) self.text_buffer.move_mark(insert_mark, start_iter)
elif insert_iter.compare(selection_iter) > 0: elif insert_iter.compare(selection_iter) > 0:
self.text_buffer.move_mark(selection_mark, start_iter) self.text_buffer.move_mark(selection_mark, start_iter)
return self.onKeyPressExtend(event) return self.onKeyPressExtend(event)
@ -461,7 +461,7 @@ class IPythonView(ConsoleView, IterableIPShell):
''' '''
ConsoleView.__init__(self) ConsoleView.__init__(self)
self.cout = StringIO() self.cout = StringIO()
IterableIPShell.__init__(self, cout=self.cout,cerr=self.cout, IterableIPShell.__init__(self, cout=self.cout,cerr=self.cout,
input_func=self.raw_input) input_func=self.raw_input)
# self.connect('key_press_event', self.keyPress) # self.connect('key_press_event', self.keyPress)
self.execute() self.execute()
@ -472,10 +472,10 @@ class IPythonView(ConsoleView, IterableIPShell):
def raw_input(self, prompt=''): def raw_input(self, prompt=''):
''' '''
Custom raw_input() replacement. Get's current line from console buffer. Custom raw_input() replacement. Get's current line from console buffer.
@param prompt: Prompt to print. Here for compatability as replacement. @param prompt: Prompt to print. Here for compatability as replacement.
@type prompt: string @type prompt: string
@return: The current command line text. @return: The current command line text.
@rtype: string @rtype: string
''' '''
@ -486,14 +486,14 @@ class IPythonView(ConsoleView, IterableIPShell):
def onKeyPressExtend(self, event): def onKeyPressExtend(self, event):
''' '''
Key press callback with plenty of shell goodness, like history, Key press callback with plenty of shell goodness, like history,
autocompletions, etc. autocompletions, etc.
@param widget: Widget that key press occured in. @param widget: Widget that key press occured in.
@type widget: gtk.Widget @type widget: gtk.Widget
@param event: Event object. @param event: Event object.
@type event: gtk.gdk.Event @type event: gtk.gdk.Event
@return: True if event should not trickle. @return: True if event should not trickle.
@rtype: boolean @rtype: boolean
''' '''
@ -533,6 +533,6 @@ class IPythonView(ConsoleView, IterableIPShell):
if rv: rv = rv.strip('\n') if rv: rv = rv.strip('\n')
self.showReturned(rv) self.showReturned(rv)
self.cout.truncate(0) self.cout.truncate(0)
# vim: se ts=3: # vim: se ts=3:

View file

@ -35,7 +35,7 @@ class MessageTextView(gtk.TextView):
(int, gtk.gdk.ModifierType ) # arguments (int, gtk.gdk.ModifierType ) # arguments
) )
) )
def __init__(self): def __init__(self):
gtk.TextView.__init__(self) gtk.TextView.__init__(self)
@ -56,7 +56,7 @@ class MessageTextView(gtk.TextView):
self.end_tags = {} self.end_tags = {}
self.color_tags = [] self.color_tags = []
self.fonts_tags = [] self.fonts_tags = []
self.other_tags = {} self.other_tags = {}
self.other_tags['bold'] = buffer.create_tag('bold') self.other_tags['bold'] = buffer.create_tag('bold')
self.other_tags['bold'].set_property('weight', pango.WEIGHT_BOLD) self.other_tags['bold'].set_property('weight', pango.WEIGHT_BOLD)
self.begin_tags['bold'] = '<strong>' self.begin_tags['bold'] = '<strong>'
@ -80,7 +80,7 @@ class MessageTextView(gtk.TextView):
start = 0 start = 0
end = 0 end = 0
index = 0 index = 0
new_text = '' new_text = ''
iterator = gajim.interface.link_pattern_re.finditer(text) iterator = gajim.interface.link_pattern_re.finditer(text)
for match in iterator: for match in iterator:
@ -94,7 +94,7 @@ class MessageTextView(gtk.TextView):
# we insert normal text # we insert normal text
new_text += text_before_special_text + \ new_text += text_before_special_text + \
'<a href="'+ url +'">' + url + '</a>' '<a href="'+ url +'">' + url + '</a>'
index = end # update index index = end # update index
if end < len(text): if end < len(text):
@ -128,7 +128,7 @@ class MessageTextView(gtk.TextView):
buffer.remove_tag_by_name('strike', start, finish) buffer.remove_tag_by_name('strike', start, finish)
elif tag == 'strike': elif tag == 'strike':
buffer.remove_tag_by_name('underline', start, finish) buffer.remove_tag_by_name('underline', start, finish)
buffer.apply_tag_by_name(tag, start, finish) buffer.apply_tag_by_name(tag, start, finish)
def clear_tags(self, widget): def clear_tags(self, widget):
buffer = self.get_buffer() buffer = self.get_buffer()
@ -190,7 +190,7 @@ class MessageTextView(gtk.TextView):
self.begin_tags[tag_name] = \ self.begin_tags[tag_name] = \
'<span style="font-family: ' + family + '; ' + \ '<span style="font-family: ' + family + '; ' + \
'font-size: ' + str(size) + 'px">' 'font-size: ' + str(size) + 'px">'
self.end_tags[tag_name] = '</span>' self.end_tags[tag_name] = '</span>'
self.fonts_tags.append(tag_name) self.fonts_tags.append(tag_name)
return_val = buffer.get_selection_bounds() return_val = buffer.get_selection_bounds()
@ -198,7 +198,7 @@ class MessageTextView(gtk.TextView):
start, finish = return_val[0], return_val[1] start, finish = return_val[0], return_val[1]
else: else:
start, finish = buffer.get_bounds() start, finish = buffer.get_bounds()
for tag in self.fonts_tags: for tag in self.fonts_tags:
buffer.remove_tag_by_name(tag, start, finish) buffer.remove_tag_by_name(tag, start, finish)
@ -247,14 +247,14 @@ class MessageTextView(gtk.TextView):
if tag_name not in self.begin_tags: if tag_name not in self.begin_tags:
continue continue
new_tags.append(tag_name) new_tags.append(tag_name)
for tag in iter.get_tags(): for tag in iter.get_tags():
tag_name = tag.get_property('name') tag_name = tag.get_property('name')
if tag_name not in self.begin_tags or tag_name not in self.end_tags: if tag_name not in self.begin_tags or tag_name not in self.end_tags:
continue continue
if tag_name not in new_tags: if tag_name not in new_tags:
old_tags.append(tag_name) old_tags.append(tag_name)
for tag in iter.get_toggled_tags(False): for tag in iter.get_toggled_tags(False):
tag_name = tag.get_property('name') tag_name = tag.get_property('name')
if tag_name not in self.end_tags: if tag_name not in self.end_tags:
@ -268,7 +268,7 @@ class MessageTextView(gtk.TextView):
for tag in new_tags: for tag in new_tags:
texte += self.begin_tags[tag] texte += self.begin_tags[tag]
for tag in old_tags: for tag in old_tags:
texte += self.begin_tags[tag] texte += self.begin_tags[tag]
texte += xhtml_special(buffer.get_text(old, buffer.get_end_iter())) texte += xhtml_special(buffer.get_text(old, buffer.get_end_iter()))
for tag in iter.get_toggled_tags(False): for tag in iter.get_toggled_tags(False):
@ -281,7 +281,7 @@ class MessageTextView(gtk.TextView):
return '<p>' + self.make_clickable_urls(texte) + '</p>' return '<p>' + self.make_clickable_urls(texte) + '</p>'
else: else:
return None return None
def destroy(self): def destroy(self):
import gc import gc
@ -308,41 +308,41 @@ gtk.binding_entry_add_signal(MessageTextView, gtk.keysyms.ISO_Left_Tab,
gtk.gdk.ModifierType, gtk.gdk.CONTROL_MASK) gtk.gdk.ModifierType, gtk.gdk.CONTROL_MASK)
# CTRL + TAB # CTRL + TAB
gtk.binding_entry_add_signal(MessageTextView, gtk.keysyms.Tab, gtk.binding_entry_add_signal(MessageTextView, gtk.keysyms.Tab,
gtk.gdk.CONTROL_MASK, 'mykeypress', int, gtk.keysyms.Tab, gtk.gdk.CONTROL_MASK, 'mykeypress', int, gtk.keysyms.Tab,
gtk.gdk.ModifierType, gtk.gdk.CONTROL_MASK) gtk.gdk.ModifierType, gtk.gdk.CONTROL_MASK)
# TAB # TAB
gtk.binding_entry_add_signal(MessageTextView, gtk.keysyms.Tab, gtk.binding_entry_add_signal(MessageTextView, gtk.keysyms.Tab,
0, 'mykeypress', int, gtk.keysyms.Tab, gtk.gdk.ModifierType, 0) 0, 'mykeypress', int, gtk.keysyms.Tab, gtk.gdk.ModifierType, 0)
# CTRL + UP # CTRL + UP
gtk.binding_entry_add_signal(MessageTextView, gtk.keysyms.Up, gtk.binding_entry_add_signal(MessageTextView, gtk.keysyms.Up,
gtk.gdk.CONTROL_MASK, 'mykeypress', int, gtk.keysyms.Up, gtk.gdk.CONTROL_MASK, 'mykeypress', int, gtk.keysyms.Up,
gtk.gdk.ModifierType, gtk.gdk.CONTROL_MASK) gtk.gdk.ModifierType, gtk.gdk.CONTROL_MASK)
# CTRL + DOWN # CTRL + DOWN
gtk.binding_entry_add_signal(MessageTextView, gtk.keysyms.Down, gtk.binding_entry_add_signal(MessageTextView, gtk.keysyms.Down,
gtk.gdk.CONTROL_MASK, 'mykeypress', int, gtk.keysyms.Down, gtk.gdk.CONTROL_MASK, 'mykeypress', int, gtk.keysyms.Down,
gtk.gdk.ModifierType, gtk.gdk.CONTROL_MASK) gtk.gdk.ModifierType, gtk.gdk.CONTROL_MASK)
# ENTER # ENTER
gtk.binding_entry_add_signal(MessageTextView, gtk.keysyms.Return, gtk.binding_entry_add_signal(MessageTextView, gtk.keysyms.Return,
0, 'mykeypress', int, gtk.keysyms.Return, 0, 'mykeypress', int, gtk.keysyms.Return,
gtk.gdk.ModifierType, 0) gtk.gdk.ModifierType, 0)
# Ctrl + Enter # Ctrl + Enter
gtk.binding_entry_add_signal(MessageTextView, gtk.keysyms.Return, gtk.binding_entry_add_signal(MessageTextView, gtk.keysyms.Return,
gtk.gdk.CONTROL_MASK, 'mykeypress', int, gtk.keysyms.Return, gtk.gdk.CONTROL_MASK, 'mykeypress', int, gtk.keysyms.Return,
gtk.gdk.ModifierType, gtk.gdk.CONTROL_MASK) gtk.gdk.ModifierType, gtk.gdk.CONTROL_MASK)
# Keypad Enter # Keypad Enter
gtk.binding_entry_add_signal(MessageTextView, gtk.keysyms.KP_Enter, gtk.binding_entry_add_signal(MessageTextView, gtk.keysyms.KP_Enter,
0, 'mykeypress', int, gtk.keysyms.KP_Enter, 0, 'mykeypress', int, gtk.keysyms.KP_Enter,
gtk.gdk.ModifierType, 0) gtk.gdk.ModifierType, 0)
# Ctrl + Keypad Enter # Ctrl + Keypad Enter
gtk.binding_entry_add_signal(MessageTextView, gtk.keysyms.KP_Enter, gtk.binding_entry_add_signal(MessageTextView, gtk.keysyms.KP_Enter,
gtk.gdk.CONTROL_MASK, 'mykeypress', int, gtk.keysyms.KP_Enter, gtk.gdk.CONTROL_MASK, 'mykeypress', int, gtk.keysyms.KP_Enter,
gtk.gdk.ModifierType, gtk.gdk.CONTROL_MASK) gtk.gdk.ModifierType, gtk.gdk.CONTROL_MASK)

View file

@ -85,7 +85,7 @@ class MessageWindow(object):
orig_window.destroy() orig_window.destroy()
del orig_window del orig_window
# NOTE: we use 'connect_after' here because in # NOTE: we use 'connect_after' here because in
# MessageWindowMgr._new_window we register handler that saves window # MessageWindowMgr._new_window we register handler that saves window
# state when closing it, and it should be called before # state when closing it, and it should be called before
# MessageWindow._on_window_delete, which manually destroys window # MessageWindow._on_window_delete, which manually destroys window
@ -695,7 +695,7 @@ class MessageWindow(object):
# If no composing contact found yet, check if this one is composing # If no composing contact found yet, check if this one is composing
first_composing_ind = ind first_composing_ind = ind
if ind == current: if ind == current:
break # a complete cycle without finding an unread tab break # a complete cycle without finding an unread tab
if found: if found:
self.notebook.set_current_page(ind) self.notebook.set_current_page(ind)
elif first_composing_ind != -1: elif first_composing_ind != -1:

View file

@ -48,11 +48,11 @@ class MusicTrackListener(gobject.GObject):
if cls._instance is None: if cls._instance is None:
cls._instance = cls() cls._instance = cls()
return cls._instance return cls._instance
def __init__(self): def __init__(self):
super(MusicTrackListener, self).__init__() super(MusicTrackListener, self).__init__()
self._last_playing_music = None self._last_playing_music = None
bus = dbus.SessionBus() bus = dbus.SessionBus()
## MPRIS ## MPRIS
@ -168,7 +168,7 @@ class MusicTrackListener(gobject.GObject):
'/org/bansheeproject/Banshee/PlayerEngine') '/org/bansheeproject/Banshee/PlayerEngine')
currentTrack = banshee.GetCurrentTrack() currentTrack = banshee.GetCurrentTrack()
self._last_playing_music = self._banshee_properties_extract( self._last_playing_music = self._banshee_properties_extract(
currentTrack) currentTrack)
self.emit('music-track-changed', self._last_playing_music) self.emit('music-track-changed', self._last_playing_music)
elif state == 'paused': elif state == 'paused':
self.emit('music-track-changed', None) self.emit('music-track-changed', None)

View file

@ -2,10 +2,10 @@
A Python module that enables posting notifications to the Growl daemon. A Python module that enables posting notifications to the Growl daemon.
See <http://growl.info/> for more information. See <http://growl.info/> for more information.
""" """
__version__ = "0.7" __version__ = "0.7"
__author__ = "Mark Rowe <bdash@users.sourceforge.net>" __author__ = "Mark Rowe <bdash@users.sourceforge.net>"
__copyright__ = "(C) 2003 Mark Rowe <bdash@users.sourceforge.net>. Released under the BSD license." __copyright__ = "(C) 2003 Mark Rowe <bdash@users.sourceforge.net>. Released under the BSD license."
__contributors__ = ["Ingmar J Stein (Growl Team)", __contributors__ = ["Ingmar J Stein (Growl Team)",
"Rui Carmo (http://the.taoofmac.com)", "Rui Carmo (http://the.taoofmac.com)",
"Jeremy Rossi <jeremy@jeremyrossi.com>" "Jeremy Rossi <jeremy@jeremyrossi.com>"
] ]
@ -35,7 +35,7 @@ GROWL_NOTIFICATION_DESCRIPTION="NotificationDescription"
GROWL_NOTIFICATION_ICON="NotificationIcon" GROWL_NOTIFICATION_ICON="NotificationIcon"
GROWL_NOTIFICATION_APP_ICON="NotificationAppIcon" GROWL_NOTIFICATION_APP_ICON="NotificationAppIcon"
GROWL_NOTIFICATION_PRIORITY="NotificationPriority" GROWL_NOTIFICATION_PRIORITY="NotificationPriority"
GROWL_NOTIFICATION_STICKY="NotificationSticky" GROWL_NOTIFICATION_STICKY="NotificationSticky"
GROWL_NOTIFICATION_CLICK_CONTEXT="NotificationClickContext" GROWL_NOTIFICATION_CLICK_CONTEXT="NotificationClickContext"
@ -51,7 +51,7 @@ GROWL_NOTIFICATION_CLICKED="GrowlClicked!"
GROWL_NOTIFICATION_TIMED_OUT="GrowlTimedOut!" GROWL_NOTIFICATION_TIMED_OUT="GrowlTimedOut!"
GROWL_KEY_CLICKED_CONTEXT="ClickedContext" GROWL_KEY_CLICKED_CONTEXT="ClickedContext"
growlPriority = {"Very Low":-2,"Moderate":-1,"Normal":0,"High":1,"Emergency":2} growlPriority = {"Very Low":-2,"Moderate":-1,"Normal":0,"High":1,"Emergency":2}
class netgrowl: class netgrowl:
@ -67,7 +67,7 @@ class netgrowl:
def send(self, data): def send(self, data):
self.socket.sendto(data, (self.hostname, GROWL_UDP_PORT)) self.socket.sendto(data, (self.hostname, GROWL_UDP_PORT))
def PostNotification(self, userInfo): def PostNotification(self, userInfo):
priority = userInfo.get(GROWL_NOTIFICATION_PRIORITY, 0) priority = userInfo.get(GROWL_NOTIFICATION_PRIORITY, 0)
if GROWL_NOTIFICATION_STICKY in userInfo: if GROWL_NOTIFICATION_STICKY in userInfo:
@ -113,9 +113,9 @@ class netgrowl:
title = title.encode("utf-8") title = title.encode("utf-8")
description = description.encode("utf-8") description = description.encode("utf-8")
flags = (priority & 0x07) * 2 flags = (priority & 0x07) * 2
if priority < 0: if priority < 0:
flags |= 0x08 flags |= 0x08
if sticky: if sticky:
flags = flags | 0x0001 flags = flags | 0x0001
data = struct.pack("!BBHHHHH", data = struct.pack("!BBHHHHH",
GROWL_PROTOCOL_VERSION, GROWL_PROTOCOL_VERSION,

View file

@ -8,7 +8,7 @@ setup(
url = 'http://www.gajim.org/', url = 'http://www.gajim.org/',
download_url = 'http://www.gajim.org/downloads.php', download_url = 'http://www.gajim.org/downloads.php',
license = 'GPL', license = 'GPL',
ext_modules=[ ext_modules=[
Extension('idle', ['idle.c'], Extension('idle', ['idle.c'],
extra_compile_args=['-Wall'], extra_compile_args=['-Wall'],

View file

@ -130,11 +130,11 @@ class ProfileWindow:
'avatar_scaled.png') 'avatar_scaled.png')
scaled_pixbuf.save(path_to_file, 'png') scaled_pixbuf.save(path_to_file, 'png')
must_delete = True must_delete = True
fd = open(path_to_file, 'rb') fd = open(path_to_file, 'rb')
data = fd.read() data = fd.read()
pixbuf = gtkgui_helpers.get_pixbuf_from_data(data) pixbuf = gtkgui_helpers.get_pixbuf_from_data(data)
try: try:
# rescale it # rescale it
pixbuf = gtkgui_helpers.get_scaled_pixbuf(pixbuf, 'vcard') pixbuf = gtkgui_helpers.get_scaled_pixbuf(pixbuf, 'vcard')
except AttributeError: # unknown format except AttributeError: # unknown format
@ -151,10 +151,10 @@ class ProfileWindow:
self.avatar_encoded = base64.encodestring(data) self.avatar_encoded = base64.encodestring(data)
# returns None if unknown type # returns None if unknown type
self.avatar_mime_type = mimetypes.guess_type(path_to_file)[0] self.avatar_mime_type = mimetypes.guess_type(path_to_file)[0]
if must_delete: if must_delete:
try: try:
os.remove(path_to_file) os.remove(path_to_file)
except OSError: except OSError:
gajim.log.debug('Cannot remove %s' % path_to_file) gajim.log.debug('Cannot remove %s' % path_to_file)
def on_clear(widget): def on_clear(widget):
@ -176,7 +176,7 @@ class ProfileWindow:
'''If right-clicked, show popup''' '''If right-clicked, show popup'''
if event.button == 3 and self.avatar_encoded: # right click if event.button == 3 and self.avatar_encoded: # right click
menu = gtk.Menu() menu = gtk.Menu()
# Try to get pixbuf # Try to get pixbuf
pixbuf = gtkgui_helpers.get_avatar_pixbuf_from_cache(self.jid, pixbuf = gtkgui_helpers.get_avatar_pixbuf_from_cache(self.jid,
use_local = False) use_local = False)
@ -192,7 +192,7 @@ class ProfileWindow:
menuitem = gtk.ImageMenuItem(gtk.STOCK_CLEAR) menuitem = gtk.ImageMenuItem(gtk.STOCK_CLEAR)
menuitem.connect('activate', self.on_clear_button_clicked) menuitem.connect('activate', self.on_clear_button_clicked)
menu.append(menuitem) menu.append(menuitem)
menu.connect('selection-done', lambda w:w.destroy()) menu.connect('selection-done', lambda w:w.destroy())
# show the menu # show the menu
menu.show_all() menu.show_all()
menu.popup(None, None, None, event.button, event.time) menu.popup(None, None, None, event.button, event.time)
@ -289,7 +289,7 @@ class ProfileWindow:
'ADR_WORK_STREET', 'ADR_WORK_EXTADR', 'ADR_WORK_LOCALITY', 'ADR_WORK_STREET', 'ADR_WORK_EXTADR', 'ADR_WORK_LOCALITY',
'ADR_WORK_REGION', 'ADR_WORK_PCODE', 'ADR_WORK_CTRY'] 'ADR_WORK_REGION', 'ADR_WORK_PCODE', 'ADR_WORK_CTRY']
vcard_ = {} vcard_ = {}
for e in entries: for e in entries:
txt = self.xml.get_widget(e + '_entry').get_text().decode('utf-8') txt = self.xml.get_widget(e + '_entry').get_text().decode('utf-8')
if txt != '': if txt != '':
vcard_ = self.add_to_vcard(vcard_, e, txt) vcard_ = self.add_to_vcard(vcard_, e, txt)

View file

@ -90,7 +90,7 @@ def get_dbus_struct(obj):
return DBUS_NONE() return DBUS_NONE()
return result return result
# unknown type # unknown type
return DBUS_NONE() return DBUS_NONE()
class Remote: class Remote:
def __init__(self): def __init__(self):
@ -265,7 +265,7 @@ class SignalObject(dbus.service.Object):
@dbus.service.method(INTERFACE, in_signature='sss', out_signature='b') @dbus.service.method(INTERFACE, in_signature='sss', out_signature='b')
def send_file(self, file_path, jid, account): def send_file(self, file_path, jid, account):
'''send file, located at 'file_path' to 'jid', using account '''send file, located at 'file_path' to 'jid', using account
(optional) 'account' ''' (optional) 'account' '''
jid = self._get_real_jid(jid, account) jid = self._get_real_jid(jid, account)
connected_account, contact = self._get_account_and_contact(account, jid) connected_account, contact = self._get_account_and_contact(account, jid)
@ -355,7 +355,7 @@ class SignalObject(dbus.service.Object):
break break
# we send the message to jid not in roster, because account is # we send the message to jid not in roster, because account is
# specified, or there is only one account # specified, or there is only one account
elif account: elif account:
connected_account = acct connected_account = acct
elif first_connected_acct is None: elif first_connected_acct is None:
first_connected_acct = acct first_connected_acct = acct
@ -378,7 +378,7 @@ class SignalObject(dbus.service.Object):
def change_status(self, status, message, account): def change_status(self, status, message, account):
''' change_status(status, message, account). account is optional - ''' change_status(status, message, account). account is optional -
if not specified status is changed for all accounts. ''' if not specified status is changed for all accounts. '''
if status not in ('offline', 'online', 'chat', if status not in ('offline', 'online', 'chat',
'away', 'xa', 'dnd', 'invisible'): 'away', 'xa', 'dnd', 'invisible'):
return DBUS_BOOLEAN(False) return DBUS_BOOLEAN(False)
if account: if account:
@ -546,7 +546,7 @@ class SignalObject(dbus.service.Object):
if account: if account:
if account in gajim.connections and \ if account in gajim.connections and \
gajim.connections[account].connected > 1: gajim.connections[account].connected > 1:
# if given account is active, use it # if given account is active, use it
AddNewContactWindow(account = account, jid = jid) AddNewContactWindow(account = account, jid = jid)
else: else:
# wrong account # wrong account

View file

@ -358,7 +358,7 @@ class RosterWindow:
contact.groups = big_brother_contact.get_shown_groups()[:] contact.groups = big_brother_contact.get_shown_groups()[:]
for child_iter in parent_iters: for child_iter in parent_iters:
it = self.model.append(child_iter, (None, contact.get_shown_name(), it = self.model.append(child_iter, (None, contact.get_shown_name(),
'contact', contact.jid, account, None, None, None, None, None)) 'contact', contact.jid, account, None, None, None, None, None))
added_iters.append(it) added_iters.append(it)
else: else:
@ -366,13 +366,13 @@ class RosterWindow:
if not groups: if not groups:
groups = contact.get_shown_groups() groups = contact.get_shown_groups()
for group in groups: for group in groups:
child_iterG = self._get_group_iter(group, account, child_iterG = self._get_group_iter(group, account,
model = self.model) model = self.model)
if not child_iterG: if not child_iterG:
# Group is not yet in roster, add it! # Group is not yet in roster, add it!
child_iterA = self._get_account_iter(account, self.model) child_iterA = self._get_account_iter(account, self.model)
child_iterG = self.model.append(child_iterA, child_iterG = self.model.append(child_iterA,
[gajim.interface.jabber_state_images['16']['closed'], [gajim.interface.jabber_state_images['16']['closed'],
gobject.markup_escape_text(group), gobject.markup_escape_text(group),
'group', group, account, None, None, None, None, None]) 'group', group, account, None, None, None, None, None])
self.draw_group(group, account) self.draw_group(group, account)
@ -425,7 +425,7 @@ class RosterWindow:
if groups: if groups:
# Only remove from specified groups # Only remove from specified groups
all_iters = iters[:] all_iters = iters[:]
group_iters = [self._get_group_iter(group, account) group_iters = [self._get_group_iter(group, account)
for group in groups] for group in groups]
iters = [titer for titer in all_iters iters = [titer for titer in all_iters
if self.model.iter_parent(titer) in group_iters] if self.model.iter_parent(titer) in group_iters]
@ -546,7 +546,7 @@ class RosterWindow:
if not family_in_roster: if not family_in_roster:
return False return False
assert old_big_jid, 'No Big Brother in nearby family % (Family: %)' % \ assert old_big_jid, 'No Big Brother in nearby family % (Family: %)' % \
(nearby_family, family) (nearby_family, family)
iters = self._get_contact_iter(old_big_jid, old_big_account, iters = self._get_contact_iter(old_big_jid, old_big_account,
@ -585,7 +585,7 @@ class RosterWindow:
self._remove_metacontact_family(family, account) self._remove_metacontact_family(family, account)
brothers = self._add_metacontact_family(family, account) brothers = self._add_metacontact_family(family, account)
for c, acc in brothers: for c, acc in brothers:
self.draw_completely(c.jid, acc) self.draw_completely(c.jid, acc)
@ -874,7 +874,7 @@ class RosterWindow:
gajim.connections[account].update_contact(jid, contact.name, gajim.connections[account].update_contact(jid, contact.name,
contact.groups) contact.groups)
self.add_contact(jid, account) self.add_contact(jid, account)
# Also redraw old groups # Also redraw old groups
for group in groups: for group in groups:
self.draw_group(group, account) self.draw_group(group, account)
@ -1145,7 +1145,7 @@ class RosterWindow:
bb_jid, bb_account = \ bb_jid, bb_account = \
self._get_nearby_family_and_big_brother(family, account)[1:] self._get_nearby_family_and_big_brother(family, account)[1:]
is_big_brother = (jid, account) == (bb_jid, bb_account) is_big_brother = (jid, account) == (bb_jid, bb_account)
iters = self._get_contact_iter(jid, account) iters = self._get_contact_iter(jid, account)
have_visible_children = iters \ have_visible_children = iters \
and self.modelfilter.iter_has_child(iters[0]) and self.modelfilter.iter_has_child(iters[0])
@ -1174,7 +1174,7 @@ class RosterWindow:
state_images = self.get_appropriate_state_images( state_images = self.get_appropriate_state_images(
jid, size = 'closed', jid, size = 'closed',
icon_name = icon_name) icon_name = icon_name)
# Expand/collapse icon might differ per iter # Expand/collapse icon might differ per iter
# (group) # (group)
img = state_images[icon_name] img = state_images[icon_name]
@ -1285,7 +1285,7 @@ class RosterWindow:
for child_iter in iters: for child_iter in iters:
self.model[child_iter][C_AVATAR_PIXBUF] = scaled_pixbuf self.model[child_iter][C_AVATAR_PIXBUF] = scaled_pixbuf
return False return False
def draw_completely(self, jid, account): def draw_completely(self, jid, account):
self.draw_contact(jid, account) self.draw_contact(jid, account)
self.draw_mood(jid, account) self.draw_mood(jid, account)
@ -4684,7 +4684,7 @@ class RosterWindow:
for account in gajim.connections: for account in gajim.connections:
if gajim.account_is_connected(account) and \ if gajim.account_is_connected(account) and \
gajim.connections[account].is_zeroconf: gajim.connections[account].is_zeroconf:
for item in (join_gc_menuitem, add_new_contact_menuitem, for item in (join_gc_menuitem, add_new_contact_menuitem,
service_disco_menuitem, single_message_menuitem): service_disco_menuitem, single_message_menuitem):
item.set_sensitive(False) item.set_sensitive(False)

View file

@ -58,7 +58,7 @@ class SearchWindow:
def request_form(self): def request_form(self):
gajim.connections[self.account].request_search_fields(self.jid) gajim.connections[self.account].request_search_fields(self.jid)
def pulse_callback(self): def pulse_callback(self):
self.progressbar.pulse() self.progressbar.pulse()
return True return True
@ -101,7 +101,7 @@ class SearchWindow:
return return
jid = model[iter_][self.jid_column] jid = model[iter_][self.jid_column]
dialogs.AddNewContactWindow(self.account, jid) dialogs.AddNewContactWindow(self.account, jid)
def on_information_button_clicked(self, widget): def on_information_button_clicked(self, widget):
(model, iter_) = self.result_treeview.get_selection().get_selected() (model, iter_) = self.result_treeview.get_selection().get_selected()
if not iter_: if not iter_:

View file

@ -54,7 +54,7 @@ class Secrets:
except KeyError: except KeyError:
return [] return []
# retained secrets are stored as a tuple of the secret and whether the user # retained secrets are stored as a tuple of the secret and whether the user
# has verified it # has verified it
def save_new_srs(self, account, jid, secret, verified): def save_new_srs(self, account, jid, secret, verified):
if not account in self.srs: if not account in self.srs:

View file

@ -44,7 +44,7 @@ class StatusIcon(systray.Systray):
def __init__(self): def __init__(self):
systray.Systray.__init__(self) systray.Systray.__init__(self)
self.status_icon = None self.status_icon = None
def show_icon(self): def show_icon(self):
if not self.status_icon: if not self.status_icon:
self.status_icon = gtk.StatusIcon() self.status_icon = gtk.StatusIcon()
@ -86,7 +86,7 @@ class StatusIcon(systray.Systray):
else: else:
state = self.status state = self.status
self.status_icon.set_blinking(False) self.status_icon.set_blinking(False)
#FIXME: do not always use 16x16 (ask actually used size and use that) #FIXME: do not always use 16x16 (ask actually used size and use that)
image = gajim.interface.jabber_state_images['16'][state] image = gajim.interface.jabber_state_images['16'][state]
if image.get_storage_type() == gtk.IMAGE_PIXBUF: if image.get_storage_type() == gtk.IMAGE_PIXBUF:

View file

@ -61,7 +61,7 @@ class Systray:
self.new_chat_handler_id = None self.new_chat_handler_id = None
self.t = None self.t = None
# click somewhere else does not popdown menu. workaround this. # click somewhere else does not popdown menu. workaround this.
self.added_hide_menuitem = False self.added_hide_menuitem = False
self.img_tray = gtk.Image() self.img_tray = gtk.Image()
self.status = 'offline' self.status = 'offline'
self.double_click = False self.double_click = False
@ -107,7 +107,7 @@ class Systray:
def change_status(self, global_status): def change_status(self, global_status):
''' set tray image to 'global_status' ''' ''' set tray image to 'global_status' '''
# change image and status, only if it is different # change image and status, only if it is different
if global_status is not None and self.status != global_status: if global_status is not None and self.status != global_status:
self.status = global_status self.status = global_status
self.set_img() self.set_img()
@ -226,7 +226,7 @@ class Systray:
self.on_single_message_menuitem_activate, account) self.on_single_message_menuitem_activate, account)
account_menu_for_single_message.append(item) account_menu_for_single_message.append(item)
# join gc # join gc
gc_item = gtk.MenuItem(_('using account %s') % account, False) gc_item = gtk.MenuItem(_('using account %s') % account, False)
gc_sub_menu.append(gc_item) gc_sub_menu.append(gc_item)
gc_menuitem_menu = gtk.Menu() gc_menuitem_menu = gtk.Menu()
@ -283,7 +283,7 @@ class Systray:
gajim.interface.handle_event(account, jid, event.type_) gajim.interface.handle_event(account, jid, event.type_)
def on_sounds_mute_menuitem_activate(self, widget): def on_sounds_mute_menuitem_activate(self, widget):
gajim.config.set('sounds_on', not widget.get_active()) gajim.config.set('sounds_on', not widget.get_active())
gajim.interface.save_config() gajim.interface.save_config()
def on_show_roster_menuitem_activate(self, widget): def on_show_roster_menuitem_activate(self, widget):
@ -296,7 +296,7 @@ class Systray:
else: else:
gajim.interface.instances['preferences'] = config.PreferencesWindow() gajim.interface.instances['preferences'] = config.PreferencesWindow()
def on_quit_menuitem_activate(self, widget): def on_quit_menuitem_activate(self, widget):
gajim.interface.roster.on_quit_request() gajim.interface.roster.on_quit_request()
def on_left_click(self): def on_left_click(self):

View file

@ -44,17 +44,17 @@ class BaseTooltip:
''' Base Tooltip class; ''' Base Tooltip class;
Usage: Usage:
tooltip = BaseTooltip() tooltip = BaseTooltip()
.... ....
tooltip.show_tooltip(data, widget_height, widget_y_position) tooltip.show_tooltip(data, widget_height, widget_y_position)
.... ....
if tooltip.timeout != 0: if tooltip.timeout != 0:
tooltip.hide_tooltip() tooltip.hide_tooltip()
* data - the text to be displayed (extenders override this argument and * data - the text to be displayed (extenders override this argument and
display more complex contents) display more complex contents)
* widget_height - the height of the widget on which we want to show tooltip * widget_height - the height of the widget on which we want to show tooltip
* widget_y_position - the vertical position of the widget on the screen * widget_y_position - the vertical position of the widget on the screen
Tooltip is displayed aligned centered to the mouse poiner and 4px below the widget. Tooltip is displayed aligned centered to the mouse poiner and 4px below the widget.
In case tooltip goes below the visible area it is shown above the widget. In case tooltip goes below the visible area it is shown above the widget.
''' '''
@ -63,14 +63,14 @@ class BaseTooltip:
self.preferred_position = [0, 0] self.preferred_position = [0, 0]
self.win = None self.win = None
self.id = None self.id = None
def populate(self, data): def populate(self, data):
''' this method must be overriden by all extenders ''' this method must be overriden by all extenders
This is the most simple implementation: show data as value of a label This is the most simple implementation: show data as value of a label
''' '''
self.create_window() self.create_window()
self.win.add(gtk.Label(data)) self.win.add(gtk.Label(data))
def create_window(self): def create_window(self):
''' create a popup window each time tooltip is requested ''' ''' create a popup window each time tooltip is requested '''
self.win = gtk.Window(gtk.WINDOW_POPUP) self.win = gtk.Window(gtk.WINDOW_POPUP)
@ -79,15 +79,15 @@ class BaseTooltip:
self.win.set_name('gtk-tooltips') self.win.set_name('gtk-tooltips')
if gtk.gtk_version >= (2, 10, 0) and gtk.pygtk_version >= (2, 10, 0): if gtk.gtk_version >= (2, 10, 0) and gtk.pygtk_version >= (2, 10, 0):
self.win.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_TOOLTIP) self.win.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_TOOLTIP)
self.win.set_events(gtk.gdk.POINTER_MOTION_MASK) self.win.set_events(gtk.gdk.POINTER_MOTION_MASK)
self.win.connect_after('expose_event', self.expose) self.win.connect_after('expose_event', self.expose)
self.win.connect('size-request', self.on_size_request) self.win.connect('size-request', self.on_size_request)
self.win.connect('motion-notify-event', self.motion_notify_event) self.win.connect('motion-notify-event', self.motion_notify_event)
self.screen = self.win.get_screen() self.screen = self.win.get_screen()
def _get_icon_name_for_tooltip(self, contact): def _get_icon_name_for_tooltip(self, contact):
''' helper function used for tooltip contacts/acounts ''' helper function used for tooltip contacts/acounts
Tooltip on account has fake contact with sub == '', in this case we show Tooltip on account has fake contact with sub == '', in this case we show
real status of the account real status of the account
''' '''
@ -102,14 +102,14 @@ class BaseTooltip:
def on_size_request(self, widget, requisition): def on_size_request(self, widget, requisition):
half_width = requisition.width / 2 + 1 half_width = requisition.width / 2 + 1
if self.preferred_position[0] < half_width: if self.preferred_position[0] < half_width:
self.preferred_position[0] = 0 self.preferred_position[0] = 0
elif self.preferred_position[0] + requisition.width > \ elif self.preferred_position[0] + requisition.width > \
self.screen.get_width() + half_width: self.screen.get_width() + half_width:
self.preferred_position[0] = self.screen.get_width() - \ self.preferred_position[0] = self.screen.get_width() - \
requisition.width requisition.width
else: else:
self.preferred_position[0] -= half_width self.preferred_position[0] -= half_width
self.screen.get_height() self.screen.get_height()
if self.preferred_position[1] + requisition.height > \ if self.preferred_position[1] + requisition.height > \
self.screen.get_height(): self.screen.get_height():
@ -132,23 +132,23 @@ class BaseTooltip:
style.paint_flat_box(self.win.window, gtk.STATE_NORMAL, gtk.SHADOW_OUT, style.paint_flat_box(self.win.window, gtk.STATE_NORMAL, gtk.SHADOW_OUT,
None, self.win, 'tooltip', size[0] - 1, 0, 1, -1) None, self.win, 'tooltip', size[0] - 1, 0, 1, -1)
return True return True
def show_tooltip(self, data, widget_height, widget_y_position): def show_tooltip(self, data, widget_height, widget_y_position):
''' show tooltip on widget. ''' show tooltip on widget.
data contains needed data for tooltip contents data contains needed data for tooltip contents
widget_height is the height of the widget on which we show the tooltip widget_height is the height of the widget on which we show the tooltip
widget_y_position is vertical position of the widget on the screen widget_y_position is vertical position of the widget on the screen
''' '''
# set tooltip contents # set tooltip contents
self.populate(data) self.populate(data)
# get the X position of mouse pointer on the screen # get the X position of mouse pointer on the screen
pointer_x = self.screen.get_display().get_pointer()[1] pointer_x = self.screen.get_display().get_pointer()[1]
# get the prefered X position of the tooltip on the screen in case this position is > # get the prefered X position of the tooltip on the screen in case this position is >
# than the height of the screen, tooltip will be shown above the widget # than the height of the screen, tooltip will be shown above the widget
preferred_y = widget_y_position + widget_height + 4 preferred_y = widget_y_position + widget_height + 4
self.preferred_position = [pointer_x, preferred_y] self.preferred_position = [pointer_x, preferred_y]
self.widget_height = widget_height self.widget_height = widget_height
self.win.ensure_style() self.win.ensure_style()
@ -164,18 +164,18 @@ class BaseTooltip:
self.id = None self.id = None
class StatusTable: class StatusTable:
''' Contains methods for creating status table. This ''' Contains methods for creating status table. This
is used in Roster and NotificationArea tooltips ''' is used in Roster and NotificationArea tooltips '''
def __init__(self): def __init__(self):
self.current_row = 1 self.current_row = 1
self.table = None self.table = None
self.text_label = None self.text_label = None
self.spacer_label = ' ' self.spacer_label = ' '
def create_table(self): def create_table(self):
self.table = gtk.Table(4, 1) self.table = gtk.Table(4, 1)
self.table.set_property('column-spacing', 2) self.table.set_property('column-spacing', 2)
def add_text_row(self, text, col_inc = 0): def add_text_row(self, text, col_inc = 0):
self.current_row += 1 self.current_row += 1
self.text_label = gtk.Label() self.text_label = gtk.Label()
@ -185,7 +185,7 @@ class StatusTable:
self.text_label.set_markup(text) self.text_label.set_markup(text)
self.table.attach(self.text_label, 1 + col_inc, 4, self.current_row, self.table.attach(self.text_label, 1 + col_inc, 4, self.current_row,
self.current_row + 1) self.current_row + 1)
def get_status_info(self, resource, priority, show, status): def get_status_info(self, resource, priority, show, status):
str_status = resource + ' (' + unicode(priority) + ')' str_status = resource + ' (' + unicode(priority) + ')'
if status: if status:
@ -200,7 +200,7 @@ class StatusTable:
status = gobject.markup_escape_text(status) status = gobject.markup_escape_text(status)
str_status += ' - <i>' + status + '</i>' str_status += ' - <i>' + status + '</i>'
return str_status return str_status
def add_status_row(self, file_path, show, str_status, status_time=None, def add_status_row(self, file_path, show, str_status, status_time=None,
show_lock=False, indent=True): show_lock=False, indent=True):
''' appends a new row with status icon to the table ''' ''' appends a new row with status icon to the table '''
@ -218,9 +218,9 @@ class StatusTable:
spacer = gtk.Label(self.spacer_label) spacer = gtk.Label(self.spacer_label)
image.set_alignment(1, 0.5) image.set_alignment(1, 0.5)
if indent: if indent:
self.table.attach(spacer, 1, 2, self.current_row, self.table.attach(spacer, 1, 2, self.current_row,
self.current_row + 1, 0, 0, 0, 0) self.current_row + 1, 0, 0, 0, 0)
self.table.attach(image, 2, 3, self.current_row, self.table.attach(image, 2, 3, self.current_row,
self.current_row + 1, gtk.FILL, gtk.FILL, 2, 0) self.current_row + 1, gtk.FILL, gtk.FILL, 2, 0)
status_label = gtk.Label() status_label = gtk.Label()
status_label.set_markup(str_status) status_label.set_markup(str_status)
@ -230,11 +230,11 @@ class StatusTable:
self.current_row + 1, gtk.FILL | gtk.EXPAND, 0, 0, 0) self.current_row + 1, gtk.FILL | gtk.EXPAND, 0, 0, 0)
if show_lock: if show_lock:
lock_image = gtk.Image() lock_image = gtk.Image()
lock_image.set_from_stock(gtk.STOCK_DIALOG_AUTHENTICATION, lock_image.set_from_stock(gtk.STOCK_DIALOG_AUTHENTICATION,
gtk.ICON_SIZE_MENU) gtk.ICON_SIZE_MENU)
self.table.attach(lock_image, 4, 5, self.current_row, self.table.attach(lock_image, 4, 5, self.current_row,
self.current_row + 1, 0, 0, 0, 0) self.current_row + 1, 0, 0, 0, 0)
class NotificationAreaTooltip(BaseTooltip, StatusTable): class NotificationAreaTooltip(BaseTooltip, StatusTable):
''' Tooltip that is shown in the notification area ''' ''' Tooltip that is shown in the notification area '''
def __init__(self): def __init__(self):
@ -248,7 +248,7 @@ class NotificationAreaTooltip(BaseTooltip, StatusTable):
file_path = os.path.join(helpers.get_iconset_path(iconset), '16x16') file_path = os.path.join(helpers.get_iconset_path(iconset), '16x16')
for acct in accounts: for acct in accounts:
message = acct['message'] message = acct['message']
# before reducing the chars we should assure we send unicode, else # before reducing the chars we should assure we send unicode, else
# there are possible pango TBs on 'set_markup' # there are possible pango TBs on 'set_markup'
if isinstance(message, str): if isinstance(message, str):
message = unicode(message, encoding = 'utf-8') message = unicode(message, encoding = 'utf-8')
@ -260,12 +260,12 @@ class NotificationAreaTooltip(BaseTooltip, StatusTable):
else: else:
show_lock = False show_lock = False
if message: if message:
self.add_status_row(file_path, acct['show'], self.add_status_row(file_path, acct['show'],
gobject.markup_escape_text(acct['name']) + \ gobject.markup_escape_text(acct['name']) + \
' - ' + message, show_lock=show_lock, indent=False) ' - ' + message, show_lock=show_lock, indent=False)
else: else:
self.add_status_row(file_path, acct['show'], self.add_status_row(file_path, acct['show'],
gobject.markup_escape_text(acct['name']) gobject.markup_escape_text(acct['name'])
, show_lock=show_lock, indent=False) , show_lock=show_lock, indent=False)
for line in acct['event_lines']: for line in acct['event_lines']:
self.add_text_row(' ' + line, 1) self.add_text_row(' ' + line, 1)
@ -294,7 +294,7 @@ class GCTooltip(BaseTooltip):
self.avatar_image = gtk.Image() self.avatar_image = gtk.Image()
BaseTooltip.__init__(self) BaseTooltip.__init__(self)
def populate(self, contact): def populate(self, contact):
if not contact: if not contact:
return return
@ -307,10 +307,10 @@ class GCTooltip(BaseTooltip):
nick_markup = '<b>' + \ nick_markup = '<b>' + \
gobject.markup_escape_text(contact.get_shown_name()) \ gobject.markup_escape_text(contact.get_shown_name()) \
+ '</b>' + '</b>'
properties.append((nick_markup, None)) properties.append((nick_markup, None))
if contact.status: # status message if contact.status: # status message
status = contact.status.strip() status = contact.status.strip()
if status != '': if status != '':
# escape markup entities # escape markup entities
@ -327,7 +327,7 @@ class GCTooltip(BaseTooltip):
properties.append((_('Jabber ID: '), contact.jid)) properties.append((_('Jabber ID: '), contact.jid))
if hasattr(contact, 'resource') and contact.resource.strip() != '': if hasattr(contact, 'resource') and contact.resource.strip() != '':
properties.append((_('Resource: '), properties.append((_('Resource: '),
gobject.markup_escape_text(contact.resource) )) gobject.markup_escape_text(contact.resource) ))
if contact.affiliation != 'none': if contact.affiliation != 'none':
uf_affiliation = helpers.get_uf_affiliation(contact.affiliation) uf_affiliation = helpers.get_uf_affiliation(contact.affiliation)
@ -335,7 +335,7 @@ class GCTooltip(BaseTooltip):
_('%(owner_or_admin_or_member)s of this group chat') %\ _('%(owner_or_admin_or_member)s of this group chat') %\
{'owner_or_admin_or_member': uf_affiliation} {'owner_or_admin_or_member': uf_affiliation}
properties.append((affiliation_str, None)) properties.append((affiliation_str, None))
# Add avatar # Add avatar
puny_name = helpers.sanitize_filename(contact.name) puny_name = helpers.sanitize_filename(contact.name)
puny_room = helpers.sanitize_filename(contact.room_jid) puny_room = helpers.sanitize_filename(contact.room_jid)
@ -372,9 +372,9 @@ class GCTooltip(BaseTooltip):
label.set_line_wrap(True) label.set_line_wrap(True)
vcard_table.attach(label, 1, 3, vcard_current_row, vcard_table.attach(label, 1, 3, vcard_current_row,
vcard_current_row + 1, gtk.FILL, vertical_fill, 0) vcard_current_row + 1, gtk.FILL, vertical_fill, 0)
self.avatar_image.set_alignment(0, 0) self.avatar_image.set_alignment(0, 0)
vcard_table.attach(self.avatar_image, 3, 4, 2, vcard_current_row + 1, vcard_table.attach(self.avatar_image, 3, 4, 2, vcard_current_row + 1,
gtk.FILL, gtk.FILL | gtk.EXPAND, 3, 3) gtk.FILL, gtk.FILL | gtk.EXPAND, 3, 3)
self.win.add(vcard_table) self.win.add(vcard_table)
@ -385,7 +385,7 @@ class RosterTooltip(NotificationAreaTooltip):
self.image = gtk.Image() self.image = gtk.Image()
self.image.set_alignment(0, 0) self.image.set_alignment(0, 0)
# padding is independent of the total length and better than alignment # padding is independent of the total length and better than alignment
self.image.set_padding(1, 2) self.image.set_padding(1, 2)
self.avatar_image = gtk.Image() self.avatar_image = gtk.Image()
NotificationAreaTooltip.__init__(self) NotificationAreaTooltip.__init__(self)
@ -401,11 +401,11 @@ class RosterTooltip(NotificationAreaTooltip):
self.fill_table_with_accounts(accounts) self.fill_table_with_accounts(accounts)
self.win.add(self.table) self.win.add(self.table)
return return
# primary contact # primary contact
prim_contact = gajim.contacts.get_highest_prio_contact_from_contacts( prim_contact = gajim.contacts.get_highest_prio_contact_from_contacts(
contacts) contacts)
puny_jid = helpers.sanitize_filename(prim_contact.jid) puny_jid = helpers.sanitize_filename(prim_contact.jid)
table_size = 3 table_size = 3
@ -466,7 +466,7 @@ class RosterTooltip(NotificationAreaTooltip):
for acontact in contacts_dict[priority]: for acontact in contacts_dict[priority]:
status_line = self.get_status_info(acontact.resource, status_line = self.get_status_info(acontact.resource,
acontact.priority, acontact.show, acontact.status) acontact.priority, acontact.show, acontact.status)
icon_name = self._get_icon_name_for_tooltip(acontact) icon_name = self._get_icon_name_for_tooltip(acontact)
self.add_status_row(file_path, icon_name, status_line, self.add_status_row(file_path, icon_name, status_line,
acontact.last_status_time) acontact.last_status_time)
@ -474,14 +474,14 @@ class RosterTooltip(NotificationAreaTooltip):
else: # only one resource else: # only one resource
if contact.show: if contact.show:
show = helpers.get_uf_show(contact.show) show = helpers.get_uf_show(contact.show)
if contact.last_status_time: if contact.last_status_time:
vcard_current_row += 1 vcard_current_row += 1
if contact.show == 'offline': if contact.show == 'offline':
text = ' - ' + _('Last status: %s') text = ' - ' + _('Last status: %s')
else: else:
text = _(' since %s') text = _(' since %s')
if time.strftime('%j', time.localtime())== \ if time.strftime('%j', time.localtime())== \
time.strftime('%j', contact.last_status_time): time.strftime('%j', contact.last_status_time):
# it's today, show only the locale hour representation # it's today, show only the locale hour representation
@ -493,7 +493,7 @@ class RosterTooltip(NotificationAreaTooltip):
contact.last_status_time) contact.last_status_time)
local_time = local_time.decode( local_time = local_time.decode(
locale.getpreferredencoding()) locale.getpreferredencoding())
text = text % local_time text = text % local_time
show += text show += text
if self.account and \ if self.account and \
prim_contact.jid in gajim.gc_connected[self.account]: prim_contact.jid in gajim.gc_connected[self.account]:
@ -503,7 +503,7 @@ class RosterTooltip(NotificationAreaTooltip):
show = _('Disconnected') show = _('Disconnected')
show = '<i>' + show + '</i>' show = '<i>' + show + '</i>'
# we append show below # we append show below
if contact.status: if contact.status:
status = contact.status.strip() status = contact.status.strip()
if status: if status:
@ -511,13 +511,13 @@ class RosterTooltip(NotificationAreaTooltip):
# (no more than 300 chars on line and no more than 5 lines) # (no more than 300 chars on line and no more than 5 lines)
# status is wrapped # status is wrapped
status = helpers.reduce_chars_newlines(status, 300, 5) status = helpers.reduce_chars_newlines(status, 300, 5)
# escape markup entities. # escape markup entities.
status = gobject.markup_escape_text(status) status = gobject.markup_escape_text(status)
properties.append(('<i>%s</i>' % status, None)) properties.append(('<i>%s</i>' % status, None))
properties.append((show, None)) properties.append((show, None))
self._append_pep_info(contact, properties) self._append_pep_info(contact, properties)
properties.append((_('Jabber ID: '), prim_contact.jid )) properties.append((_('Jabber ID: '), prim_contact.jid ))
# contact has only one ressource # contact has only one ressource
@ -525,13 +525,13 @@ class RosterTooltip(NotificationAreaTooltip):
properties.append((_('Resource: '), properties.append((_('Resource: '),
gobject.markup_escape_text(contact.resource) +\ gobject.markup_escape_text(contact.resource) +\
' (' + unicode(contact.priority) + ')')) ' (' + unicode(contact.priority) + ')'))
if self.account and prim_contact.sub and prim_contact.sub != 'both' and\ if self.account and prim_contact.sub and prim_contact.sub != 'both' and\
prim_contact.jid not in gajim.gc_connected[self.account]: prim_contact.jid not in gajim.gc_connected[self.account]:
# ('both' is the normal sub so we don't show it) # ('both' is the normal sub so we don't show it)
properties.append(( _('Subscription: '), properties.append(( _('Subscription: '),
gobject.markup_escape_text(helpers.get_uf_sub(prim_contact.sub)))) gobject.markup_escape_text(helpers.get_uf_sub(prim_contact.sub))))
if prim_contact.keyID: if prim_contact.keyID:
keyID = None keyID = None
if len(prim_contact.keyID) == 8: if len(prim_contact.keyID) == 8:
@ -541,7 +541,7 @@ class RosterTooltip(NotificationAreaTooltip):
if keyID: if keyID:
properties.append((_('OpenPGP: '), properties.append((_('OpenPGP: '),
gobject.markup_escape_text(keyID))) gobject.markup_escape_text(keyID)))
while properties: while properties:
property_ = properties.pop(0) property_ = properties.pop(0)
vcard_current_row += 1 vcard_current_row += 1
@ -563,7 +563,7 @@ class RosterTooltip(NotificationAreaTooltip):
vertical_fill, 0, 0) vertical_fill, 0, 0)
else: else:
if isinstance(property_[0], (unicode, str)): #FIXME: rm unicode? if isinstance(property_[0], (unicode, str)): #FIXME: rm unicode?
label.set_markup(property_[0]) label.set_markup(property_[0])
label.set_line_wrap(True) label.set_line_wrap(True)
else: else:
label = property_[0] label = property_[0]
@ -640,7 +640,7 @@ class RosterTooltip(NotificationAreaTooltip):
'from <i>%(source)s</i>') % {'title': title, 'from <i>%(source)s</i>') % {'title': title,
'artist': artist, 'source': source} 'artist': artist, 'source': source}
properties.append((tune_string, None)) properties.append((tune_string, None))
class FileTransfersTooltip(BaseTooltip): class FileTransfersTooltip(BaseTooltip):
''' Tooltip that is shown in the notification area ''' ''' Tooltip that is shown in the notification area '''
@ -658,13 +658,13 @@ class FileTransfersTooltip(BaseTooltip):
file_name = os.path.split(file_props['file-name'])[1] file_name = os.path.split(file_props['file-name'])[1]
else: else:
file_name = file_props['name'] file_name = file_props['name']
properties.append((_('Name: '), properties.append((_('Name: '),
gobject.markup_escape_text(file_name))) gobject.markup_escape_text(file_name)))
if file_props['type'] == 'r': if file_props['type'] == 'r':
type_ = _('Download') type_ = _('Download')
actor = _('Sender: ') actor = _('Sender: ')
sender = unicode(file_props['sender']).split('/')[0] sender = unicode(file_props['sender']).split('/')[0]
name = gajim.contacts.get_first_contact_from_jid( name = gajim.contacts.get_first_contact_from_jid(
file_props['tt_account'], sender).get_shown_name() file_props['tt_account'], sender).get_shown_name()
else: else:
type_ = _('Upload') type_ = _('Upload')
@ -676,10 +676,10 @@ class FileTransfersTooltip(BaseTooltip):
name = receiver.split('/')[0] name = receiver.split('/')[0]
properties.append((_('Type: '), type_)) properties.append((_('Type: '), type_))
properties.append((actor, gobject.markup_escape_text(name))) properties.append((actor, gobject.markup_escape_text(name)))
transfered_len = file_props.get('received-len', 0) transfered_len = file_props.get('received-len', 0)
properties.append((_('Transferred: '), helpers.convert_bytes(transfered_len))) properties.append((_('Transferred: '), helpers.convert_bytes(transfered_len)))
status = '' status = ''
if 'started' not in file_props or not file_props['started']: if 'started' not in file_props or not file_props['started']:
status = _('Not started') status = _('Not started')
elif 'connected' in file_props: elif 'connected' in file_props:
@ -714,15 +714,15 @@ class FileTransfersTooltip(BaseTooltip):
label = gtk.Label() label = gtk.Label()
label.set_alignment(0, 0) label.set_alignment(0, 0)
label.set_markup(property_[0]) label.set_markup(property_[0])
ft_table.attach(label, 1, 2, current_row, current_row + 1, ft_table.attach(label, 1, 2, current_row, current_row + 1,
gtk.FILL, gtk.FILL, 0, 0) gtk.FILL, gtk.FILL, 0, 0)
label = gtk.Label() label = gtk.Label()
label.set_alignment(0, 0) label.set_alignment(0, 0)
label.set_line_wrap(True) label.set_line_wrap(True)
label.set_markup(property_[1]) label.set_markup(property_[1])
ft_table.attach(label, 2, 3, current_row, current_row + 1, ft_table.attach(label, 2, 3, current_row, current_row + 1,
gtk.EXPAND | gtk.FILL, gtk.FILL, 0, 0) gtk.EXPAND | gtk.FILL, gtk.FILL, 0, 0)
self.win.add(ft_table) self.win.add(ft_table)

View file

@ -155,7 +155,7 @@ class VcardWindow:
self.contact.jid, self.account, self.contact.get_shown_name() + self.contact.jid, self.account, self.contact.get_shown_name() +
'.jpeg') '.jpeg')
menu.append(menuitem) menu.append(menuitem)
menu.connect('selection-done', lambda w:w.destroy()) menu.connect('selection-done', lambda w:w.destroy())
# show the menu # show the menu
menu.show_all() menu.show_all()
menu.popup(None, None, None, event.button, event.time) menu.popup(None, None, None, event.button, event.time)
@ -300,7 +300,7 @@ class VcardWindow:
self.contact.get_shown_name() + self.contact.get_shown_name() +
'</span></b>') '</span></b>')
self.xml.get_widget('jid_label').set_text(self.contact.jid) self.xml.get_widget('jid_label').set_text(self.contact.jid)
subscription_label = self.xml.get_widget('subscription_label') subscription_label = self.xml.get_widget('subscription_label')
ask_label = self.xml.get_widget('ask_label') ask_label = self.xml.get_widget('ask_label')
if self.gc_contact: if self.gc_contact:
@ -442,7 +442,7 @@ class ZeroconfVcardWindow:
self.contact.jid, self.account, self.contact.get_shown_name() + self.contact.jid, self.account, self.contact.get_shown_name() +
'.jpeg') '.jpeg')
menu.append(menuitem) menu.append(menuitem)
menu.connect('selection-done', lambda w:w.destroy()) menu.connect('selection-done', lambda w:w.destroy())
# show the menu # show the menu
menu.show_all() menu.show_all()
menu.popup(None, None, None, event.button, event.time) menu.popup(None, None, None, event.button, event.time)
@ -493,7 +493,7 @@ class ZeroconfVcardWindow:
tip = gtk.Tooltips() tip = gtk.Tooltips()
status_label_eventbox = self.xml.get_widget('status_label_eventbox') status_label_eventbox = self.xml.get_widget('status_label_eventbox')
tip.set_tip(status_label_eventbox, stats) tip.set_tip(status_label_eventbox, stats)
def fill_contact_page(self): def fill_contact_page(self):
tooltips = gtk.Tooltips() tooltips = gtk.Tooltips()
self.xml.get_widget('nickname_label').set_markup( self.xml.get_widget('nickname_label').set_markup(
@ -521,7 +521,7 @@ class ZeroconfVcardWindow:
self.fill_status_label() self.fill_status_label()
# gajim.connections[self.account].request_vcard(self.contact.jid, self.is_fake) # gajim.connections[self.account].request_vcard(self.contact.jid, self.is_fake)
def fill_personal_page(self): def fill_personal_page(self):
contact = gajim.connections[gajim.ZEROCONF_ACC_NAME].roster.getItem(self.contact.jid) contact = gajim.connections[gajim.ZEROCONF_ACC_NAME].roster.getItem(self.contact.jid)
for key in ('1st', 'last', 'jid', 'email'): for key in ('1st', 'last', 'jid', 'email'):