[thorstenp] remove whitespace at eol
This commit is contained in:
parent
0d33683944
commit
e389e0b16b
|
@ -492,7 +492,7 @@ class CommandWindow:
|
|||
if self.data_form_widget.data_form:
|
||||
# cmdnode.addChild(node=dataforms.DataForm(tofill=self.data_form_widget.data_form))
|
||||
# FIXME: simplified form to send
|
||||
|
||||
|
||||
cmdnode.addChild(node=self.data_form_widget.data_form)
|
||||
|
||||
def callback(response):
|
||||
|
|
|
@ -92,14 +92,14 @@ class AdvancedConfigurationWindow(object):
|
|||
# key = option name (root/subopt/opt separated by \n then)
|
||||
# value = array(oldval, newval)
|
||||
self.changed_opts = {}
|
||||
|
||||
|
||||
# For i18n
|
||||
self.right_true_dict = {True: _('Activated'), False: _('Deactivated')}
|
||||
self.right_true_dict = {True: _('Activated'), False: _('Deactivated')}
|
||||
self.types = {
|
||||
'boolean': _('Boolean'),
|
||||
'integer': _('Integer'),
|
||||
'string': _('Text'),
|
||||
'color': _('Color')}
|
||||
'color': _('Color')}
|
||||
|
||||
treeview = self.xml.get_widget('advanced_treeview')
|
||||
self.treeview = treeview
|
||||
|
@ -279,6 +279,6 @@ class AdvancedConfigurationWindow(object):
|
|||
self.treeview.collapse_all()
|
||||
else:
|
||||
# ... and be restored correctly here
|
||||
self.treeview.expand_all()
|
||||
self.treeview.expand_all()
|
||||
|
||||
# vim: se ts=3:
|
||||
|
|
|
@ -68,7 +68,7 @@ class AtomWindow:
|
|||
assert len(self.__class__.entries)>0
|
||||
|
||||
newentry = self.__class__.entries.pop(0)
|
||||
|
||||
|
||||
# fill the fields
|
||||
if newentry.feed_link is not None:
|
||||
self.feed_title_label.set_markup(
|
||||
|
|
|
@ -28,7 +28,7 @@ import gobject
|
|||
class CellRendererImage(gtk.GenericCellRenderer):
|
||||
|
||||
__gproperties__ = {
|
||||
'image': (gobject.TYPE_OBJECT, 'Image',
|
||||
'image': (gobject.TYPE_OBJECT, 'Image',
|
||||
'Image', gobject.PARAM_READWRITE),
|
||||
}
|
||||
|
||||
|
@ -46,13 +46,13 @@ class CellRendererImage(gtk.GenericCellRenderer):
|
|||
return getattr(self, pspec.name)
|
||||
|
||||
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:
|
||||
return
|
||||
self.redraw = 1
|
||||
col = tree.get_column(self.col_index)
|
||||
cell_area = tree.get_cell_area(path, col)
|
||||
|
||||
|
||||
tree.queue_draw_area(cell_area.x, cell_area.y,
|
||||
cell_area.width, cell_area.height)
|
||||
|
||||
|
@ -70,7 +70,7 @@ class CellRendererImage(gtk.GenericCellRenderer):
|
|||
self.animation_timeout, tree, image)
|
||||
elif image in self.iters:
|
||||
del self.iters[image]
|
||||
|
||||
|
||||
def on_render(self, window, widget, background_area, cell_area,
|
||||
expose_area, flags):
|
||||
if not self.image:
|
||||
|
|
|
@ -509,7 +509,7 @@ class ChatControlBase(MessageControl):
|
|||
start_iter, end_iter = message_buffer.get_bounds()
|
||||
message = message_buffer.get_text(start_iter, end_iter, False).decode(
|
||||
'utf-8')
|
||||
xhtml = self.msg_textview.get_xhtml()
|
||||
xhtml = self.msg_textview.get_xhtml()
|
||||
|
||||
# construct event instance from binding
|
||||
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):
|
||||
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.show_all()
|
||||
|
||||
def on_font_menuitem_activale(self, widget):
|
||||
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.show_all()
|
||||
|
||||
|
||||
|
||||
def on_actions_button_clicked(self, widget):
|
||||
'''popup action menu'''
|
||||
|
|
|
@ -108,7 +108,7 @@ if gajim.HAVE_GPG:
|
|||
enc = self._addHeaderFooter(str_, 'MESSAGE')
|
||||
proc.handles['stdin'].write(enc)
|
||||
proc.handles['stdin'].close()
|
||||
|
||||
|
||||
output = proc.handles['stdout'].read()
|
||||
proc.handles['stdout'].close()
|
||||
|
||||
|
@ -166,7 +166,7 @@ if gajim.HAVE_GPG:
|
|||
|
||||
try: proc.wait()
|
||||
except IOError: pass
|
||||
|
||||
|
||||
keyid = ''
|
||||
if 'GOODSIG' in resp:
|
||||
keyid = resp['GOODSIG'].split()[0]
|
||||
|
|
|
@ -39,15 +39,15 @@ Process object, which contains the filehandles to talk to GnuPG with.
|
|||
Example code:
|
||||
|
||||
>>> import GnuPGInterface
|
||||
>>>
|
||||
>>>
|
||||
>>> plaintext = "Three blind mice"
|
||||
>>> passphrase = "This is the passphrase"
|
||||
>>>
|
||||
>>>
|
||||
>>> gnupg = GnuPGInterface.GnuPG()
|
||||
>>> gnupg.options.armor = 1
|
||||
>>> gnupg.options.meta_interactive = 0
|
||||
>>> gnupg.options.extra_args.append('--no-secmem-warning')
|
||||
>>>
|
||||
>>>
|
||||
>>> # Normally we might specify something in
|
||||
>>> # gnupg.options.recipients, like
|
||||
>>> # gnupg.options.recipients = [ '0xABCD1234', 'bob@foo.bar' ]
|
||||
|
@ -55,39 +55,39 @@ Example code:
|
|||
>>> # If you are doing standard, public-key encryption, using
|
||||
>>> # --encrypt, you will need to specify recipients before
|
||||
>>> # calling gnupg.run()
|
||||
>>>
|
||||
>>>
|
||||
>>> # First we'll encrypt the test_text input symmetrically
|
||||
>>> p1 = gnupg.run(['--symmetric'],
|
||||
... create_fhs=['stdin', 'stdout', 'passphrase'])
|
||||
>>>
|
||||
>>>
|
||||
>>> p1.handles['passphrase'].write(passphrase)
|
||||
>>> p1.handles['passphrase'].close()
|
||||
>>>
|
||||
>>>
|
||||
>>> p1.handles['stdin'].write(plaintext)
|
||||
>>> p1.handles['stdin'].close()
|
||||
>>>
|
||||
>>>
|
||||
>>> ciphertext = p1.handles['stdout'].read()
|
||||
>>> p1.handles['stdout'].close()
|
||||
>>>
|
||||
>>>
|
||||
>>> # process cleanup
|
||||
>>> p1.wait()
|
||||
>>>
|
||||
>>>
|
||||
>>> # Now we'll decrypt what we just encrypted it,
|
||||
>>> # using the convience method to get the
|
||||
>>> # passphrase to GnuPG
|
||||
>>> gnupg.passphrase = passphrase
|
||||
>>>
|
||||
>>>
|
||||
>>> p2 = gnupg.run(['--decrypt'], create_fhs=['stdin', 'stdout'])
|
||||
>>>
|
||||
>>>
|
||||
>>> p2.handles['stdin'].write(ciphertext)
|
||||
>>> p2.handles['stdin'].close()
|
||||
>>>
|
||||
>>>
|
||||
>>> decrypted_plaintext = p2.handles['stdout'].read()
|
||||
>>> p2.handles['stdout'].close()
|
||||
>>>
|
||||
>>>
|
||||
>>> # process cleanup
|
||||
>>> p2.wait()
|
||||
>>>
|
||||
>>>
|
||||
>>> # Our decrypted plaintext:
|
||||
>>> decrypted_plaintext
|
||||
'Three blind mice'
|
||||
|
@ -99,10 +99,10 @@ Example code:
|
|||
>>>
|
||||
>>> ##################################################
|
||||
>>> # Now let's trying using run()'s attach_fhs paramter
|
||||
>>>
|
||||
>>>
|
||||
>>> # we're assuming we're running on a unix...
|
||||
>>> input = open('/etc/motd')
|
||||
>>>
|
||||
>>>
|
||||
>>> p1 = gnupg.run(['--symmetric'], create_fhs=['stdout'],
|
||||
... attach_fhs={'stdin': input})
|
||||
>>>
|
||||
|
@ -111,26 +111,26 @@ Example code:
|
|||
>>>
|
||||
>>> # process cleanup
|
||||
>>> p1.wait()
|
||||
>>>
|
||||
>>>
|
||||
>>> # Now let's run the output through GnuPG
|
||||
>>> # We'll write the output to a temporary file,
|
||||
>>> import tempfile
|
||||
>>> temp = tempfile.TemporaryFile()
|
||||
>>>
|
||||
>>>
|
||||
>>> p2 = gnupg.run(['--decrypt'], create_fhs=['stdin'],
|
||||
... attach_fhs={'stdout': temp})
|
||||
>>>
|
||||
>>>
|
||||
>>> # give GnuPG our encrypted stuff from the first run
|
||||
>>> p2.handles['stdin'].write(ciphertext)
|
||||
>>> p2.handles['stdin'].close()
|
||||
>>>
|
||||
>>>
|
||||
>>> # process cleanup
|
||||
>>> p2.wait()
|
||||
>>>
|
||||
>>>
|
||||
>>> # rewind the tempfile and see what GnuPG gave us
|
||||
>>> temp.seek(0)
|
||||
>>> decrypted_plaintext = temp.read()
|
||||
>>>
|
||||
>>>
|
||||
>>> # compare what GnuPG decrypted with our original input
|
||||
>>> input.seek(0)
|
||||
>>> input_data = input.read()
|
||||
|
@ -150,7 +150,7 @@ so that it has an encrypt_string() method that returns
|
|||
ciphertext.
|
||||
|
||||
>>> import GnuPGInterface
|
||||
>>>
|
||||
>>>
|
||||
>>> class MyGnuPG(GnuPGInterface.GnuPG):
|
||||
...
|
||||
... def __init__(self):
|
||||
|
@ -164,12 +164,12 @@ ciphertext.
|
|||
...
|
||||
... def encrypt_string(self, string, recipients):
|
||||
... gnupg.options.recipients = recipients # a list!
|
||||
...
|
||||
...
|
||||
... proc = gnupg.run(['--encrypt'], create_fhs=['stdin', 'stdout'])
|
||||
...
|
||||
...
|
||||
... proc.handles['stdin'].write(string)
|
||||
... proc.handles['stdin'].close()
|
||||
...
|
||||
...
|
||||
... output = proc.handles['stdout'].read()
|
||||
... 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.
|
||||
>>> # We also have to capture stdout since otherwise doctest complains;
|
||||
>>> # Normally you can let stdout through when generating a key.
|
||||
>>>
|
||||
>>>
|
||||
>>> proc = gnupg.run(['--gen-key'], create_fhs=['stdin', 'stdout',
|
||||
... 'logger'])
|
||||
>>>
|
||||
>>>
|
||||
>>> proc.handles['stdin'].write('''Key-Type: DSA
|
||||
... Key-Length: 1024
|
||||
... # 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
|
||||
... %secring foo.sec
|
||||
... ''')
|
||||
>>>
|
||||
>>>
|
||||
>>> proc.handles['stdin'].close()
|
||||
>>>
|
||||
>>>
|
||||
>>> report = proc.handles['logger'].read()
|
||||
>>> proc.handles['logger'].close()
|
||||
>>>
|
||||
>>>
|
||||
>>> proc.wait()
|
||||
"""
|
||||
|
||||
|
@ -250,21 +250,21 @@ _fd_options = { 'passphrase': '--passphrase-fd',
|
|||
|
||||
class GnuPG:
|
||||
"""Class instances represent GnuPG.
|
||||
|
||||
|
||||
Instance attributes of a GnuPG object are:
|
||||
|
||||
|
||||
* call -- string to call GnuPG with. Defaults to "gpg"
|
||||
|
||||
* passphrase -- Since it is a common operation
|
||||
to pass in a passphrase to GnuPG,
|
||||
and working with the passphrase filehandle mechanism directly
|
||||
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(),
|
||||
then GnuPG instnace will take care of sending the passphrase to
|
||||
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
|
||||
the command-line options used when calling GnuPG.
|
||||
"""
|
||||
|
@ -273,14 +273,14 @@ class GnuPG:
|
|||
self.call = 'gpg'
|
||||
self.passphrase = None
|
||||
self.options = Options()
|
||||
|
||||
|
||||
def run(self, gnupg_commands, args=None, create_fhs=None, attach_fhs=None):
|
||||
"""Calls GnuPG with the list of string commands gnupg_commands,
|
||||
complete with prefixing dashes.
|
||||
For example, gnupg_commands could be
|
||||
'["--sign", "--encrypt"]'
|
||||
Returns a GnuPGInterface.Process object.
|
||||
|
||||
|
||||
args is an optional list of GnuPG command arguments (not options),
|
||||
such as keyID's to export, filenames to process, etc.
|
||||
|
||||
|
@ -289,7 +289,7 @@ class GnuPG:
|
|||
'handles' attribute. The generated filehandles can be used
|
||||
to communicate with GnuPG via standard input, standard output,
|
||||
the status-fd, passphrase-fd, etc.
|
||||
|
||||
|
||||
Valid GnuPG filehandle names are:
|
||||
* stdin
|
||||
* stdout
|
||||
|
@ -298,10 +298,10 @@ class GnuPG:
|
|||
* passphase
|
||||
* command
|
||||
* logger
|
||||
|
||||
|
||||
The purpose of each filehandle is described in the GnuPG
|
||||
documentation.
|
||||
|
||||
|
||||
attach_fhs is an optional dictionary with GnuPG filehandle
|
||||
names mapping to opened files. GnuPG will read or write
|
||||
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
|
||||
if you want GnuPG to read/write to/from an existing file.
|
||||
For instance:
|
||||
|
||||
|
||||
f = open("encrypted.gpg")
|
||||
gnupg.run(["--decrypt"], attach_fhs={'stdin': f})
|
||||
|
||||
Using attach_fhs also helps avoid system buffering
|
||||
issues that can arise when using create_fhs, which
|
||||
can cause the process to deadlock.
|
||||
|
||||
|
||||
If not mentioned in create_fhs or attach_fhs,
|
||||
GnuPG filehandles which are a std* (stdin, stdout, stderr)
|
||||
are defaulted to the running process' version of handle.
|
||||
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
|
||||
status filehandle, simply do not specify it.
|
||||
|
||||
|
||||
run() returns a Process() object which has a 'handles'
|
||||
which is a dictionary mapping from the handle name
|
||||
(such as 'stdin' or 'stdout') to the respective
|
||||
|
@ -331,47 +331,47 @@ class GnuPG:
|
|||
For instance, if the call was
|
||||
|
||||
process = gnupg.run(["--decrypt"], stdin=1)
|
||||
|
||||
|
||||
after run returns 'process.handles["stdin"]'
|
||||
is a FileObject connected to GnuPG's standard input,
|
||||
and can be written to.
|
||||
"""
|
||||
|
||||
|
||||
if args is None: args = []
|
||||
if create_fhs is None: create_fhs = []
|
||||
if attach_fhs is None: attach_fhs = {}
|
||||
|
||||
|
||||
for std in _stds:
|
||||
if std not in attach_fhs \
|
||||
and std not in create_fhs:
|
||||
attach_fhs.setdefault(std, getattr(sys, std))
|
||||
|
||||
|
||||
handle_passphrase = 0
|
||||
|
||||
|
||||
if self.passphrase is not None \
|
||||
and 'passphrase' not in attach_fhs \
|
||||
and 'passphrase' not in create_fhs:
|
||||
handle_passphrase = 1
|
||||
create_fhs.append('passphrase')
|
||||
|
||||
|
||||
process = self._attach_fork_exec(gnupg_commands, args,
|
||||
create_fhs, attach_fhs)
|
||||
|
||||
|
||||
if handle_passphrase:
|
||||
passphrase_fh = process.handles['passphrase']
|
||||
passphrase_fh.write( self.passphrase )
|
||||
passphrase_fh.close()
|
||||
del process.handles['passphrase']
|
||||
|
||||
|
||||
return process
|
||||
|
||||
|
||||
|
||||
|
||||
def _attach_fork_exec(self, gnupg_commands, args, create_fhs, attach_fhs):
|
||||
"""This is like run(), but without the passphrase-helping
|
||||
(note that run() calls this)."""
|
||||
|
||||
|
||||
process = Process()
|
||||
|
||||
|
||||
for fh_name in create_fhs + attach_fhs.keys():
|
||||
if fh_name not in _fd_modes:
|
||||
raise KeyError, \
|
||||
|
@ -393,26 +393,26 @@ class GnuPG:
|
|||
# if we are writing
|
||||
if _fd_modes[fh_name] == 'w': pipe = (pipe[1], pipe[0])
|
||||
process._pipes[fh_name] = Pipe(pipe[0], pipe[1], 0)
|
||||
|
||||
|
||||
for fh_name, fh in attach_fhs.items():
|
||||
process._pipes[fh_name] = Pipe(fh.fileno(), fh.fileno(), 1)
|
||||
|
||||
|
||||
process.pid = os.fork()
|
||||
|
||||
|
||||
if process.pid == 0: self._as_child(process, gnupg_commands, args)
|
||||
return self._as_parent(process)
|
||||
|
||||
|
||||
|
||||
|
||||
def _as_parent(self, process):
|
||||
"""Stuff run after forking in parent"""
|
||||
for k, p in process._pipes.items():
|
||||
if not p.direct:
|
||||
os.close(p.child)
|
||||
process.handles[k] = os.fdopen(p.parent, _fd_modes[k])
|
||||
|
||||
|
||||
# user doesn't need these
|
||||
del process._pipes
|
||||
|
||||
|
||||
return process
|
||||
|
||||
|
||||
|
@ -422,27 +422,27 @@ class GnuPG:
|
|||
for std in _stds:
|
||||
p = process._pipes[std]
|
||||
os.dup2( p.child, getattr(sys, "__%s__" % std).fileno() )
|
||||
|
||||
|
||||
for k, p in process._pipes.items():
|
||||
if p.direct and k not in _stds:
|
||||
# we want the fh to stay open after execing
|
||||
fcntl.fcntl( p.child, fcntl.F_SETFD, 0 )
|
||||
|
||||
|
||||
fd_args = []
|
||||
|
||||
|
||||
for k, p in process._pipes.items():
|
||||
# set command-line options for non-standard fds
|
||||
if k not in _stds:
|
||||
fd_args.extend([ _fd_options[k], "%d" % p.child ])
|
||||
|
||||
|
||||
if not p.direct: os.close(p.parent)
|
||||
|
||||
|
||||
command = [ self.call ] + fd_args + self.options.get_args() \
|
||||
+ gnupg_commands + args
|
||||
|
||||
os.execvp( command[0], command )
|
||||
|
||||
|
||||
|
||||
class Pipe:
|
||||
"""simple struct holding stuff about pipes we use"""
|
||||
def __init__(self, parent, child, direct):
|
||||
|
@ -456,14 +456,14 @@ class Options:
|
|||
This class is responsible for determining command-line arguments
|
||||
which are based on options. It can be said that a GnuPG
|
||||
object has-a Options object in its options attribute.
|
||||
|
||||
|
||||
Attributes which correlate directly to GnuPG options:
|
||||
|
||||
|
||||
Each option here defaults to false or None, and is described in
|
||||
GnuPG documentation.
|
||||
|
||||
|
||||
Booleans (set these attributes to booleans)
|
||||
|
||||
|
||||
* armor
|
||||
* no_greeting
|
||||
* no_verbose
|
||||
|
@ -475,54 +475,54 @@ class Options:
|
|||
* force_v3_sigs
|
||||
* no_options
|
||||
* textmode
|
||||
|
||||
|
||||
Strings (set these attributes to strings)
|
||||
|
||||
|
||||
* homedir
|
||||
* default_key
|
||||
* comment
|
||||
* compress_algo
|
||||
* options
|
||||
|
||||
|
||||
Lists (set these attributes to lists)
|
||||
|
||||
|
||||
* recipients (***NOTE*** plural of 'recipient')
|
||||
* encrypt_to
|
||||
|
||||
|
||||
Meta options
|
||||
|
||||
|
||||
Meta options are options provided by this module that do
|
||||
not correlate directly to any GnuPG option by name,
|
||||
but are rather bundle of options used to accomplish
|
||||
a specific goal, such as obtaining compatibility with PGP 5.
|
||||
The actual arguments each of these reflects may change with time. Each
|
||||
defaults to false unless otherwise specified.
|
||||
|
||||
|
||||
meta_pgp_5_compatible -- If true, arguments are generated to try
|
||||
to be compatible with PGP 5.x.
|
||||
|
||||
|
||||
meta_pgp_2_compatible -- If true, arguments are generated to try
|
||||
to be compatible with PGP 2.x.
|
||||
|
||||
|
||||
meta_interactive -- If false, arguments are generated to try to
|
||||
help the using program use GnuPG in a non-interactive
|
||||
environment, such as CGI scripts. Default is true.
|
||||
|
||||
|
||||
extra_args -- Extra option arguments may be passed in
|
||||
via the attribute extra_args, a list.
|
||||
|
||||
>>> import GnuPGInterface
|
||||
>>>
|
||||
>>>
|
||||
>>> gnupg = GnuPGInterface.GnuPG()
|
||||
>>> gnupg.options.armor = 1
|
||||
>>> gnupg.options.recipients = ['Alice', 'Bob']
|
||||
>>> gnupg.options.extra_args = ['--no-secmem-warning']
|
||||
>>>
|
||||
>>>
|
||||
>>> # no need for users to call this normally; just for show here
|
||||
>>> gnupg.options.get_args()
|
||||
['--armor', '--recipient', 'Alice', '--recipient', 'Bob', '--no-secmem-warning']
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self):
|
||||
# booleans
|
||||
self.armor = 0
|
||||
|
@ -553,13 +553,13 @@ class Options:
|
|||
# lists
|
||||
self.encrypt_to = []
|
||||
self.recipients = []
|
||||
|
||||
|
||||
# miscellaneous arguments
|
||||
self.extra_args = []
|
||||
|
||||
|
||||
def get_args( self ):
|
||||
"""Generate a list of GnuPG arguments based upon attributes."""
|
||||
|
||||
|
||||
return self.get_meta_args() + self.get_standard_args() + self.extra_args
|
||||
|
||||
def get_standard_args( self ):
|
||||
|
@ -575,7 +575,7 @@ class Options:
|
|||
args.extend( [ '--compress-algo', self.compress_algo ] )
|
||||
if self.default_key is not None:
|
||||
args.extend( [ '--default-key', self.default_key ] )
|
||||
|
||||
|
||||
if self.no_options: args.append( '--no-options' )
|
||||
if self.armor: args.append( '--armor' )
|
||||
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.encrypt_to: args.extend( [ '--encrypt-to', r ] )
|
||||
|
||||
|
||||
return args
|
||||
|
||||
def get_meta_args( self ):
|
||||
|
@ -610,26 +610,26 @@ class Options:
|
|||
class Process:
|
||||
"""Objects of this class encompass properties of a GnuPG
|
||||
process spawned by GnuPG.run().
|
||||
|
||||
|
||||
# gnupg is a GnuPG object
|
||||
process = gnupg.run( [ '--decrypt' ], stdout = 1 )
|
||||
out = process.handles['stdout'].read()
|
||||
...
|
||||
os.waitpid( process.pid, 0 )
|
||||
|
||||
|
||||
Data Attributes
|
||||
|
||||
|
||||
handles -- This is a map of filehandle-names to
|
||||
the file handles, if any, that were requested via run() and hence
|
||||
are connected to the running GnuPG process. Valid names
|
||||
of this map are only those handles that were requested.
|
||||
|
||||
|
||||
pid -- The PID of the spawned GnuPG process.
|
||||
Useful to know, since once should call
|
||||
os.waitpid() to clean up the process, especially
|
||||
if multiple calls are made to run().
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self):
|
||||
self._pipes = {}
|
||||
self.handles = {}
|
||||
|
@ -639,7 +639,7 @@ class Process:
|
|||
def wait(self):
|
||||
"""Wait on the process to exit, allowing for child cleanup.
|
||||
Will raise an IOError if the process exits non-zero."""
|
||||
|
||||
|
||||
e = os.waitpid(self.pid, 0)[1]
|
||||
if e != 0:
|
||||
raise IOError, "GnuPG exited non-zero, with code %d" % (e << 8)
|
||||
|
|
|
@ -88,7 +88,7 @@ class OldEntry(xmpp.Node, object):
|
|||
source_feed = self.getTag('feed').getTagData('title')
|
||||
else:
|
||||
source_feed = None
|
||||
|
||||
|
||||
|
||||
if main_feed is not None and source_feed is not None:
|
||||
return u'%s: %s' % (main_feed, source_feed)
|
||||
|
@ -99,7 +99,7 @@ class OldEntry(xmpp.Node, object):
|
|||
else:
|
||||
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
|
||||
which delivered this entry. ''')
|
||||
|
||||
|
@ -151,7 +151,7 @@ class OldEntry(xmpp.Node, object):
|
|||
|
||||
return date
|
||||
|
||||
updated = property(get_updated, None, None,
|
||||
updated = property(get_updated, None, None,
|
||||
''' Last significant modification time. ''')
|
||||
|
||||
feed_tagline = u''
|
||||
|
|
|
@ -239,7 +239,7 @@ class ConnectionCaps(object):
|
|||
if contact is None:
|
||||
# TODO: a way to put contact not-in-roster
|
||||
# into Contacts
|
||||
return
|
||||
return
|
||||
|
||||
# get the caps element
|
||||
caps = presence.getTag('c')
|
||||
|
|
|
@ -42,7 +42,7 @@ except ImportError:
|
|||
|
||||
def create_log_db():
|
||||
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
|
||||
cur = con.cursor()
|
||||
# create the tables
|
||||
|
@ -61,19 +61,19 @@ def create_log_db():
|
|||
jid TEXT UNIQUE,
|
||||
type INTEGER
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE unread_messages(
|
||||
message_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||
jid_id INTEGER
|
||||
);
|
||||
|
||||
|
||||
CREATE INDEX idx_unread_messages_jid_id ON unread_messages (jid_id);
|
||||
|
||||
|
||||
CREATE TABLE transports_cache (
|
||||
transport TEXT UNIQUE,
|
||||
type INTEGER
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE logs(
|
||||
log_line_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||
jid_id INTEGER,
|
||||
|
@ -84,7 +84,7 @@ def create_log_db():
|
|||
message TEXT,
|
||||
subject TEXT
|
||||
);
|
||||
|
||||
|
||||
CREATE INDEX idx_logs_jid_id_kind ON logs (jid_id, kind);
|
||||
|
||||
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 _('Gajim will now exit')
|
||||
sys.exit()
|
||||
|
||||
|
||||
else: # dot_gajim doesn't exist
|
||||
if dot_gajim: # is '' on win9x so avoid that
|
||||
create_path(dot_gajim)
|
||||
|
|
|
@ -36,7 +36,7 @@ class AdHocCommand:
|
|||
def isVisibleFor(samejid):
|
||||
''' This returns True if that command should be visible and invokable
|
||||
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.'''
|
||||
return True
|
||||
|
||||
|
@ -88,7 +88,7 @@ class ChangeStatusCommand(AdHocCommand):
|
|||
# first query...
|
||||
response, cmd = self.buildResponse(request, defaultaction = 'execute',
|
||||
actions = ['execute'])
|
||||
|
||||
|
||||
cmd.addChild(node = dataforms.SimpleDataForm(
|
||||
title = _('Change status'),
|
||||
instructions = _('Set the presence type and description'),
|
||||
|
@ -113,7 +113,7 @@ class ChangeStatusCommand(AdHocCommand):
|
|||
|
||||
# for next invocation
|
||||
self.execute = self.changestatus
|
||||
|
||||
|
||||
return True # keep the session
|
||||
|
||||
def changestatus(self, request):
|
||||
|
@ -193,7 +193,7 @@ class LeaveGroupchatsCommand(AdHocCommand):
|
|||
if not len(options):
|
||||
response, cmd = self.buildResponse(request, status = 'completed')
|
||||
cmd.addChild('note', {}, _('You have not joined a groupchat.'))
|
||||
|
||||
|
||||
self.connection.connection.send(response)
|
||||
return False
|
||||
|
||||
|
|
|
@ -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.')],
|
||||
'notify_on_file_complete': [opt_bool, True],
|
||||
'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, ''],
|
||||
'use_kib_mib': [opt_bool, False, _('IEC standard says KiB = 1024 bytes, KB = 1000 bytes.')],
|
||||
'notify_on_all_muc_messages': [opt_bool, False],
|
||||
|
@ -557,7 +557,7 @@ class Config:
|
|||
if optname not in self.__options:
|
||||
return None
|
||||
return self.__options[optname][OPT_VAL]
|
||||
|
||||
|
||||
def get_desc(self, optname):
|
||||
if optname not in self.__options:
|
||||
return None
|
||||
|
@ -574,7 +574,7 @@ class Config:
|
|||
if typename not in self.__options_per_key:
|
||||
# raise RuntimeError, 'option %s does not exist' % typename
|
||||
return
|
||||
|
||||
|
||||
opt = self.__options_per_key[typename]
|
||||
if name in opt[1]:
|
||||
# we already have added group name before
|
||||
|
@ -589,7 +589,7 @@ class Config:
|
|||
opt = self.__options_per_key[typename]
|
||||
if subname is None:
|
||||
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]:
|
||||
del opt[1][name][subname]
|
||||
|
||||
|
|
|
@ -1542,7 +1542,7 @@ class Connection(ConnectionHandlers):
|
|||
# Not in special table, get it from messages DB
|
||||
last_log = gajim.logger.get_last_date_that_has_logs(room_jid,
|
||||
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
|
||||
if last_log is None:
|
||||
last_log = 0
|
||||
|
|
|
@ -331,7 +331,7 @@ class ConnectionBytestream:
|
|||
return
|
||||
|
||||
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'''
|
||||
if not self.connection or self.connected < 2:
|
||||
return
|
||||
|
@ -1471,7 +1471,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
'password': conf.getTagData('password'),
|
||||
'nick': conf.getTagData('nick'),
|
||||
'print_status': print_status}
|
||||
|
||||
|
||||
self.bookmarks.append(bm)
|
||||
self.dispatch('BOOKMARKS', self.bookmarks)
|
||||
|
||||
|
@ -1501,7 +1501,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
groups.append(group.getData())
|
||||
self.dispatch('ROSTER_INFO', (jid, name, sub, ask, groups))
|
||||
raise common.xmpp.NodeProcessed
|
||||
|
||||
|
||||
def _VersionCB(self, con, iq_obj):
|
||||
gajim.log.debug('VersionCB')
|
||||
if not self.connection or self.connected < 2:
|
||||
|
@ -1526,7 +1526,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
qp.attrs['seconds'] = '0'
|
||||
else:
|
||||
qp.attrs['seconds'] = idle.getIdleSec()
|
||||
|
||||
|
||||
self.connection.send(iq_obj)
|
||||
raise common.xmpp.NodeProcessed
|
||||
|
||||
|
@ -2256,7 +2256,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
if 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))
|
||||
|
||||
def _MucErrorCB(self, con, iq_obj):
|
||||
|
@ -2294,13 +2294,13 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
if not self.connection:
|
||||
return
|
||||
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')
|
||||
self.discoverInfo(gajim.config.get_per('accounts', self.name,
|
||||
self.discoverInfo(gajim.config.get_per('accounts', self.name,
|
||||
'hostname'), id_prefix='p')
|
||||
if gajim.config.get_per('accounts', self.name, 'use_ft_proxies'):
|
||||
self.discover_ft_proxies()
|
||||
|
||||
|
||||
def discover_ft_proxies(self):
|
||||
cfg_proxies = gajim.config.get_per('accounts', self.name,
|
||||
'file_transfer_proxies')
|
||||
|
@ -2310,7 +2310,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
proxies = map(lambda e:e.strip(), cfg_proxies.split(','))
|
||||
for proxy in proxies:
|
||||
gajim.proxy65_manager.resolve(proxy, self.connection, our_jid)
|
||||
|
||||
|
||||
def _on_roster_set(self, roster):
|
||||
raw_roster = roster.getRaw()
|
||||
roster = {}
|
||||
|
@ -2398,7 +2398,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
# Inform GUI we just signed in
|
||||
self.dispatch('SIGNED_IN', ())
|
||||
self.continue_connect_info = None
|
||||
|
||||
|
||||
def request_gmail_notifications(self):
|
||||
if not self.connection or self.connected < 2:
|
||||
return
|
||||
|
@ -2421,7 +2421,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
|||
query.setNamespace(common.xmpp.NS_GMAILNOTIFY)
|
||||
self.connection.send(iq)
|
||||
|
||||
|
||||
|
||||
def _search_fields_received(self, con, iq_obj):
|
||||
jid = jid = helpers.get_jid_from_iq(iq_obj)
|
||||
tag = iq_obj.getTag('query', namespace = common.xmpp.NS_SEARCH)
|
||||
|
|
|
@ -197,7 +197,7 @@ class Contacts:
|
|||
caps_hash_method=None, caps_hash=None, our_chatstate=None,
|
||||
chatstate=None, last_status_time=None, composing_xep=None,
|
||||
mood={}, tune={}, activity={}):
|
||||
|
||||
|
||||
# We don't want duplicated group values
|
||||
groups_unique = []
|
||||
for group in groups:
|
||||
|
@ -210,7 +210,7 @@ class Contacts:
|
|||
caps_hash=caps_hash, our_chatstate=our_chatstate, chatstate=chatstate,
|
||||
last_status_time=last_status_time, composing_xep=composing_xep,
|
||||
mood=mood, tune=tune, activity=activity)
|
||||
|
||||
|
||||
def copy_contact(self, contact):
|
||||
return self.create_contact(jid=contact.jid, name=contact.name,
|
||||
groups=contact.groups, show=contact.show, status=contact.status,
|
||||
|
@ -272,7 +272,7 @@ class Contacts:
|
|||
return self._contacts[account][jid]
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
def get_contact(self, account, jid, resource=None):
|
||||
### WARNING ###
|
||||
# This function returns a *RANDOM* resource if resource = None!
|
||||
|
@ -437,7 +437,7 @@ class Contacts:
|
|||
nearby_family = [data for data in family
|
||||
if account in accounts]
|
||||
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 False
|
||||
|
||||
|
@ -484,7 +484,7 @@ class Contacts:
|
|||
# is not in our roster
|
||||
if not contact1:
|
||||
if contact2:
|
||||
return -1 # prefer the known contact
|
||||
return -1 # prefer the known contact
|
||||
else:
|
||||
show1 = 0
|
||||
priority1 = 0
|
||||
|
@ -578,7 +578,7 @@ class Contacts:
|
|||
role='', affiliation='', jid='', resource=''):
|
||||
return GC_Contact(room_jid, name, show, status, role, affiliation, jid,
|
||||
resource)
|
||||
|
||||
|
||||
def add_gc_contact(self, account, gc_contact):
|
||||
# No such account before ?
|
||||
if account not in self._gc_contacts:
|
||||
|
|
|
@ -90,7 +90,7 @@ def srand(bottom, top):
|
|||
return (decode_mpi(random_bytes(bytes)) % (top - bottom)) + bottom
|
||||
|
||||
# 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):
|
||||
square = base % mod
|
||||
result = 1
|
||||
|
|
|
@ -129,7 +129,7 @@ class DataField(ExtendedNode):
|
|||
assert isinstance(value, basestring)
|
||||
self.setAttr('type', value)
|
||||
return locals()
|
||||
|
||||
|
||||
@nested_property
|
||||
def var():
|
||||
'''Field identifier.'''
|
||||
|
@ -274,7 +274,7 @@ class ListMultiField(ListField):
|
|||
for element in self.getTags('value'):
|
||||
self.delChild(element)
|
||||
return locals()
|
||||
|
||||
|
||||
def iter_values(self):
|
||||
for element in self.getTags('value'):
|
||||
yield element.getData()
|
||||
|
@ -412,7 +412,7 @@ class SimpleDataForm(DataForm, DataRecord):
|
|||
def __init__(self, type_=None, title=None, instructions=None, fields=None, extend=None):
|
||||
DataForm.__init__(self, type_=type_, title=title, instructions=instructions, extend=extend)
|
||||
DataRecord.__init__(self, fields=fields, extend=self, associated=self)
|
||||
|
||||
|
||||
def get_purged(self):
|
||||
c = SimpleDataForm(extend=self)
|
||||
del c.title
|
||||
|
|
|
@ -51,7 +51,7 @@ class SystemBus:
|
|||
'''A Singleton for the DBus SystemBus'''
|
||||
def __init__(self):
|
||||
self.system_bus = None
|
||||
|
||||
|
||||
def SystemBus(self):
|
||||
if not supported:
|
||||
raise exceptions.DbusNotSupported
|
||||
|
@ -84,7 +84,7 @@ class SessionBus:
|
|||
'''A Singleton for the D-Bus SessionBus'''
|
||||
def __init__(self):
|
||||
self.session_bus = None
|
||||
|
||||
|
||||
def SessionBus(self):
|
||||
if not supported:
|
||||
raise exceptions.DbusNotSupported
|
||||
|
@ -112,7 +112,7 @@ class SessionBus:
|
|||
session_bus = SessionBus()
|
||||
|
||||
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.'''
|
||||
if not supported:
|
||||
return None
|
||||
|
@ -148,7 +148,7 @@ def get_notifications_interface():
|
|||
if supported:
|
||||
class MissingArgument(dbus.DBusException):
|
||||
_dbus_error_name = _GAJIM_ERROR_IFACE + '.MissingArgument'
|
||||
|
||||
|
||||
class InvalidArgument(dbus.DBusException):
|
||||
'''Raised when one of the provided arguments is invalid.'''
|
||||
_dbus_error_name = _GAJIM_ERROR_IFACE + '.InvalidArgument'
|
||||
|
|
|
@ -166,7 +166,7 @@ except ImportError:
|
|||
|
||||
HAVE_GPG = True
|
||||
try:
|
||||
import GnuPGInterface
|
||||
import GnuPGInterface
|
||||
except ImportError:
|
||||
HAVE_GPG = False
|
||||
else:
|
||||
|
|
|
@ -350,10 +350,10 @@ def get_uf_role(role, plural = False):
|
|||
else:
|
||||
role_name = _('Visitor')
|
||||
return role_name
|
||||
|
||||
|
||||
def get_uf_affiliation(affiliation):
|
||||
'''Get a nice and translated affilition for muc'''
|
||||
if affiliation == 'none':
|
||||
if affiliation == 'none':
|
||||
affiliation_name = Q_('?Group Chat Contact Affiliation:None')
|
||||
elif affiliation == 'owner':
|
||||
affiliation_name = _('Owner')
|
||||
|
@ -593,7 +593,7 @@ def get_global_status():
|
|||
status = gajim.connections[account].status
|
||||
return status
|
||||
|
||||
def statuses_unified():
|
||||
def statuses_unified():
|
||||
'''testing if all statuses are the same.'''
|
||||
reference = None
|
||||
for account in gajim.connections:
|
||||
|
@ -765,7 +765,7 @@ def get_random_string_16():
|
|||
char_sequence = map(lambda e:chr(e), rng)
|
||||
from random import sample
|
||||
return ''.join(sample(char_sequence, 16))
|
||||
|
||||
|
||||
def get_os_info():
|
||||
if os.name == 'nt':
|
||||
ver = os.sys.getwindowsversion()
|
||||
|
@ -790,9 +790,9 @@ def get_os_info():
|
|||
full_path_to_executable = is_in_path(executable, return_abs_path = True)
|
||||
if full_path_to_executable:
|
||||
command = executable + params
|
||||
p = subprocess.Popen([command], shell=True, stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE, close_fds=True)
|
||||
p.wait()
|
||||
p = subprocess.Popen([command], shell=True, stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE, close_fds=True)
|
||||
p.wait()
|
||||
output = temp_failure_retry(p.stdout.readline).strip()
|
||||
# some distros put n/a in places, so remove those
|
||||
output = output.replace('n/a', '').replace('N/A', '')
|
||||
|
@ -832,7 +832,7 @@ def get_os_info():
|
|||
return 'N/A'
|
||||
|
||||
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)'''
|
||||
# 48 is the limit
|
||||
if len(filename) > 48:
|
||||
|
@ -845,7 +845,7 @@ def sanitize_filename(filename):
|
|||
filename = filename.replace('?', '_').replace(':', '_')\
|
||||
.replace('\\', '_').replace('"', "'").replace('|', '_')\
|
||||
.replace('*', '_').replace('<', '_').replace('>', '_')
|
||||
|
||||
|
||||
return filename
|
||||
|
||||
def allow_showing_notification(account, type_ = 'notify_on_new_message',
|
||||
|
@ -952,7 +952,7 @@ def get_account_status(account):
|
|||
return status
|
||||
|
||||
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]}'''
|
||||
# How many events must there be before they're shown summarized, not per-user
|
||||
max_ungrouped_events = 10
|
||||
|
@ -1000,7 +1000,7 @@ def get_notification_icon_tooltip_dict():
|
|||
else:
|
||||
text += _(' from %s') % (jid)
|
||||
account['event_lines'].append(text)
|
||||
|
||||
|
||||
# Display unseen events numbers, if any
|
||||
if total_non_messages > 0:
|
||||
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 show_more_accounts:
|
||||
text = _('Gajim')
|
||||
else:
|
||||
else:
|
||||
text = _('Gajim - %s') % (get_account_status(accounts[0]))
|
||||
|
||||
# Gather and display events. (With accounts, when there are more.)
|
||||
|
@ -1081,7 +1081,7 @@ def get_accounts_info():
|
|||
message = message.strip()
|
||||
if message != '':
|
||||
single_line += ': ' + message
|
||||
accounts.append({'name': account, 'status_line': single_line,
|
||||
accounts.append({'name': account, 'status_line': single_line,
|
||||
'show': status, 'message': message})
|
||||
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.
|
||||
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'''
|
||||
if gajim.connections[account].USE_GPG:
|
||||
if gajim.connections[account].USE_GPG:
|
||||
if keyID and len(keyID) == 16:
|
||||
keyID = keyID[8:]
|
||||
|
||||
|
||||
attached_keys = gajim.config.get_per('accounts', account,
|
||||
'attached_gpg_keys').split()
|
||||
|
||||
|
||||
if jid in attached_keys and keyID:
|
||||
attachedkeyID = attached_keys[attached_keys.index(jid) + 1]
|
||||
if attachedkeyID != keyID:
|
||||
|
@ -1165,7 +1165,7 @@ def prepare_and_validate_gpg_keyID(account, jid, keyID):
|
|||
elif jid in attached_keys:
|
||||
# An unsigned presence, just use the assigned key
|
||||
keyID = attached_keys[attached_keys.index(jid) + 1]
|
||||
elif keyID:
|
||||
elif keyID:
|
||||
public_keys = gajim.connections[account].ask_gpg_keys()
|
||||
# Assign the corresponding key, if we have it in our keyring
|
||||
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'):
|
||||
'''Compute caps hash according to XEP-0115, V1.5
|
||||
|
||||
|
||||
dataforms are xmpp.DataForms objects as common.dataforms don't allow several
|
||||
values without a field type list-multi'''
|
||||
S = ''
|
||||
|
|
|
@ -58,7 +58,7 @@ def Q_(s):
|
|||
# so we must use as:
|
||||
# s = Q_('?vcard:Unknown')
|
||||
# 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.
|
||||
# translator can either put the ?vcard: part or no (easier for him or her to no)
|
||||
# nothing fails
|
||||
|
@ -70,7 +70,7 @@ def Q_(s):
|
|||
def ngettext(s_sing, s_plural, n, replace_sing = None, replace_plural = None):
|
||||
'''use as:
|
||||
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..
|
||||
'''
|
||||
text = _translation.ungettext(s_sing, s_plural, n)
|
||||
|
|
|
@ -176,8 +176,8 @@ class Logger:
|
|||
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)
|
||||
and after that all okay'''
|
||||
|
||||
if jid.find('/') > -1:
|
||||
|
||||
if jid.find('/') > -1:
|
||||
possible_room_jid = jid.split('/', 1)[1]
|
||||
return self.jid_is_room_jid(possible_room_jid)
|
||||
else:
|
||||
|
@ -336,7 +336,7 @@ class Logger:
|
|||
try:
|
||||
self.cur.execute(sql, values)
|
||||
except sqlite.DatabaseError:
|
||||
raise exceptions.DatabaseMalformed
|
||||
raise exceptions.DatabaseMalformed
|
||||
except sqlite.OperationalError, e:
|
||||
raise exceptions.PysqliteOperationalError(str(e))
|
||||
message_id = None
|
||||
|
@ -373,7 +373,7 @@ class Logger:
|
|||
for message in results:
|
||||
msg_id = message[0]
|
||||
# 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
|
||||
self.cur.execute('''
|
||||
SELECT logs.log_line_id, logs.message, logs.time, logs.subject,
|
||||
|
|
|
@ -43,22 +43,22 @@ class Resolver:
|
|||
def __init__(self, idlequeue):
|
||||
self.idlequeue = idlequeue
|
||||
# dict {host : list of srv records}
|
||||
self.resolved_hosts = {}
|
||||
self.resolved_hosts = {}
|
||||
# dict {host : list of callbacks}
|
||||
self.handlers = {}
|
||||
|
||||
self.handlers = {}
|
||||
|
||||
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
|
||||
srv hosts '''
|
||||
if os.name == 'nt':
|
||||
return self._parse_srv_result_nt(fqdn, result)
|
||||
elif os.name == 'posix':
|
||||
return self._parse_srv_result_posix(fqdn, result)
|
||||
|
||||
|
||||
def _parse_srv_result_nt(self, fqdn, result):
|
||||
# output from win32 nslookup command
|
||||
if not result:
|
||||
if not result:
|
||||
return []
|
||||
hosts = []
|
||||
lines = result.replace('\r','').split('\n')
|
||||
|
@ -78,7 +78,7 @@ class Resolver:
|
|||
hosts.append(current_host)
|
||||
current_host = None
|
||||
continue
|
||||
prop_type = res[0].strip()
|
||||
prop_type = res[0].strip()
|
||||
prop_value = res[1].strip()
|
||||
if prop_type.find('prio') > -1:
|
||||
try:
|
||||
|
@ -104,11 +104,11 @@ class Resolver:
|
|||
hosts.append(current_host)
|
||||
current_host = None
|
||||
return hosts
|
||||
|
||||
|
||||
def _parse_srv_result_posix(self, fqdn, result):
|
||||
# typical output of bind-tools nslookup command:
|
||||
# _xmpp-client._tcp.jabber.org service = 30 30 5222 jabber.org.
|
||||
if not result:
|
||||
if not result:
|
||||
return []
|
||||
ufqdn = helpers.ascii_to_idn(fqdn) # Unicode domain name
|
||||
hosts = []
|
||||
|
@ -144,11 +144,11 @@ class Resolver:
|
|||
hosts.append({'host': host, 'port': port,'weight': weight,
|
||||
'prio': prio})
|
||||
return hosts
|
||||
|
||||
|
||||
def _on_ready(self, host, result):
|
||||
# nslookup finished, parse the result and call the handlers
|
||||
result_list = self.parse_srv_result(host, result)
|
||||
|
||||
|
||||
# practically it is impossible to be the opposite, but who knows :)
|
||||
if host not in self.resolved_hosts:
|
||||
self.resolved_hosts[host] = result_list
|
||||
|
@ -156,14 +156,14 @@ class Resolver:
|
|||
for callback in self.handlers[host]:
|
||||
callback(host, result_list)
|
||||
del(self.handlers[host])
|
||||
|
||||
|
||||
def start_resolve(self, host):
|
||||
''' spawn new nslookup process and start waiting for results '''
|
||||
ns = NsLookup(self._on_ready, host)
|
||||
ns.set_idlequeue(self.idlequeue)
|
||||
ns.commandtimeout = 10
|
||||
ns.start()
|
||||
|
||||
|
||||
def resolve(self, host, on_ready):
|
||||
if not host:
|
||||
# empty host, return empty list of srv records
|
||||
|
@ -175,7 +175,7 @@ class Resolver:
|
|||
return
|
||||
if host in self.handlers:
|
||||
# host is about to be resolved by another connection,
|
||||
# attach our callback
|
||||
# attach our callback
|
||||
self.handlers[host].append(on_ready)
|
||||
else:
|
||||
# host has never been resolved, start now
|
||||
|
@ -187,29 +187,29 @@ class IdleCommand(IdleObject):
|
|||
def __init__(self, on_result):
|
||||
# how long (sec.) to wait for result ( 0 - forever )
|
||||
# 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
|
||||
self.result_handler = on_result
|
||||
# if it is True, we can safetely execute the command
|
||||
self.canexecute = True
|
||||
self.idlequeue = None
|
||||
self.result = ''
|
||||
|
||||
|
||||
def set_idlequeue(self, idlequeue):
|
||||
self.idlequeue = idlequeue
|
||||
|
||||
|
||||
def _return_result(self):
|
||||
if self.result_handler:
|
||||
self.result_handler(self.result)
|
||||
self.result_handler = None
|
||||
|
||||
|
||||
def _compose_command_args(self):
|
||||
return ['echo', 'da']
|
||||
|
||||
|
||||
def _compose_command_line(self):
|
||||
''' return one line representation of command and its arguments '''
|
||||
return ' '.join(self._compose_command_args())
|
||||
|
||||
|
||||
def wait_child(self):
|
||||
if self.pipe.poll() is None:
|
||||
# result timeout
|
||||
|
@ -235,16 +235,16 @@ class IdleCommand(IdleObject):
|
|||
self._start_nt()
|
||||
elif os.name == 'posix':
|
||||
self._start_posix()
|
||||
|
||||
|
||||
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
|
||||
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)
|
||||
if self.commandtimeout >= 0:
|
||||
self.endtime = self.idlequeue.current_time() + self.commandtimeout
|
||||
self.idlequeue.set_alarm(self.wait_child, 0.1)
|
||||
|
||||
|
||||
def _start_posix(self):
|
||||
self.pipe = os.popen(self._compose_command_line())
|
||||
self.fd = self.pipe.fileno()
|
||||
|
@ -252,19 +252,19 @@ class IdleCommand(IdleObject):
|
|||
self.idlequeue.plug_idle(self, False, True)
|
||||
if self.commandtimeout >= 0:
|
||||
self.idlequeue.set_read_timeout(self.fd, self.commandtimeout)
|
||||
|
||||
|
||||
def end(self):
|
||||
self.idlequeue.unplug_idle(self.fd)
|
||||
try:
|
||||
self.pipe.close()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def pollend(self):
|
||||
self.idlequeue.remove_timeout(self.fd)
|
||||
self.end()
|
||||
self._return_result()
|
||||
|
||||
|
||||
def pollin(self):
|
||||
try:
|
||||
res = self.pipe.read()
|
||||
|
@ -274,15 +274,15 @@ class IdleCommand(IdleObject):
|
|||
return self.pollend()
|
||||
else:
|
||||
self.result += res
|
||||
|
||||
|
||||
def read_timeout(self):
|
||||
self.end()
|
||||
self._return_result()
|
||||
|
||||
|
||||
class NsLookup(IdleCommand):
|
||||
def __init__(self, on_result, host='_xmpp-client', type_ = 'srv'):
|
||||
IdleCommand.__init__(self, on_result)
|
||||
self.commandtimeout = 10
|
||||
self.commandtimeout = 10
|
||||
self.host = host.lower()
|
||||
self.type = type_.lower()
|
||||
if not host_pattern.match(self.host):
|
||||
|
@ -294,15 +294,15 @@ class NsLookup(IdleCommand):
|
|||
print >> sys.stderr, 'Invalid querytype: %s' % self.type
|
||||
self.canexecute = False
|
||||
return
|
||||
|
||||
|
||||
def _compose_command_args(self):
|
||||
return ['nslookup', '-type=' + self.type , self.host]
|
||||
|
||||
|
||||
def _return_result(self):
|
||||
if self.result_handler:
|
||||
self.result_handler(self.host, self.result)
|
||||
self.result_handler = None
|
||||
|
||||
|
||||
# below lines is on how to use API and assist in testing
|
||||
if __name__ == '__main__':
|
||||
if os.name == 'posix':
|
||||
|
@ -312,9 +312,9 @@ if __name__ == '__main__':
|
|||
# testing Resolver class
|
||||
import gobject
|
||||
import gtk
|
||||
|
||||
|
||||
resolver = Resolver(idlequeue)
|
||||
|
||||
|
||||
def clicked(widget):
|
||||
host = text_view.get_text()
|
||||
def on_result(host, result_array):
|
||||
|
|
|
@ -106,7 +106,7 @@ class OptionsParser:
|
|||
s += p + '.'
|
||||
s += opt
|
||||
fd.write(s + ' = ' + value + '\n')
|
||||
|
||||
|
||||
def write(self):
|
||||
(base_dir, filename) = os.path.split(self.__filename)
|
||||
self.__tempfile = os.path.join(base_dir, '.' + filename)
|
||||
|
@ -192,7 +192,7 @@ class OptionsParser:
|
|||
gajim.config.set('version', new_version)
|
||||
|
||||
gajim.capscache.load_from_db()
|
||||
|
||||
|
||||
def update_config_x_to_09(self):
|
||||
# Var name that changed:
|
||||
# avatar_width /height -> chat_avatar_width / height
|
||||
|
@ -212,7 +212,7 @@ class OptionsParser:
|
|||
d = ['accounttextcolor', 'accountbgcolor', 'accountfont',
|
||||
'accountfontattrs', 'grouptextcolor', 'groupbgcolor', 'groupfont',
|
||||
'groupfontattrs', 'contacttextcolor', 'contactbgcolor', 'contactfont',
|
||||
'contactfontattrs', 'bannertextcolor', 'bannerbgcolor', 'bannerfont',
|
||||
'contactfontattrs', 'bannertextcolor', 'bannerbgcolor', 'bannerfont',
|
||||
'bannerfontattrs']
|
||||
for theme_name in (_('grocery'), _('default')):
|
||||
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 \
|
||||
self.old_values['always_compact_view_gc'] != 'False':
|
||||
gajim.config.set('always_hide_groupchat_buttons', True)
|
||||
|
||||
|
||||
for account in gajim.config.get_per('accounts'):
|
||||
proxies_str = gajim.config.get_per('accounts', account,
|
||||
'file_transfer_proxies')
|
||||
proxies = proxies_str.split(',')
|
||||
for i in range(0, len(proxies)):
|
||||
proxies[i] = proxies[i].strip()
|
||||
for wrong_proxy in ('proxy65.jabber.autocom.pl',
|
||||
'proxy65.jabber.ccc.de'):
|
||||
for wrong_proxy in ('proxy65.jabber.autocom.pl',
|
||||
'proxy65.jabber.ccc.de'):
|
||||
if wrong_proxy in proxies:
|
||||
proxies.remove(wrong_proxy)
|
||||
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]
|
||||
con.close()
|
||||
gajim.config.set('version', '0.10.1.5')
|
||||
|
||||
|
||||
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.'''
|
||||
if 'notify_on_all_muc_messages' in self.old_values 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',
|
||||
self.old_values['ft_override_host_to_send'])
|
||||
gajim.config.set('version', '0.11.0.2')
|
||||
|
||||
|
||||
def update_config_to_01111(self):
|
||||
'''always_hide_chatbuttons -> compact_view'''
|
||||
if 'always_hide_groupchat_buttons' in self.old_values and \
|
||||
|
@ -464,7 +464,7 @@ class OptionsParser:
|
|||
d = ['accounttextcolor', 'accountbgcolor', 'accountfont',
|
||||
'accountfontattrs', 'grouptextcolor', 'groupbgcolor', 'groupfont',
|
||||
'groupfontattrs', 'contacttextcolor', 'contactbgcolor', 'contactfont',
|
||||
'contactfontattrs', 'bannertextcolor', 'bannerbgcolor', 'bannerfont',
|
||||
'contactfontattrs', 'bannertextcolor', 'bannerbgcolor', 'bannerfont',
|
||||
'bannerfontattrs']
|
||||
theme_name = _('default')
|
||||
if theme_name not in gajim.config.get_per('themes'):
|
||||
|
@ -481,7 +481,7 @@ class OptionsParser:
|
|||
for o in d:
|
||||
gajim.config.set_per('themes', theme_name, o, theme[d.index(o)])
|
||||
gajim.config.set('version', '0.11.1.4')
|
||||
|
||||
|
||||
def update_config_to_01115(self):
|
||||
# copy&pasted from update_config_to_01013, possibly 'FIXME see #2812' applies too
|
||||
back = os.getcwd()
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||
##
|
||||
|
||||
import socket
|
||||
import socket
|
||||
import struct
|
||||
import errno
|
||||
|
||||
|
@ -39,9 +39,9 @@ S_FINISHED = 4
|
|||
CONNECT_TIMEOUT = 20
|
||||
|
||||
class Proxy65Manager:
|
||||
''' keep records for file transfer proxies. Each time account
|
||||
establishes a connection to its server call proxy65manger.resolve(proxy)
|
||||
for every proxy that is convigured within the account. The class takes
|
||||
''' keep records for file transfer proxies. Each time account
|
||||
establishes a connection to its server call proxy65manger.resolve(proxy)
|
||||
for every proxy that is convigured within the account. The class takes
|
||||
care to resolve and test each proxy only once.'''
|
||||
def __init__(self, idlequeue):
|
||||
# dict {proxy: proxy properties}
|
||||
|
@ -111,9 +111,9 @@ class ProxyResolver:
|
|||
# self.sid, self.sender_jid, self._on_receiver_success,
|
||||
# self._on_connect_failure)
|
||||
#self.receiver_tester.connect()
|
||||
|
||||
|
||||
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._on_connect_failure)
|
||||
self.host_tester.connect()
|
||||
|
@ -252,7 +252,7 @@ class HostTester(Socks5, IdleObject):
|
|||
self.idlequeue.remove_timeout(self.fd)
|
||||
if self.state == 2:
|
||||
self.idlequeue.set_read_timeout(self.fd, CONNECT_TIMEOUT)
|
||||
# begin negotiation. on success 'address' != 0
|
||||
# begin negotiation. on success 'address' != 0
|
||||
buff = self.receive()
|
||||
if buff == '':
|
||||
# end connection
|
||||
|
@ -296,7 +296,7 @@ class HostTester(Socks5, IdleObject):
|
|||
self.buff = ''
|
||||
self.state = 1 # connected
|
||||
self.idlequeue.plug_idle(self, True, False)
|
||||
return
|
||||
return
|
||||
|
||||
class ReceiverTester(Socks5, IdleObject):
|
||||
''' fake proxy tester. '''
|
||||
|
@ -356,7 +356,7 @@ class ReceiverTester(Socks5, IdleObject):
|
|||
self.idlequeue.remove_timeout(self.fd)
|
||||
if self.state in (2, 3):
|
||||
self.idlequeue.set_read_timeout(self.fd, CONNECT_TIMEOUT)
|
||||
# begin negotiation. on success 'address' != 0
|
||||
# begin negotiation. on success 'address' != 0
|
||||
buff = self.receive()
|
||||
if buff == '':
|
||||
# end connection
|
||||
|
@ -408,6 +408,6 @@ class ReceiverTester(Socks5, IdleObject):
|
|||
self.buff = ''
|
||||
self.state = 1 # connected
|
||||
self.idlequeue.plug_idle(self, True, False)
|
||||
return
|
||||
return
|
||||
|
||||
# vim: se ts=3:
|
||||
|
|
|
@ -57,7 +57,7 @@ else:
|
|||
interpret_url:
|
||||
this, modulo the validated text, will be added to it
|
||||
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,
|
||||
options={}, content=[]):
|
||||
|
@ -143,7 +143,7 @@ else:
|
|||
|
||||
def create_xhtml(text):
|
||||
return Generator.create_xhtml(text)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print "test 1\n", Generator.create_xhtml("""
|
||||
|
|
|
@ -14,8 +14,8 @@ features - different stuff that didn't worths separating into modules
|
|||
browser - DISCO server framework. Allows to build dynamic disco tree.
|
||||
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
|
||||
class PlugIn so they share a single set of methods allowing you to compile
|
||||
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
|
||||
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
|
||||
methods of owner to it's own ones for easy access. All session specific info stored
|
||||
|
|
|
@ -208,7 +208,7 @@ class SASL(PlugIn):
|
|||
node=Node('response',attrs={'xmlns':NS_SASL},payload=[base64.encodestring(sasl_data[:-1]).replace('\r','').replace('\n','')])
|
||||
self._owner.send(node.__str__())
|
||||
elif 'rspauth' in chal: self._owner.send(Node('response',attrs={'xmlns':NS_SASL}).__str__())
|
||||
else:
|
||||
else:
|
||||
self.startsasl='failure'
|
||||
self.DEBUG('Failed SASL authentification: unknown challenge','error')
|
||||
raise NodeProcessed
|
||||
|
|
|
@ -50,7 +50,7 @@ def challenge_splitter(data):
|
|||
keyword, value = '', ''
|
||||
dict_ = {}
|
||||
arr = None
|
||||
|
||||
|
||||
expecting = X_KEYWORD
|
||||
for iter_ in range(len(data) + 1):
|
||||
end = False
|
||||
|
@ -104,12 +104,12 @@ class SASL(PlugIn):
|
|||
self.on_sasl = on_sasl
|
||||
self.realm = None
|
||||
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'
|
||||
elif self._owner.Dispatcher.Stream.features:
|
||||
try:
|
||||
try:
|
||||
self.FeaturesHandler(self._owner.Dispatcher, self._owner.Dispatcher.Stream.features)
|
||||
except NodeProcessed:
|
||||
except NodeProcessed:
|
||||
pass
|
||||
else: self.startsasl=None
|
||||
|
||||
|
@ -117,12 +117,12 @@ class SASL(PlugIn):
|
|||
''' 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
|
||||
two Dispatcher.Process() calls. '''
|
||||
if self.startsasl:
|
||||
if self.startsasl:
|
||||
pass
|
||||
elif self._owner.Dispatcher.Stream.features:
|
||||
try:
|
||||
try:
|
||||
self.FeaturesHandler(self._owner.Dispatcher, self._owner.Dispatcher.Stream.features)
|
||||
except NodeProcessed:
|
||||
except NodeProcessed:
|
||||
pass
|
||||
else: self._owner.RegisterHandler('features', self.FeaturesHandler, xmlns=NS_STREAMS)
|
||||
|
||||
|
@ -164,9 +164,9 @@ class SASL(PlugIn):
|
|||
self.mechanism = 'DIGEST-MD5'
|
||||
elif 'PLAIN' in self.mecs:
|
||||
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)
|
||||
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','')])
|
||||
self.mechanism = 'PLAIN'
|
||||
else:
|
||||
|
@ -179,13 +179,13 @@ class SASL(PlugIn):
|
|||
|
||||
def SASLHandler(self, conn, challenge):
|
||||
''' Perform next SASL auth step. Used internally. '''
|
||||
if challenge.getNamespace() != NS_SASL:
|
||||
if challenge.getNamespace() != NS_SASL:
|
||||
return
|
||||
if challenge.getName() == 'failure':
|
||||
self.startsasl = 'failure'
|
||||
try:
|
||||
try:
|
||||
reason = challenge.getChildren()[0]
|
||||
except Exception:
|
||||
except Exception:
|
||||
reason = challenge
|
||||
self.DEBUG('Failed SASL authentification: %s' % reason, 'error')
|
||||
if len(self.mecs) > 0:
|
||||
|
@ -244,7 +244,7 @@ class SASL(PlugIn):
|
|||
resp['nc'] = ('00000001')
|
||||
resp['qop'] = 'auth'
|
||||
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']])
|
||||
A2=C(['AUTHENTICATE',resp['digest-uri']])
|
||||
response= HH(C([HH(A1), resp['nonce'], resp['nc'], resp['cnonce'],
|
||||
|
@ -253,25 +253,25 @@ class SASL(PlugIn):
|
|||
resp['charset'] = 'utf-8'
|
||||
sasl_data=''
|
||||
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])
|
||||
else:
|
||||
else:
|
||||
sasl_data += '%s="%s",' % (key,resp[key])
|
||||
########################################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','')])
|
||||
self._owner.send(node.__str__())
|
||||
elif 'rspauth' in chal:
|
||||
elif 'rspauth' in chal:
|
||||
self._owner.send(Node('response', attrs={'xmlns':NS_SASL}).__str__())
|
||||
else:
|
||||
else:
|
||||
self.startsasl='failure'
|
||||
self.DEBUG('Failed SASL authentification: unknown challenge', 'error')
|
||||
if self.on_sasl :
|
||||
self.on_sasl ()
|
||||
raise NodeProcessed
|
||||
|
||||
|
||||
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.
|
||||
'''
|
||||
def __init__(self, user, password, resource, on_auth):
|
||||
|
@ -286,15 +286,15 @@ class NonBlockingNonSASL(PlugIn):
|
|||
def plugin(self, owner):
|
||||
''' Determine the best auth method (digest/0k/plain) and use it for auth.
|
||||
Returns used method name on success. Used internally. '''
|
||||
if not self.resource:
|
||||
if not self.resource:
|
||||
return self.authComponent(owner)
|
||||
self.DEBUG('Querying server about possible auth methods', 'start')
|
||||
self.owner = owner
|
||||
|
||||
self.owner = owner
|
||||
|
||||
owner.Dispatcher.SendAndWaitForResponse(
|
||||
Iq('get', NS_AUTH, payload=[Node('username', payload=[self.user])]), func=self._on_username
|
||||
)
|
||||
|
||||
|
||||
def _on_username(self, resp):
|
||||
if not isResultNode(resp):
|
||||
self.DEBUG('No result node arrived! Aborting...','error')
|
||||
|
@ -306,9 +306,9 @@ class NonBlockingNonSASL(PlugIn):
|
|||
|
||||
if query.getTag('digest'):
|
||||
self.DEBUG("Performing digest authentication",'ok')
|
||||
query.setTagData('digest',
|
||||
query.setTagData('digest',
|
||||
sha.new(self.owner.Dispatcher.Stream._document_attrs['id']+self.password).hexdigest())
|
||||
if query.getTag('password'):
|
||||
if query.getTag('password'):
|
||||
query.delChild('password')
|
||||
self._method='digest'
|
||||
elif query.getTag('token'):
|
||||
|
@ -330,7 +330,7 @@ class NonBlockingNonSASL(PlugIn):
|
|||
query.setTagData('password',self.password)
|
||||
self._method='plain'
|
||||
resp=self.owner.Dispatcher.SendAndWaitForResponse(iq, func=self._on_auth)
|
||||
|
||||
|
||||
def _on_auth(self, resp):
|
||||
if isResultNode(resp):
|
||||
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()]))
|
||||
owner.RegisterHandler('handshake', self.handshakeHandler, xmlns=NS_COMPONENT_ACCEPT)
|
||||
self._owner.onreceive(self._on_auth_component)
|
||||
|
||||
|
||||
def _on_auth_component(self, data):
|
||||
''' called when we receive some response, after we send the handshake '''
|
||||
if data:
|
||||
|
@ -358,25 +358,25 @@ class NonBlockingNonSASL(PlugIn):
|
|||
return
|
||||
self._owner.onreceive(None)
|
||||
self._owner._registered_name=self.user
|
||||
if self.handshake+1:
|
||||
if self.handshake+1:
|
||||
return self.on_auth('ok')
|
||||
self.on_auth(None)
|
||||
|
||||
def handshakeHandler(self,disp,stanza):
|
||||
''' Handler for registering in dispatcher for accepting transport authentication. '''
|
||||
if stanza.getName() == 'handshake':
|
||||
if stanza.getName() == 'handshake':
|
||||
self.handshake=1
|
||||
else:
|
||||
else:
|
||||
self.handshake=-1
|
||||
|
||||
|
||||
class NonBlockingBind(Bind):
|
||||
''' Bind some JID to the current connection to allow router know of our location.'''
|
||||
def plugin(self, owner):
|
||||
''' Start resource binding, if allowed at this time. Used internally. '''
|
||||
if self._owner.Dispatcher.Stream.features:
|
||||
try:
|
||||
try:
|
||||
self.FeaturesHandler(self._owner.Dispatcher, self._owner.Dispatcher.Stream.features)
|
||||
except NodeProcessed:
|
||||
except NodeProcessed:
|
||||
pass
|
||||
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). '''
|
||||
self.on_bound = on_bound
|
||||
self._resource = resource
|
||||
if self._resource:
|
||||
if self._resource:
|
||||
self._resource = [Node('resource', payload=[self._resource])]
|
||||
else:
|
||||
else:
|
||||
self._resource = []
|
||||
|
||||
|
||||
self._owner.onreceive(None)
|
||||
self._owner.Dispatcher.SendAndWaitForResponse(
|
||||
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)
|
||||
def _on_bound(self, resp):
|
||||
if isResultNode(resp):
|
||||
|
@ -405,7 +405,7 @@ class NonBlockingBind(Bind):
|
|||
jid=JID(resp.getTag('bind').getTagData('jid'))
|
||||
self._owner.User=jid.getNode()
|
||||
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)
|
||||
elif resp:
|
||||
self.DEBUG('Binding failed: %s.' % resp.getTag('error'),'error')
|
||||
|
@ -413,7 +413,7 @@ class NonBlockingBind(Bind):
|
|||
else:
|
||||
self.DEBUG('Binding failed: timeout expired.', 'error')
|
||||
self.on_bound(None)
|
||||
|
||||
|
||||
def _on_session(self, resp):
|
||||
self._owner.onreceive(None)
|
||||
if isResultNode(resp):
|
||||
|
@ -435,15 +435,15 @@ class NonBlockingBind(Bind):
|
|||
self.on_bound(None)
|
||||
|
||||
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.
|
||||
'''
|
||||
def plugin(self,owner):
|
||||
''' Start resource binding, if allowed at this time. Used internally. '''
|
||||
if self._owner.Dispatcher.Stream.features:
|
||||
try:
|
||||
try:
|
||||
self.FeaturesHandler(self._owner.Dispatcher, self._owner.Dispatcher.Stream.features)
|
||||
except NodeProcessed:
|
||||
except NodeProcessed:
|
||||
pass
|
||||
else:
|
||||
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. '''
|
||||
if self.needsUnregister:
|
||||
self._owner.UnregisterHandler('features', self.FeaturesHandler, xmlns=NS_STREAMS)
|
||||
|
||||
|
||||
def Bind(self, domain = None, on_bind = None):
|
||||
''' Perform binding. Use provided domain name (if not provided). '''
|
||||
def wrapper(resp):
|
||||
self._on_bound(resp, domain)
|
||||
self._owner.onreceive(wrapper)
|
||||
self.on_bind = on_bind
|
||||
|
||||
|
||||
def _on_bound(self, resp, domain=None):
|
||||
if resp:
|
||||
self.Dispatcher.ProcessNonBlocking(resp)
|
||||
|
@ -468,9 +468,9 @@ class NBComponentBind(ComponentBind):
|
|||
return
|
||||
self._owner.onreceive(None)
|
||||
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)
|
||||
|
||||
|
||||
def _on_bind_reponse(self, resp):
|
||||
if resp and resp.getAttr('error'):
|
||||
self.DEBUG('Binding failed: %s.' % resp.getAttr('error'), 'error')
|
||||
|
|
|
@ -128,7 +128,7 @@ class Browser(PlugIn):
|
|||
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 jid this handler will be used for all queried JIDs.
|
||||
|
||||
|
||||
Usage:
|
||||
cl.Browser.setDiscoHandler(someDict,node,jid)
|
||||
or
|
||||
|
@ -147,8 +147,8 @@ class Browser(PlugIn):
|
|||
{'category':'category1','type':'type1','name':'name1'},
|
||||
{'category':'category2','type':'type2','name':'name2'},
|
||||
{'category':'category3','type':'type3','name':'name3'},
|
||||
],
|
||||
'features':['feature1','feature2','feature3','feature4'],
|
||||
],
|
||||
'features':['feature1','feature2','feature3','feature4'],
|
||||
'xdata':DataForm
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@ class PlugIn:
|
|||
owner.__dict__[method.__name__]=method
|
||||
owner.__dict__[self.__class__.__name__]=self
|
||||
if 'plugin' in self.__class__.__dict__: return self.plugin(owner)
|
||||
|
||||
|
||||
def PlugOut(self):
|
||||
""" Unregister all our staff from main instance and detach from it. """
|
||||
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
|
||||
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.
|
||||
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'] . """
|
||||
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
|
||||
|
@ -161,7 +161,7 @@ class CommonClient:
|
|||
return self.connected
|
||||
|
||||
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).
|
||||
We will create listening socket on the same ip '''
|
||||
if hasattr(self, 'Connection'):
|
||||
|
@ -174,7 +174,7 @@ class CommonClient:
|
|||
if proxy: socket=transports.HTTPPROXYsocket(proxy,server,use_srv)
|
||||
else: socket=transports.TCPsocket(server,use_srv)
|
||||
connected=socket.PlugIn(self)
|
||||
if not connected:
|
||||
if not connected:
|
||||
socket.PlugOut()
|
||||
return
|
||||
self._Server,self._Proxy=server,proxy
|
||||
|
@ -196,7 +196,7 @@ class Client(CommonClient):
|
|||
""" Example client class, based on CommonClient. """
|
||||
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
|
||||
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.
|
||||
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.
|
||||
|
@ -265,7 +265,7 @@ class Component(CommonClient):
|
|||
Jabberd1.4 and Ejabberd use the default namespace then for all client messages.
|
||||
Jabberd2 uses jabber:client.
|
||||
'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()"."""
|
||||
CommonClient.__init__(self,server,port=port,debug=debug)
|
||||
self.typ=typ
|
||||
|
@ -274,7 +274,7 @@ class Component(CommonClient):
|
|||
self.domains=domains
|
||||
else:
|
||||
self.domains=[server]
|
||||
|
||||
|
||||
def connect(self,server=None,proxy=None):
|
||||
""" 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.
|
||||
|
|
|
@ -28,28 +28,28 @@ from client import *
|
|||
|
||||
class NBCommonClient(CommonClient):
|
||||
''' 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):
|
||||
''' 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"
|
||||
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'] . '''
|
||||
|
||||
if isinstance(self, NonBlockingClient):
|
||||
|
||||
if isinstance(self, NonBlockingClient):
|
||||
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.defaultNamespace = self.Namespace
|
||||
self.disconnect_handlers = []
|
||||
self.Server = server
|
||||
self.Port = port
|
||||
|
||||
|
||||
# Who initiated this client
|
||||
# Used to register the EventDispatcher
|
||||
self._caller = caller
|
||||
if debug and not isinstance(debug, list):
|
||||
if debug and not isinstance(debug, list):
|
||||
debug = ['always', 'nodebuilder']
|
||||
self._DEBUG = Debug.Debug(debug)
|
||||
self.DEBUG = self._DEBUG.Show
|
||||
|
@ -64,10 +64,10 @@ class NBCommonClient(CommonClient):
|
|||
self.on_connect = on_connect
|
||||
self.on_proxy_failure = on_proxy_failure
|
||||
self.on_connect_failure = on_connect_failure
|
||||
|
||||
|
||||
def set_idlequeue(self, idlequeue):
|
||||
self.idlequeue = idlequeue
|
||||
|
||||
|
||||
def disconnected(self):
|
||||
''' Called on disconnection. Calls disconnect handlers and cleans things up. '''
|
||||
self.connected=''
|
||||
|
@ -90,15 +90,15 @@ class NBCommonClient(CommonClient):
|
|||
self.NBSOCKS5PROXYsocket.PlugOut()
|
||||
if 'NonBlockingTcp' in self.__dict__:
|
||||
self.NonBlockingTcp.PlugOut()
|
||||
|
||||
|
||||
def reconnectAndReauth(self):
|
||||
''' Just disconnect. We do reconnecting in connection.py '''
|
||||
self.disconnect()
|
||||
return ''
|
||||
return ''
|
||||
|
||||
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. '''
|
||||
if not server:
|
||||
if not server:
|
||||
server = (self.Server, self.Port)
|
||||
self._Server, self._Proxy, self._Ssl = server , proxy, ssl
|
||||
self.on_stream_start = on_stream_start
|
||||
|
@ -117,22 +117,22 @@ class NBCommonClient(CommonClient):
|
|||
self.socket = transports_nb.NBHTTPPROXYsocket(self._on_connected,
|
||||
self._on_proxy_failure, self._on_connected_failure, proxy,
|
||||
server)
|
||||
else:
|
||||
else:
|
||||
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.socket.PlugIn(self)
|
||||
return True
|
||||
|
||||
|
||||
def get_attrs(self, on_stream_start):
|
||||
self.on_stream_start = on_stream_start
|
||||
self.onreceive(self._on_receive_document_attrs)
|
||||
|
||||
def _on_proxy_failure(self, reason):
|
||||
def _on_proxy_failure(self, reason):
|
||||
if self.on_proxy_failure:
|
||||
self.on_proxy_failure(reason)
|
||||
|
||||
def _on_connected_failure(self, retry = None):
|
||||
def _on_connected_failure(self, retry = None):
|
||||
if self.socket:
|
||||
self.socket.disconnect()
|
||||
if self.on_connect_failure:
|
||||
|
@ -143,7 +143,7 @@ class NBCommonClient(CommonClient):
|
|||
# in nonblocking mode, and this handler is actually called
|
||||
# as soon as connection is initiated, NOT when connection
|
||||
# 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.connected = 'tcp'
|
||||
if self._Ssl:
|
||||
|
@ -153,7 +153,7 @@ class NBCommonClient(CommonClient):
|
|||
self.connected = 'ssl'
|
||||
self.onreceive(self._on_receive_document_attrs)
|
||||
dispatcher_nb.Dispatcher().PlugIn(self)
|
||||
|
||||
|
||||
def _on_receive_document_attrs(self, data):
|
||||
if data:
|
||||
self.Dispatcher.ProcessNonBlocking(data)
|
||||
|
@ -169,11 +169,11 @@ class NBCommonClient(CommonClient):
|
|||
self.on_stream_start()
|
||||
self.on_stream_start = None
|
||||
return True
|
||||
|
||||
|
||||
def _on_receive_stream_features(self, data):
|
||||
if data:
|
||||
self.Dispatcher.ProcessNonBlocking(data)
|
||||
if not self.Dispatcher.Stream.features:
|
||||
if not self.Dispatcher.Stream.features:
|
||||
return
|
||||
# pass # If we get version 1.0 stream the features tag MUST BE presented
|
||||
self.onreceive(None)
|
||||
|
@ -181,12 +181,12 @@ class NBCommonClient(CommonClient):
|
|||
self.on_stream_start()
|
||||
self.on_stream_start = None
|
||||
return True
|
||||
|
||||
|
||||
class NonBlockingClient(NBCommonClient):
|
||||
''' Example client class, based on CommonClient. '''
|
||||
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
|
||||
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.
|
||||
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.
|
||||
|
@ -195,18 +195,18 @@ class NonBlockingClient(NBCommonClient):
|
|||
Returns '' or 'tcp' or 'tls', depending on the result.'''
|
||||
self.__secure = secure
|
||||
self.Connection = None
|
||||
NBCommonClient.connect(self, server = server, proxy = proxy, ssl = secure,
|
||||
on_stream_start = self._on_tcp_stream_start)
|
||||
NBCommonClient.connect(self, server = server, proxy = proxy, ssl = secure,
|
||||
on_stream_start = self._on_tcp_stream_start)
|
||||
return self.connected
|
||||
|
||||
|
||||
|
||||
|
||||
def _is_connected(self):
|
||||
self.onreceive(None)
|
||||
if self.on_connect:
|
||||
self.on_connect(self, self.connected)
|
||||
self.on_connect_failure = None
|
||||
self.on_connect = None
|
||||
|
||||
|
||||
def _on_tcp_stream_start(self):
|
||||
if not self.connected or self.__secure is not None and not self.__secure:
|
||||
self._is_connected()
|
||||
|
@ -217,12 +217,12 @@ class NonBlockingClient(NBCommonClient):
|
|||
if not self.Connection: # ssl error, stream is closed
|
||||
return True
|
||||
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()
|
||||
return
|
||||
if not self.Dispatcher.Stream.features.getTag('starttls'):
|
||||
if not self.Dispatcher.Stream.features.getTag('starttls'):
|
||||
self._is_connected()
|
||||
return
|
||||
return
|
||||
self.onreceive(self._on_receive_starttls)
|
||||
|
||||
def _on_receive_starttls(self, data):
|
||||
|
@ -231,7 +231,7 @@ class NonBlockingClient(NBCommonClient):
|
|||
if not self.NonBlockingTLS.starttls:
|
||||
return
|
||||
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._is_connected()
|
||||
return
|
||||
|
@ -239,7 +239,7 @@ class NonBlockingClient(NBCommonClient):
|
|||
self.onreceive(None)
|
||||
self._is_connected()
|
||||
return True
|
||||
|
||||
|
||||
def auth(self, user, password, resource = '', sasl = 1, on_auth = None):
|
||||
''' Authenticate connnection and bind resource. If resource is not provided
|
||||
random one or library name used. '''
|
||||
|
@ -247,7 +247,7 @@ class NonBlockingClient(NBCommonClient):
|
|||
self.on_auth = on_auth
|
||||
self.get_attrs(self._on_doc_attrs)
|
||||
return
|
||||
|
||||
|
||||
def _on_old_auth(self, res):
|
||||
if res:
|
||||
self.connected += '+old_auth'
|
||||
|
@ -256,27 +256,27 @@ class NonBlockingClient(NBCommonClient):
|
|||
self.on_auth(self, None)
|
||||
|
||||
def _on_doc_attrs(self):
|
||||
if self._sasl:
|
||||
if self._sasl:
|
||||
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._Resource:
|
||||
if not self._Resource:
|
||||
self._Resource = 'xmpppy'
|
||||
auth_nb.NonBlockingNonSASL(self._User, self._Password, self._Resource, self._on_old_auth).PlugIn(self)
|
||||
return
|
||||
self.onreceive(self._on_start_sasl)
|
||||
self.SASL.auth()
|
||||
return True
|
||||
|
||||
|
||||
def _on_start_sasl(self, data=None):
|
||||
if data:
|
||||
self.Dispatcher.ProcessNonBlocking(data)
|
||||
if 'SASL' not in self.__dict__:
|
||||
# SASL is pluged out, possible disconnect
|
||||
if 'SASL' not in self.__dict__:
|
||||
# SASL is pluged out, possible disconnect
|
||||
return
|
||||
if self.SASL.startsasl == 'in-process':
|
||||
if self.SASL.startsasl == 'in-process':
|
||||
return
|
||||
self.onreceive(None)
|
||||
if self.SASL.startsasl == 'failure':
|
||||
if self.SASL.startsasl == 'failure':
|
||||
# wrong user/pass, stop auth
|
||||
self.connected = None
|
||||
self._on_sasl_auth(None)
|
||||
|
@ -285,16 +285,16 @@ class NonBlockingClient(NBCommonClient):
|
|||
auth_nb.NonBlockingBind().PlugIn(self)
|
||||
self.onreceive(self._on_auth_bind)
|
||||
return True
|
||||
|
||||
|
||||
def _on_auth_bind(self, data):
|
||||
if data:
|
||||
self.Dispatcher.ProcessNonBlocking(data)
|
||||
if not hasattr(self, 'NonBlockingBind') or self.NonBlockingBind.bound is \
|
||||
None:
|
||||
None:
|
||||
return
|
||||
self.NonBlockingBind.NonBlockingBind(self._Resource, self._on_sasl_auth)
|
||||
return True
|
||||
|
||||
|
||||
def _on_sasl_auth(self, res):
|
||||
self.onreceive(None)
|
||||
if res:
|
||||
|
@ -302,10 +302,10 @@ class NonBlockingClient(NBCommonClient):
|
|||
self.on_auth(self, 'sasl')
|
||||
else:
|
||||
self.on_auth(self, None)
|
||||
|
||||
|
||||
def initRoster(self):
|
||||
''' Plug in the roster. '''
|
||||
if 'NonBlockingRoster' not in self.__dict__:
|
||||
if 'NonBlockingRoster' not in self.__dict__:
|
||||
roster_nb.NonBlockingRoster().PlugIn(self)
|
||||
|
||||
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.
|
||||
Jabberd2 uses jabber:client.
|
||||
'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()".'''
|
||||
NBCommonClient.__init__(self, server, port=port, debug=debug)
|
||||
self.typ = typ
|
||||
|
@ -341,7 +341,7 @@ class Component(NBCommonClient):
|
|||
self.domains=[server]
|
||||
self.on_connect_component = on_connect
|
||||
self.on_connect_failure = on_connect_failure
|
||||
|
||||
|
||||
def connect(self, server=None, proxy=None):
|
||||
''' 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.
|
||||
|
@ -349,9 +349,9 @@ class Component(NBCommonClient):
|
|||
if self.component:
|
||||
self.Namespace=auth.NS_COMPONENT_1
|
||||
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)
|
||||
|
||||
|
||||
def _on_connect(self):
|
||||
if self.typ=='jabberd2' or not self.typ and self.Dispatcher.Stream.features is not None:
|
||||
self.defaultNamespace=auth.NS_CLIENT
|
||||
|
@ -365,9 +365,9 @@ class Component(NBCommonClient):
|
|||
''' Authenticate component "name" with password "password".'''
|
||||
self._User, self._Password, self._Resource=name, password,''
|
||||
try:
|
||||
if self.component:
|
||||
if self.component:
|
||||
sasl=1
|
||||
if sasl:
|
||||
if sasl:
|
||||
auth.SASL(name,password).PlugIn(self)
|
||||
if not sasl or self.SASL.startsasl=='not-supported':
|
||||
if auth.NonSASL(name,password,'').PlugIn(self):
|
||||
|
@ -378,11 +378,11 @@ class Component(NBCommonClient):
|
|||
self.onreceive(self._on_auth_component)
|
||||
except Exception:
|
||||
self.DEBUG(self.DBG,"Failed to authenticate %s" % name,'error')
|
||||
|
||||
|
||||
def _on_auth_component(self, data):
|
||||
if data:
|
||||
self.Dispatcher.ProcessNonBlocking(data)
|
||||
if self.SASL.startsasl == 'in-process':
|
||||
if self.SASL.startsasl == 'in-process':
|
||||
return
|
||||
if self.SASL.startsasl =='success':
|
||||
if self.component:
|
||||
|
@ -392,18 +392,18 @@ class Component(NBCommonClient):
|
|||
self.connected += '+sasl'
|
||||
else:
|
||||
raise auth.NotAuthorized(self.SASL.startsasl)
|
||||
|
||||
|
||||
def _on_component_bind(self, data):
|
||||
if data:
|
||||
self.Dispatcher.ProcessNonBlocking(data)
|
||||
if self.NBComponentBind.bound is None:
|
||||
if self.NBComponentBind.bound is None:
|
||||
return
|
||||
|
||||
|
||||
for domain in self.domains:
|
||||
self.NBComponentBind.Bind(domain, _on_component_bound)
|
||||
|
||||
|
||||
def _on_component_bound(self, resp):
|
||||
self.NBComponentBind.PlugOut()
|
||||
|
||||
|
||||
|
||||
# vim: se ts=3:
|
||||
|
|
|
@ -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.
|
||||
|
||||
To use this module:
|
||||
|
||||
|
||||
Instansiate the module with the parent transport and disco browser manager as parameters.
|
||||
'Plug in' commands using the command template.
|
||||
The command feature must be added to existing disco replies where neccessary.
|
||||
|
||||
|
||||
What it supplies:
|
||||
|
||||
|
||||
Automatic command registration with the disco browser manager.
|
||||
Automatic listing of commands in the public command list.
|
||||
A means of handling requests, by redirection though the command manager.
|
||||
|
@ -39,9 +39,9 @@ DBG_COMMANDS = 'commands'
|
|||
|
||||
class Commands(PlugIn):
|
||||
"""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:
|
||||
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.
|
||||
|
@ -53,7 +53,7 @@ class Commands(PlugIn):
|
|||
self._exported_methods=[]
|
||||
self._handlers={'':{}}
|
||||
self._browser = browser
|
||||
|
||||
|
||||
def plugin(self, owner):
|
||||
"""Makes handlers within the session"""
|
||||
# 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='get',ns=NS_COMMANDS)
|
||||
self._browser.setDiscoHandler(self._DiscoHandler,node=NS_COMMANDS,jid='')
|
||||
owner.debug_flags.append(DBG_COMMANDS)
|
||||
|
||||
owner.debug_flags.append(DBG_COMMANDS)
|
||||
|
||||
def plugout(self):
|
||||
"""Removes handlers from the session"""
|
||||
# unPlug from the session and the disco manager
|
||||
self._owner.UnregisterHandler('iq',self._CommandHandler,ns=NS_COMMANDS)
|
||||
for jid in self._handlers:
|
||||
self._browser.delDiscoHandler(self._DiscoHandler,node=NS_COMMANDS,jid=jid)
|
||||
|
||||
|
||||
def _CommandHandler(self,conn,request):
|
||||
"""The internal method to process the routing of command execution requests"""
|
||||
# This is the command handler itself.
|
||||
|
@ -93,7 +93,7 @@ class Commands(PlugIn):
|
|||
else:
|
||||
conn.send(Error(request,ERR_ITEM_NOT_FOUND))
|
||||
raise NodeProcessed
|
||||
|
||||
|
||||
def _DiscoHandler(self,conn,request,typ):
|
||||
"""The internal method to process service discovery requests"""
|
||||
# This is the disco manager handler.
|
||||
|
@ -130,7 +130,7 @@ class Commands(PlugIn):
|
|||
raise NodeProcessed
|
||||
elif typ == 'info':
|
||||
return {'ids':[{'category':'automation','type':'command-list'}],'features':[]}
|
||||
|
||||
|
||||
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"""
|
||||
# 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}
|
||||
# Need to add disco stuff here
|
||||
self._browser.setDiscoHandler(cmddisco,node=name,jid=jid)
|
||||
|
||||
|
||||
def delCommand(self,name,jid=''):
|
||||
"""Removed command from the session"""
|
||||
# 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']
|
||||
del self._handlers[jid][name]
|
||||
self._browser.delDiscoHandler(command,node=name,jid=jid)
|
||||
|
||||
|
||||
def getCommand(self,name,jid=''):
|
||||
"""Returns the command tuple"""
|
||||
# This gets the command object with name
|
||||
|
@ -174,19 +174,19 @@ class Commands(PlugIn):
|
|||
raise NameError,'Command not found'
|
||||
else:
|
||||
return self._handlers[jid][name]
|
||||
|
||||
|
||||
class Command_Handler_Prototype(PlugIn):
|
||||
"""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
|
||||
my first attempt at making a generic handler that you can hang process
|
||||
"""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
|
||||
my first attempt at making a generic handler that you can hang process
|
||||
stages on too. There is an example command below.
|
||||
|
||||
|
||||
The parameters are as follows:
|
||||
name : the name of the command within the jabber environment
|
||||
description : the natural language description
|
||||
discofeatures : the features supported by the command
|
||||
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.
|
||||
"""
|
||||
name = 'examplecommand'
|
||||
|
@ -203,14 +203,14 @@ class Command_Handler_Prototype(PlugIn):
|
|||
# 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._jid = jid
|
||||
|
||||
|
||||
def plugin(self,owner):
|
||||
"""Plug command into the commands class"""
|
||||
# The owner in this instance is the Command Processor
|
||||
self._commands = owner
|
||||
self._owner = owner._owner
|
||||
self._commands.addCommand(self.name,self._DiscoHandler,self.Execute,jid=self._jid)
|
||||
|
||||
|
||||
def plugout(self):
|
||||
"""Remove command from the commands class"""
|
||||
self._commands.delCommand(name,self._jid)
|
||||
|
@ -219,7 +219,7 @@ class Command_Handler_Prototype(PlugIn):
|
|||
"""Returns an id for the command session"""
|
||||
self.count = self.count+1
|
||||
return 'cmd-%s-%d'%(self.name,self.count)
|
||||
|
||||
|
||||
def Execute(self,conn,request):
|
||||
"""The method that handles all the commands, and routes them to the correct method for that stage."""
|
||||
# New request or old?
|
||||
|
@ -254,7 +254,7 @@ class Command_Handler_Prototype(PlugIn):
|
|||
else:
|
||||
# New session
|
||||
self.initial[action](conn,request)
|
||||
|
||||
|
||||
def _DiscoHandler(self,conn,request,type_):
|
||||
"""The handler for discovery events"""
|
||||
if type_ == 'list':
|
||||
|
@ -263,9 +263,9 @@ class Command_Handler_Prototype(PlugIn):
|
|||
return []
|
||||
elif type_ == 'info':
|
||||
return self.discoinfo
|
||||
|
||||
|
||||
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.
|
||||
"""
|
||||
name = 'testcommand'
|
||||
|
@ -275,7 +275,7 @@ class TestCommand(Command_Handler_Prototype):
|
|||
Command_Handler_Prototype.__init__(self,jid)
|
||||
self.pi = 3.14
|
||||
self.initial = {'execute':self.cmdFirstStage}
|
||||
|
||||
|
||||
def cmdFirstStage(self,conn,request):
|
||||
""" Determine """
|
||||
# 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}
|
||||
# The form generation is split out to another method as it may be called by cmdThirdStage
|
||||
self.cmdSecondStageReply(conn,request)
|
||||
|
||||
|
||||
def cmdSecondStageReply(self,conn,request):
|
||||
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')])
|
||||
|
@ -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)
|
||||
self._owner.send(reply)
|
||||
raise NodeProcessed
|
||||
|
||||
|
||||
def cmdThirdStage(self,conn,request):
|
||||
form = DataForm(node = result.getTag(name='command').getTag(name='x',namespace=NS_DATA))
|
||||
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)
|
||||
self._owner.send(reply)
|
||||
raise NodeProcessed
|
||||
|
||||
|
||||
def cmdCancel(self,conn,request):
|
||||
reply = request.buildReply('result')
|
||||
reply.addChild(name='command',attrs={'xmlns':NS_COMMAND,'node':request.getTagAttr('command','node'),'sessionid':request.getTagAttr('command','sessionid'),'status':'cancelled'})
|
||||
self._owner.send(reply)
|
||||
del self.sessions[request.getTagAttr('command','sessionid')]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# vim: se ts=3:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
## debug.py
|
||||
## debug.py
|
||||
##
|
||||
## 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
|
||||
|
||||
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.
|
||||
|
||||
flags can be numeric, but that makes analysing harder, on creation its
|
||||
|
@ -104,12 +104,12 @@ class NoDebug:
|
|||
pass
|
||||
def active_set( self, active_flags = None ):
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
LINE_FEED = '\n'
|
||||
|
||||
|
||||
class Debug:
|
||||
class Debug:
|
||||
def __init__( self,
|
||||
#
|
||||
# active_flags are those that will trigger output
|
||||
|
@ -128,7 +128,7 @@ class Debug:
|
|||
prefix = 'DEBUG: ',
|
||||
sufix = '\n',
|
||||
#
|
||||
# If you want unix style timestamps,
|
||||
# If you want unix style timestamps,
|
||||
# 0 disables timestamps
|
||||
# 1 before prefix, good when prefix is a string
|
||||
# 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
|
||||
# good view of what flags are actually used for calls,
|
||||
# if it is not None, it should be a string
|
||||
# flags for current call will be displayed
|
||||
# with flag_show as separator
|
||||
# flags for current call will be displayed
|
||||
# with flag_show as separator
|
||||
# recomended values vould be '-' or ':', but any string goes
|
||||
#
|
||||
flag_show = None,
|
||||
|
@ -153,14 +153,14 @@ class Debug:
|
|||
# default is to show welcome if any flags are active
|
||||
welcome = -1
|
||||
):
|
||||
|
||||
|
||||
self.debug_flags = []
|
||||
if welcome == -1:
|
||||
if active_flags and len(active_flags):
|
||||
welcome = 1
|
||||
else:
|
||||
welcome = 0
|
||||
|
||||
|
||||
self._remove_dupe_flags()
|
||||
if log_file:
|
||||
if isinstance(log_file, str):
|
||||
|
@ -173,7 +173,7 @@ class Debug:
|
|||
self._fh = log_file
|
||||
else:
|
||||
self._fh = sys.stdout
|
||||
|
||||
|
||||
if time_stamp not in (0,1,2):
|
||||
raise Exception('Invalid time_stamp param "%s"' % str(time_stamp))
|
||||
self.prefix = prefix
|
||||
|
@ -206,18 +206,18 @@ class Debug:
|
|||
flag can be of folowing types:
|
||||
None - this msg will always be shown if any debugging is on
|
||||
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
|
||||
|
||||
if prefix / sufix are not given, default ones from init will be used
|
||||
|
||||
|
||||
lf = -1 means strip linefeed if pressent
|
||||
lf = 1 means add linefeed if not pressent
|
||||
"""
|
||||
|
||||
|
||||
if self.validate_flags:
|
||||
self._validate_flag( flag )
|
||||
|
||||
|
||||
if not self.is_active(flag):
|
||||
return
|
||||
if prefix:
|
||||
|
@ -241,7 +241,7 @@ class Debug:
|
|||
)
|
||||
else:
|
||||
output = pre
|
||||
|
||||
|
||||
if self.flag_show:
|
||||
if flag:
|
||||
output = '%s%s%s' % ( output, flag, self.flag_show )
|
||||
|
@ -271,7 +271,7 @@ class Debug:
|
|||
s=s+c
|
||||
self._fh.write( '%s%s%s' % ( pre, s, suf ))
|
||||
self._fh.flush()
|
||||
|
||||
|
||||
def active_set( self, active_flags = None ):
|
||||
"returns 1 if any flags where actually set, otherwise 0."
|
||||
r = 0
|
||||
|
@ -285,7 +285,7 @@ class Debug:
|
|||
if t not in self.debug_flags:
|
||||
print 'Invalid debugflag given', t
|
||||
ok_flags.append( t )
|
||||
|
||||
|
||||
self.active = ok_flags
|
||||
r = 1
|
||||
else:
|
||||
|
@ -298,7 +298,7 @@ class Debug:
|
|||
self.show( '*** please correct your param!' )
|
||||
self.show( '*** due to this, full debuging is enabled' )
|
||||
self.active = self.debug_flags
|
||||
|
||||
|
||||
for f in flags:
|
||||
s = f.strip()
|
||||
ok_flags.append( s )
|
||||
|
@ -306,15 +306,15 @@ class Debug:
|
|||
|
||||
self._remove_dupe_flags()
|
||||
return r
|
||||
|
||||
|
||||
def active_get( self ):
|
||||
"returns currently active flags."
|
||||
return self.active
|
||||
|
||||
|
||||
|
||||
|
||||
def _as_one_list( self, items ):
|
||||
""" init param might contain nested lists, typically from group flags.
|
||||
|
||||
|
||||
This code organises lst and remves dupes
|
||||
"""
|
||||
if not isinstance(items, (list, tuple)):
|
||||
|
@ -323,15 +323,15 @@ class Debug:
|
|||
for l in items:
|
||||
if isinstance(l, list):
|
||||
lst2 = self._as_one_list( l )
|
||||
for l2 in lst2:
|
||||
for l2 in lst2:
|
||||
self._append_unique_str(r, l2 )
|
||||
elif l is None:
|
||||
continue
|
||||
else:
|
||||
self._append_unique_str(r, l )
|
||||
return r
|
||||
|
||||
|
||||
|
||||
|
||||
def _append_unique_str( self, lst, item ):
|
||||
"""filter out any dupes."""
|
||||
if not isinstance(item, str):
|
||||
|
@ -342,7 +342,7 @@ class Debug:
|
|||
lst.append( item )
|
||||
return lst
|
||||
|
||||
|
||||
|
||||
def _validate_flag( self, flags ):
|
||||
'verify that flag is defined.'
|
||||
if flags:
|
||||
|
@ -353,7 +353,7 @@ class Debug:
|
|||
|
||||
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
|
||||
"""
|
||||
unique_flags = []
|
||||
|
@ -371,12 +371,12 @@ class Debug:
|
|||
if not colors_enabled: prefixcolor=''
|
||||
elif flag in self.colors: prefixcolor=self.colors[flag]
|
||||
else: prefixcolor=color_none
|
||||
|
||||
|
||||
if prefix=='error':
|
||||
_exception = sys.exc_info()
|
||||
if _exception[0]:
|
||||
msg=msg+'\n'+''.join(traceback.format_exception(_exception[0], _exception[1], _exception[2])).rstrip()
|
||||
|
||||
|
||||
prefix= self.prefix+prefixcolor+(flag+' '*12)[:12]+' '+(prefix+' '*6)[:6]
|
||||
self.show(msg, flag, prefix)
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
"""
|
||||
Main xmpppy mechanism. Provides library with methods to assign different handlers
|
||||
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.
|
||||
"""
|
||||
|
||||
|
@ -135,7 +135,7 @@ class Dispatcher(PlugIn):
|
|||
raise _pendingException[0], _pendingException[1], _pendingException[2]
|
||||
return len(data)
|
||||
return '0' # It means that nothing is received but link is alive.
|
||||
|
||||
|
||||
def RegisterNamespace(self,xmlns,order='info'):
|
||||
""" Creates internal structures for newly registered 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):
|
||||
""" 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".
|
||||
3) data that comes along with event. Depends on event."""
|
||||
if self._eventHandler: self._eventHandler(realm,event,data)
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
'''
|
||||
Main xmpppy mechanism. Provides library with methods to assign different handlers
|
||||
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.
|
||||
'''
|
||||
|
||||
|
@ -59,7 +59,7 @@ class Dispatcher(PlugIn):
|
|||
''' Return set of user-registered callbacks in it's internal format.
|
||||
Used within the library to carry user handlers set over Dispatcher replugins. '''
|
||||
return self.handlers
|
||||
|
||||
|
||||
def restoreHandlers(self, handlers):
|
||||
''' Restores user-registered callbacks structure from dump previously obtained via dumpHandlers.
|
||||
Used within the library to carry user handlers set over Dispatcher replugins. '''
|
||||
|
@ -76,7 +76,7 @@ class Dispatcher(PlugIn):
|
|||
self.RegisterDefaultHandler(self.returnStanzaHandler)
|
||||
self.RegisterEventHandler(self._owner._caller._event_dispatcher)
|
||||
self.on_responses = {}
|
||||
|
||||
|
||||
def plugin(self, owner):
|
||||
''' Plug the Dispatcher instance into Client class instance and send initial stream header. Used internally.'''
|
||||
self._init()
|
||||
|
@ -87,7 +87,7 @@ class Dispatcher(PlugIn):
|
|||
self._owner.StreamInit()
|
||||
else:
|
||||
self.StreamInit()
|
||||
|
||||
|
||||
def plugout(self):
|
||||
''' Prepares instance to be destructed. '''
|
||||
self.Stream.dispatch = None
|
||||
|
@ -126,7 +126,7 @@ class Dispatcher(PlugIn):
|
|||
1) length of processed data if some data were processed;
|
||||
2) '0' string if no data were processed but link is alive;
|
||||
3) 0 (zero) if underlying connection is closed.'''
|
||||
for handler in self._cycleHandlers:
|
||||
for handler in self._cycleHandlers:
|
||||
handler(self)
|
||||
if len(self._pendingExceptions) > 0:
|
||||
_pendingException = self._pendingExceptions.pop()
|
||||
|
@ -150,7 +150,7 @@ class Dispatcher(PlugIn):
|
|||
raise _pendingException[0], _pendingException[1], _pendingException[2]
|
||||
if len(data) == 0: return '0'
|
||||
return len(data)
|
||||
|
||||
|
||||
def RegisterNamespace(self, xmlns, order='info'):
|
||||
''' Creates internal structures for newly registered 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.
|
||||
"system" - call handler even if NodeProcessed Exception were raised already.
|
||||
'''
|
||||
if not xmlns:
|
||||
if not xmlns:
|
||||
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')
|
||||
if not typ and not ns:
|
||||
if not typ and not ns:
|
||||
typ='default'
|
||||
if xmlns not in self.handlers:
|
||||
if xmlns not in self.handlers:
|
||||
self.RegisterNamespace(xmlns,'warn')
|
||||
if name not in self.handlers[xmlns]:
|
||||
if name not in self.handlers[xmlns]:
|
||||
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]=[]
|
||||
if makefirst:
|
||||
if makefirst:
|
||||
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})
|
||||
|
||||
def RegisterHandlerOnce(self,name,handler,typ='',ns='',xmlns=None,makefirst=0, system=0):
|
||||
''' Unregister handler after first call (not implemented yet). '''
|
||||
if not xmlns:
|
||||
if not xmlns:
|
||||
xmlns=self._owner.defaultNamespace
|
||||
self.RegisterHandler(name, handler, typ, ns, xmlns, makefirst, system)
|
||||
|
||||
def UnregisterHandler(self, name, handler, typ='', ns='', xmlns=None):
|
||||
''' Unregister handler. "typ" and "ns" must be specified exactly the same as with registering.'''
|
||||
if not xmlns:
|
||||
if not xmlns:
|
||||
xmlns=self._owner.defaultNamespace
|
||||
if not typ and not ns:
|
||||
if not typ and not ns:
|
||||
typ='default'
|
||||
if xmlns not in self.handlers:
|
||||
return
|
||||
if name not in self.handlers[xmlns]:
|
||||
if name not in self.handlers[xmlns]:
|
||||
return
|
||||
if typ+ns not in self.handlers[xmlns][name]:
|
||||
if typ+ns not in self.handlers[xmlns][name]:
|
||||
return
|
||||
for pack in self.handlers[xmlns][name][typ+ns]:
|
||||
if pack['func'] == handler:
|
||||
try:
|
||||
if pack['func'] == handler:
|
||||
try:
|
||||
self.handlers[xmlns][name][typ+ns].remove(pack)
|
||||
except ValueError:
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
def RegisterDefaultHandler(self,handler):
|
||||
|
@ -251,29 +251,29 @@ class Dispatcher(PlugIn):
|
|||
name,text='error',error.getData()
|
||||
for tag in error.getChildren():
|
||||
if tag.getNamespace()==NS_XMPP_STREAMS:
|
||||
if tag.getName()=='text':
|
||||
if tag.getName()=='text':
|
||||
text=tag.getData()
|
||||
else:
|
||||
else:
|
||||
name=tag.getName()
|
||||
if name in stream_exceptions.keys():
|
||||
if name in stream_exceptions.keys():
|
||||
exc=stream_exceptions[name]
|
||||
else:
|
||||
else:
|
||||
exc=StreamError
|
||||
raise exc((name,text))
|
||||
|
||||
def RegisterCycleHandler(self, handler):
|
||||
''' 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)
|
||||
|
||||
def UnregisterCycleHandler(self, handler):
|
||||
''' 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)
|
||||
|
||||
|
||||
def Event(self, realm, event, data):
|
||||
''' 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".
|
||||
3) data that comes along with event. Depends on event.'''
|
||||
if self._eventHandler: self._eventHandler(realm,event,data)
|
||||
|
@ -281,7 +281,7 @@ class Dispatcher(PlugIn):
|
|||
def dispatch(self, stanza, session=None, direct=0):
|
||||
''' Main procedure that performs XMPP stanza recognition and calling apppropriate handlers for it.
|
||||
Called internally. '''
|
||||
if not session:
|
||||
if not session:
|
||||
session = self
|
||||
session.Stream._mini_dom = None
|
||||
name = stanza.getName()
|
||||
|
@ -302,10 +302,10 @@ class Dispatcher(PlugIn):
|
|||
pass
|
||||
else:
|
||||
raise UnsupportedStanzaType(name)
|
||||
|
||||
if name=='features':
|
||||
|
||||
if name=='features':
|
||||
session.Stream.features=stanza
|
||||
|
||||
|
||||
xmlns=stanza.getNamespace()
|
||||
if xmlns not in self.handlers:
|
||||
self.DEBUG("Unknown namespace: " + xmlns, 'warn')
|
||||
|
@ -316,38 +316,38 @@ class Dispatcher(PlugIn):
|
|||
else:
|
||||
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)
|
||||
|
||||
|
||||
typ=stanza.getType()
|
||||
if not typ: typ=''
|
||||
stanza.props=stanza.getProperties()
|
||||
ID=stanza.getID()
|
||||
|
||||
|
||||
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:
|
||||
if typ in self.handlers[xmlns][name]: list_.append(typ) # from very common...
|
||||
for prop in stanza.props:
|
||||
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
|
||||
|
||||
|
||||
chain=self.handlers[xmlns]['default']['default']
|
||||
for key in list_:
|
||||
if key: chain = chain + self.handlers[xmlns][name][key]
|
||||
|
||||
|
||||
if ID in session._expected:
|
||||
user=0
|
||||
if isinstance(session._expected[ID], tuple):
|
||||
cb,args = session._expected[ID]
|
||||
session.DEBUG("Expected stanza arrived. Callback %s(%s) found!" % (cb, args), 'ok')
|
||||
try:
|
||||
try:
|
||||
cb(session,stanza,**args)
|
||||
except Exception, typ:
|
||||
if typ.__class__.__name__ !='NodeProcessed': raise
|
||||
else:
|
||||
session.DEBUG("Expected stanza arrived!",'ok')
|
||||
session._expected[ID]=stanza
|
||||
else:
|
||||
else:
|
||||
user=1
|
||||
for handler in chain:
|
||||
if user or handler['system']:
|
||||
|
@ -358,9 +358,9 @@ class Dispatcher(PlugIn):
|
|||
self._pendingExceptions.insert(0, sys.exc_info())
|
||||
return
|
||||
user=0
|
||||
if user and self._defaultHandler:
|
||||
if user and self._defaultHandler:
|
||||
self._defaultHandler(session, stanza)
|
||||
|
||||
|
||||
def WaitForData(self, data):
|
||||
if data is None:
|
||||
return
|
||||
|
@ -382,10 +382,10 @@ class Dispatcher(PlugIn):
|
|||
else:
|
||||
resp(self._owner, self._expected[self._witid], **args)
|
||||
del self._expected[i]
|
||||
|
||||
|
||||
def SendAndWaitForResponse(self, stanza, timeout=None, func=None, args=None):
|
||||
''' 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
|
||||
self._witid = self.send(stanza)
|
||||
if func:
|
||||
|
@ -395,27 +395,27 @@ class Dispatcher(PlugIn):
|
|||
self._owner.onreceive(self.WaitForData)
|
||||
self._expected[self._witid] = None
|
||||
return self._witid
|
||||
|
||||
|
||||
def SendAndCallForResponse(self, stanza, func=None, args=None):
|
||||
''' Put stanza on the wire and call back when recipient replies.
|
||||
Additional callback arguments can be specified in args. '''
|
||||
self.SendAndWaitForResponse(stanza, 0, func, args)
|
||||
|
||||
|
||||
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.
|
||||
Returns assigned ID.'''
|
||||
if isinstance(stanza, basestring):
|
||||
return self._owner.Connection.send(stanza, now = now)
|
||||
if not isinstance(stanza, Protocol):
|
||||
if not isinstance(stanza, Protocol):
|
||||
_ID=None
|
||||
elif not stanza.getID():
|
||||
global ID
|
||||
ID+=1
|
||||
_ID=repr(ID)
|
||||
stanza.setID(_ID)
|
||||
else:
|
||||
else:
|
||||
_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)
|
||||
if self._owner._component and stanza.getName() != 'bind':
|
||||
to=self._owner.Server
|
||||
|
@ -433,7 +433,7 @@ class Dispatcher(PlugIn):
|
|||
else:
|
||||
self._owner.Connection.send(stanza, now = now)
|
||||
return _ID
|
||||
|
||||
|
||||
def disconnect(self):
|
||||
''' Send a stream terminator. '''
|
||||
self._owner.Connection.send('</stream:stream>')
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
## features.py
|
||||
## features.py
|
||||
##
|
||||
## Copyright (C) 2003-2004 Alexey "Snake" Nezhdanov
|
||||
##
|
||||
|
@ -82,7 +82,7 @@ def discoverInfo(disp,jid,node=None):
|
|||
def getRegInfo(disp,host,info={},sync=True):
|
||||
""" Gets registration form from remote host.
|
||||
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.
|
||||
'disp' must be connected dispatcher instance."""
|
||||
iq=Iq('get',NS_REGISTER,to=host)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
## features.py
|
||||
## features.py
|
||||
##
|
||||
## Copyright (C) 2003-2004 Alexey "Snake" Nezhdanov
|
||||
## Copyright (C) 2007 Julien Pivotto <roidelapluie@gmail.com>
|
||||
|
@ -20,7 +20,7 @@ from protocol import *
|
|||
|
||||
def _on_default_response(disp, iq, cb):
|
||||
def _on_response(resp):
|
||||
if isResultNode(resp):
|
||||
if isResultNode(resp):
|
||||
if cb:
|
||||
cb(1)
|
||||
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
|
||||
(if gb2a is true). Returns obtained info. Used internally. """
|
||||
iq=Iq(to=jid, typ='get', queryNS=ns)
|
||||
if node:
|
||||
if node:
|
||||
iq.setQuerynode(node)
|
||||
def _on_resp1(resp):
|
||||
if fb2b and not isResultNode(resp):
|
||||
if fb2b and not isResultNode(resp):
|
||||
# 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:
|
||||
_on_resp2('')
|
||||
def _on_resp2(resp):
|
||||
if fb2a and not isResultNode(resp):
|
||||
if fb2a and not isResultNode(resp):
|
||||
# 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:
|
||||
_on_result('')
|
||||
def _on_result(resp):
|
||||
if isResultNode(resp):
|
||||
if isResultNode(resp):
|
||||
if cb:
|
||||
cb(resp.getQueryPayload())
|
||||
elif cb:
|
||||
|
@ -65,7 +65,7 @@ def discoverItems(disp,jid,node=None, cb=None):
|
|||
def _on_response(result_array):
|
||||
ret=[]
|
||||
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'))
|
||||
ret.append(result.attrs)
|
||||
if cb:
|
||||
|
@ -82,39 +82,39 @@ def discoverInfo(disp,jid,node=None, cb=None):
|
|||
def _on_response(result):
|
||||
identities , features = [] , []
|
||||
for i in result:
|
||||
if i.getName()=='identity':
|
||||
if i.getName()=='identity':
|
||||
identities.append(i.attrs)
|
||||
elif i.getName()=='feature':
|
||||
elif i.getName()=='feature':
|
||||
features.append(i.getAttr('var'))
|
||||
elif i.getName()=='agent':
|
||||
if i.getTag('name'):
|
||||
if i.getTag('name'):
|
||||
i.setAttr('name',i.getTagData('name'))
|
||||
if i.getTag('description'):
|
||||
if i.getTag('description'):
|
||||
i.setAttr('name',i.getTagData('description'))
|
||||
identities.append(i.attrs)
|
||||
if i.getTag('groupchat'):
|
||||
if i.getTag('groupchat'):
|
||||
features.append(NS_GROUPCHAT)
|
||||
if i.getTag('register'):
|
||||
if i.getTag('register'):
|
||||
features.append(NS_REGISTER)
|
||||
if i.getTag('search'):
|
||||
if i.getTag('search'):
|
||||
features.append(NS_SEARCH)
|
||||
if cb:
|
||||
cb(identities , features)
|
||||
_discover(disp, NS_DISCO_INFO, jid, node, _on_response)
|
||||
|
||||
|
||||
### Registration ### jabber:iq:register ### JEP-0077 ###########################
|
||||
def getRegInfo(disp, host, info={}, sync=True):
|
||||
""" Gets registration form from remote host.
|
||||
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.
|
||||
'disp' must be connected dispatcher instance."""
|
||||
iq=Iq('get',NS_REGISTER,to=host)
|
||||
for i in info.keys():
|
||||
for i in info.keys():
|
||||
iq.setTagData(i,info[i])
|
||||
if sync:
|
||||
disp.SendAndCallForResponse(iq, lambda resp: _ReceivedRegInfo(disp.Dispatcher,resp, host))
|
||||
else:
|
||||
else:
|
||||
disp.SendAndCallForResponse(iq, _ReceivedRegInfo, {'agent': host })
|
||||
|
||||
def _ReceivedRegInfo(con, resp, agent):
|
||||
|
@ -208,7 +208,7 @@ def getPrivacyList(disp, listname):
|
|||
""" Requests specific privacy list listname. Returns list of XML nodes (rules)
|
||||
taken from the server responce."""
|
||||
def _on_response(resp):
|
||||
if not isResultNode(resp):
|
||||
if not isResultNode(resp):
|
||||
disp.Event(NS_PRIVACY, PRIVACY_LIST_RECEIVED, (False))
|
||||
return
|
||||
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):
|
||||
""" Switches privacy list 'listname' to specified type.
|
||||
By default the type is 'active'. Returns true on success."""
|
||||
if listname:
|
||||
if listname:
|
||||
attrs={'name':listname}
|
||||
else:
|
||||
else:
|
||||
attrs={}
|
||||
iq = Iq('set',NS_PRIVACY,payload=[Node(typ,attrs)])
|
||||
_on_default_response(disp, iq, cb)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
## filetransfer.py
|
||||
## filetransfer.py
|
||||
##
|
||||
## 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.
|
||||
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.
|
||||
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.
|
||||
"""
|
||||
def __init__(self):
|
||||
|
|
|
@ -19,42 +19,42 @@ class IdleObject:
|
|||
'''
|
||||
def __init__(self):
|
||||
self.fd = -1
|
||||
|
||||
|
||||
def pollend(self):
|
||||
''' called on stream failure '''
|
||||
pass
|
||||
|
||||
|
||||
def pollin(self):
|
||||
''' called on new read event '''
|
||||
pass
|
||||
|
||||
|
||||
def pollout(self):
|
||||
''' called on new write event (connect in sockets is a pollout) '''
|
||||
pass
|
||||
|
||||
|
||||
def read_timeout(self, fd):
|
||||
''' called when timeout has happend '''
|
||||
pass
|
||||
|
||||
|
||||
class IdleQueue:
|
||||
def __init__(self):
|
||||
self.queue = {}
|
||||
|
||||
|
||||
# when there is a timeout it executes obj.read_timeout()
|
||||
# timeout is not removed automatically!
|
||||
self.read_timeouts = {}
|
||||
|
||||
|
||||
# cb, which are executed after XX sec., alarms are removed automatically
|
||||
self.alarms = {}
|
||||
self.init_idle()
|
||||
|
||||
|
||||
def init_idle(self):
|
||||
self.selector = select.poll()
|
||||
|
||||
|
||||
def remove_timeout(self, fd):
|
||||
if fd in self.read_timeouts:
|
||||
del(self.read_timeouts[fd])
|
||||
|
||||
|
||||
def set_alarm(self, alarm_cb, seconds):
|
||||
''' set up a new alarm, to be called after alarm_cb sec. '''
|
||||
alarm_time = self.current_time() + seconds
|
||||
|
@ -63,13 +63,13 @@ class IdleQueue:
|
|||
self.alarms[alarm_time].append(alarm_cb)
|
||||
else:
|
||||
self.alarms[alarm_time] = [alarm_cb]
|
||||
|
||||
|
||||
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 '''
|
||||
timeout = self.current_time() + seconds
|
||||
self.read_timeouts[fd] = timeout
|
||||
|
||||
|
||||
def check_time_events(self):
|
||||
current_time = self.current_time()
|
||||
for fd, timeout in self.read_timeouts.items():
|
||||
|
@ -86,7 +86,7 @@ class IdleQueue:
|
|||
for cb in self.alarms[alarm_time]:
|
||||
cb()
|
||||
del(self.alarms[alarm_time])
|
||||
|
||||
|
||||
def plug_idle(self, obj, writable = True, readable = True):
|
||||
if obj.fd == -1:
|
||||
return
|
||||
|
@ -105,43 +105,43 @@ class IdleQueue:
|
|||
# when we paused a FT, we expect only a close event
|
||||
flags = 16
|
||||
self.add_idle(obj.fd, flags)
|
||||
|
||||
|
||||
def add_idle(self, fd, flags):
|
||||
self.selector.register(fd, flags)
|
||||
|
||||
|
||||
def unplug_idle(self, fd):
|
||||
if fd in self.queue:
|
||||
del(self.queue[fd])
|
||||
self.remove_idle(fd)
|
||||
|
||||
|
||||
def current_time(self):
|
||||
from time import time
|
||||
return time()
|
||||
|
||||
|
||||
def remove_idle(self, fd):
|
||||
self.selector.unregister(fd)
|
||||
|
||||
|
||||
def process_events(self, fd, flags):
|
||||
obj = self.queue.get(fd)
|
||||
if obj is None:
|
||||
self.unplug_idle(fd)
|
||||
return False
|
||||
|
||||
|
||||
if flags & 3: # waiting read event
|
||||
obj.pollin()
|
||||
return True
|
||||
|
||||
|
||||
elif flags & 4: # waiting write event
|
||||
obj.pollout()
|
||||
return True
|
||||
|
||||
|
||||
elif flags & 16: # closed channel
|
||||
# io error, don't expect more events
|
||||
self.remove_timeout(obj.fd)
|
||||
self.unplug_idle(obj.fd)
|
||||
obj.pollend()
|
||||
return False
|
||||
|
||||
|
||||
def process(self):
|
||||
if not self.queue:
|
||||
# check for timeouts/alert also when there are no active fds
|
||||
|
@ -159,7 +159,7 @@ class IdleQueue:
|
|||
return True
|
||||
|
||||
class SelectIdleQueue(IdleQueue):
|
||||
'''
|
||||
'''
|
||||
Extends IdleQueue to use select.select() for polling
|
||||
This class exisists for the sake of gtk2.8 on windows, which
|
||||
doesn't seem to support io_add_watch properly (yet)
|
||||
|
@ -171,7 +171,7 @@ class SelectIdleQueue(IdleQueue):
|
|||
self.read_fds = {}
|
||||
self.write_fds = {}
|
||||
self.error_fds = {}
|
||||
|
||||
|
||||
def add_idle(self, fd, flags):
|
||||
''' this method is called when we plug a new idle object.
|
||||
Remove descriptor to read/write/error lists, according flags
|
||||
|
@ -181,7 +181,7 @@ class SelectIdleQueue(IdleQueue):
|
|||
if flags & 4:
|
||||
self.write_fds[fd] = fd
|
||||
self.error_fds[fd] = fd
|
||||
|
||||
|
||||
def remove_idle(self, fd):
|
||||
''' this method is called when we unplug a new idle object.
|
||||
Remove descriptor from read/write/error lists
|
||||
|
@ -192,13 +192,13 @@ class SelectIdleQueue(IdleQueue):
|
|||
del(self.write_fds[fd])
|
||||
if fd in self.error_fds:
|
||||
del(self.error_fds[fd])
|
||||
|
||||
|
||||
def process(self):
|
||||
if not self.write_fds and not self.read_fds:
|
||||
self.check_time_events()
|
||||
return True
|
||||
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)
|
||||
except select.error, e:
|
||||
waiting_descriptors = ((),(),())
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
## protocol.py
|
||||
## protocol.py
|
||||
##
|
||||
## 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 $
|
||||
|
||||
"""
|
||||
Protocol module contains tools that is needed for processing of
|
||||
Protocol module contains tools that is needed for processing of
|
||||
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.
|
||||
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.
|
||||
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)."""
|
||||
sasl_error_conditions="""
|
||||
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'))
|
||||
return attrs
|
||||
|
||||
class Iq(Protocol):
|
||||
class Iq(Protocol):
|
||||
""" 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):
|
||||
""" Create Iq object. You can specify type, query namespace
|
||||
|
@ -638,7 +638,7 @@ class Error(Protocol):
|
|||
|
||||
class DataField(Node):
|
||||
""" 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. """
|
||||
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.
|
||||
|
|
|
@ -24,7 +24,7 @@ from client import PlugIn
|
|||
|
||||
class Roster(PlugIn):
|
||||
""" 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
|
||||
currently support 'error' presences.
|
||||
You can also use mapping interface for access to the internal representation of
|
||||
|
@ -48,7 +48,7 @@ class Roster(PlugIn):
|
|||
if request: self.Request()
|
||||
|
||||
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). """
|
||||
if self.set is None: self.set=0
|
||||
elif not force: return
|
||||
|
@ -187,7 +187,7 @@ class Roster(PlugIn):
|
|||
""" Authorise JID 'jid'. Works only if these JID requested auth previously. """
|
||||
self._owner.send(Presence(jid,'subscribed'))
|
||||
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. """
|
||||
self._owner.send(Presence(jid,'unsubscribed'))
|
||||
def getRaw(self):
|
||||
|
|
|
@ -32,23 +32,23 @@ class NonBlockingRoster(Roster):
|
|||
self._owner.RegisterHandler('iq', self.RosterIqHandler, 'result', NS_ROSTER, makefirst = 1)
|
||||
self._owner.RegisterHandler('iq', self.RosterIqHandler, 'set', NS_ROSTER)
|
||||
self._owner.RegisterHandler('presence', self.PresenceHandler)
|
||||
if request:
|
||||
if request:
|
||||
self.Request()
|
||||
|
||||
|
||||
def _on_roster_set(self, data):
|
||||
if data:
|
||||
self._owner.Dispatcher.ProcessNonBlocking(data)
|
||||
if not self.set:
|
||||
return
|
||||
if not self.set:
|
||||
return
|
||||
self._owner.onreceive(None)
|
||||
if self.on_ready:
|
||||
self.on_ready(self)
|
||||
self.on_ready = None
|
||||
return True
|
||||
|
||||
|
||||
def getRoster(self, on_ready=None):
|
||||
''' Requests roster from server if neccessary and returns self. '''
|
||||
if not self.set:
|
||||
if not self.set:
|
||||
self.on_ready = on_ready
|
||||
self._owner.onreceive(self._on_roster_set)
|
||||
return
|
||||
|
|
|
@ -46,7 +46,7 @@ SESSION_CLOSED =5
|
|||
|
||||
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
|
||||
client type connection) etc.
|
||||
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):
|
||||
""" Change the session 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.
|
||||
"""
|
||||
if self._session_state<newstate:
|
||||
|
|
|
@ -53,14 +53,14 @@ class Node(object):
|
|||
""" 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
|
||||
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
|
||||
"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."""
|
||||
if node:
|
||||
if self.FORCE_NODE_RECREATION and isinstance(node, Node):
|
||||
if self.FORCE_NODE_RECREATION and isinstance(node, Node):
|
||||
node=str(node)
|
||||
if not isinstance(node, Node):
|
||||
if not isinstance(node, Node):
|
||||
node=NodeBuilder(node,self)
|
||||
node_built = True
|
||||
else:
|
||||
|
@ -94,7 +94,7 @@ class Node(object):
|
|||
for i in payload:
|
||||
if isinstance(i, Node): self.addChild(node=i)
|
||||
else: self.data.append(ustr(i))
|
||||
|
||||
|
||||
def lookup_nsp(self,pfx=''):
|
||||
ns = self.nsd.get(pfx,None)
|
||||
if ns is None:
|
||||
|
@ -119,7 +119,7 @@ class Node(object):
|
|||
val = ustr(self.attrs[key])
|
||||
s = s + ' %s="%s"' % ( key, XMLescape(val) )
|
||||
s = s + ">"
|
||||
cnt = 0
|
||||
cnt = 0
|
||||
if self.kids:
|
||||
if fancy: s = s + "\n"
|
||||
for a in self.kids:
|
||||
|
@ -196,7 +196,7 @@ class Node(object):
|
|||
try: ret.append(self.kids[i])
|
||||
except IndexError: pass
|
||||
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.
|
||||
Returns the first found or None if not found. """
|
||||
return self.getTags(name, attrs, namespace, one=1)
|
||||
|
@ -224,7 +224,7 @@ class Node(object):
|
|||
else: nodes.append(node)
|
||||
if one and nodes: return nodes[0]
|
||||
if not one: return nodes
|
||||
|
||||
|
||||
def iterTags(self, name, attrs={}, namespace=None):
|
||||
""" Iterate over all children using specified arguments as filter. """
|
||||
for node in self.kids:
|
||||
|
@ -248,8 +248,8 @@ class Node(object):
|
|||
def setNamespace(self, namespace):
|
||||
""" Changes the node namespace. """
|
||||
self.namespace=namespace
|
||||
def setParent(self, node):
|
||||
""" Sets node's parent to "node". WARNING: do not checks if the parent already present
|
||||
def setParent(self, node):
|
||||
""" 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. """
|
||||
self.parent = node
|
||||
def setPayload(self,payload,add=0):
|
||||
|
@ -320,7 +320,7 @@ DBG_NODEBUILDER = 'nodebuilder'
|
|||
class NodeBuilder:
|
||||
""" 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.
|
||||
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.
|
||||
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):
|
||||
|
@ -331,7 +331,7 @@ class NodeBuilder:
|
|||
"data" (if provided) feeded to parser immidiatedly after instance init.
|
||||
"""
|
||||
self.DEBUG(DBG_NODEBUILDER, "Preparing to handle incoming XML stream.", 'start')
|
||||
|
||||
|
||||
self._parser = xml.parsers.expat.ParserCreate()
|
||||
self._parser.StartElementHandler = self.starttag
|
||||
self._parser.EndElementHandler = self.endtag
|
||||
|
@ -339,7 +339,7 @@ class NodeBuilder:
|
|||
self._parser.CharacterDataHandler = self.handle_cdata
|
||||
self._parser.buffer_text = True
|
||||
self.Parse = self._parser.Parse
|
||||
|
||||
|
||||
self.__depth = 0
|
||||
self.__last_depth = 0
|
||||
self.__max_depth = 0
|
||||
|
@ -352,13 +352,13 @@ class NodeBuilder:
|
|||
self.data_buffer = None
|
||||
if data:
|
||||
self._parser.Parse(data,1)
|
||||
|
||||
|
||||
def check_data_buffer(self):
|
||||
if self.data_buffer:
|
||||
self._ptr.data.append(''.join(self.data_buffer))
|
||||
del self.data_buffer[:]
|
||||
self.data_buffer = None
|
||||
|
||||
|
||||
def destroy(self):
|
||||
""" Method used to allow class instance to be garbage-collected. """
|
||||
self.check_data_buffer()
|
||||
|
@ -373,9 +373,9 @@ class NodeBuilder:
|
|||
self._inc_depth()
|
||||
self.DEBUG(DBG_NODEBUILDER, "DEPTH -> %i , tag -> %s, attrs -> %s" % (self.__depth, tag, repr(attrs)), 'down')
|
||||
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)
|
||||
else:
|
||||
else:
|
||||
Node.__init__(self._mini_dom,tag=tag, attrs=attrs, nsp = self._document_nsp, node_built=True)
|
||||
self._ptr = self._mini_dom
|
||||
elif self.__depth > self._dispatch_depth:
|
||||
|
@ -398,7 +398,7 @@ class NodeBuilder:
|
|||
except ValueError, e:
|
||||
self._document_attrs = None
|
||||
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.last_is_data = 0
|
||||
def endtag(self, tag ):
|
||||
|
@ -414,7 +414,7 @@ class NodeBuilder:
|
|||
self._dec_depth()
|
||||
self.last_is_data = 0
|
||||
if self.__depth == 0: self.stream_footer_received()
|
||||
|
||||
|
||||
def handle_cdata(self, data):
|
||||
if self.last_is_data:
|
||||
if self.data_buffer:
|
||||
|
@ -422,7 +422,7 @@ class NodeBuilder:
|
|||
elif self._ptr:
|
||||
self.data_buffer = [data]
|
||||
self.last_is_data = 1
|
||||
|
||||
|
||||
def handle_namespace_start(self, prefix, uri):
|
||||
"""XML Parser callback. Used internally"""
|
||||
self.check_data_buffer()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
## transports_nb.py
|
||||
## based on transports.py
|
||||
##
|
||||
##
|
||||
## Copyright (C) 2003-2004 Alexey "Snake" Nezhdanov
|
||||
## modified by Dimitur Kirov <dkirov@gmail.com>
|
||||
##
|
||||
|
@ -22,7 +22,7 @@ from simplexml import ustr
|
|||
from client import PlugIn
|
||||
from idlequeue import IdleObject
|
||||
from protocol import *
|
||||
from transports import *
|
||||
from transports import *
|
||||
|
||||
import sys
|
||||
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, "=" * 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
|
||||
|
||||
# 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 '''
|
||||
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)
|
||||
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_failure - called if there was error connecting to socket
|
||||
'''
|
||||
IdleObject.__init__(self)
|
||||
PlugIn.__init__(self)
|
||||
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._server = server
|
||||
self._hostfqdn = server[0]
|
||||
|
@ -256,43 +256,43 @@ class NonBlockingTcp(PlugIn, IdleObject):
|
|||
self.on_receive = None
|
||||
self.on_disconnect = None
|
||||
self.printed_error = False
|
||||
|
||||
|
||||
# 0 - not connected
|
||||
# 1 - connected
|
||||
# -1 - about to disconnect (when we wait for final events to complete)
|
||||
# -2 - disconnected
|
||||
self.state = 0
|
||||
|
||||
# queue with messages to be send
|
||||
|
||||
# queue with messages to be send
|
||||
self.sendqueue = []
|
||||
|
||||
|
||||
# bytes remained from the last send message
|
||||
self.sendbuff = ''
|
||||
|
||||
|
||||
# time to wait for SOME stanza to come and then send keepalive
|
||||
self.sendtimeout = 0
|
||||
|
||||
|
||||
# in case we want to something different than sending keepalives
|
||||
self.on_timeout = None
|
||||
|
||||
|
||||
# writable, readable - keep state of the last pluged flags
|
||||
# This prevents replug of same object with the same flags
|
||||
self.writable = True
|
||||
self.readable = False
|
||||
self.ais = None
|
||||
|
||||
|
||||
def plugin(self, owner):
|
||||
''' Fire up connection. Return non-empty string on success.
|
||||
Also registers self.disconnected method in the owner's dispatcher.
|
||||
Called internally. '''
|
||||
self.idlequeue = owner.idlequeue
|
||||
self.printed_error = False
|
||||
if not self._server:
|
||||
if not self._server:
|
||||
self._server=(self._owner.Server,5222)
|
||||
if self.connect(self._server) is False:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def read_timeout(self):
|
||||
if self.state == 0:
|
||||
self.idlequeue.unplug_idle(self.fd)
|
||||
|
@ -307,7 +307,7 @@ class NonBlockingTcp(PlugIn, IdleObject):
|
|||
''' Try to establish connection. '''
|
||||
if not server:
|
||||
server=self._server
|
||||
else:
|
||||
else:
|
||||
self._server = server
|
||||
self._hostfqdn = self._server[0]
|
||||
self.printed_error = False
|
||||
|
@ -338,23 +338,23 @@ class NonBlockingTcp(PlugIn, IdleObject):
|
|||
writable = False
|
||||
if self.writable != writable or self.readable != readable:
|
||||
self.idlequeue.plug_idle(self, writable, readable)
|
||||
|
||||
|
||||
def pollout(self):
|
||||
if self.state == 0:
|
||||
self._do_connect()
|
||||
return
|
||||
self._do_send()
|
||||
|
||||
|
||||
def plugout(self):
|
||||
''' Disconnect from the remote server and unregister self.disconnected method from
|
||||
the owner's dispatcher. '''
|
||||
self.disconnect()
|
||||
self._owner.Connection = None
|
||||
self._owner = None
|
||||
|
||||
|
||||
def pollin(self):
|
||||
self._do_receive()
|
||||
|
||||
self._do_receive()
|
||||
|
||||
def pollend(self, retry=False):
|
||||
if not self.printed_error:
|
||||
self.printed_error = True
|
||||
|
@ -366,13 +366,13 @@ class NonBlockingTcp(PlugIn, IdleObject):
|
|||
self.disconnect()
|
||||
if conn_failure_cb:
|
||||
conn_failure_cb(retry)
|
||||
|
||||
|
||||
def disconnect(self):
|
||||
if self.state == -2: # already disconnected
|
||||
return
|
||||
self.state = -2
|
||||
self.sendqueue = None
|
||||
self.remove_timeout()
|
||||
self.remove_timeout()
|
||||
try:
|
||||
self._owner.disconnected()
|
||||
except Exception:
|
||||
|
@ -394,12 +394,12 @@ class NonBlockingTcp(PlugIn, IdleObject):
|
|||
if self.on_disconnect:
|
||||
self.on_disconnect()
|
||||
self.on_connect_failure = None
|
||||
|
||||
|
||||
def end_disconnect(self):
|
||||
''' force disconnect only if we are still trying to disconnect '''
|
||||
if self.state == -1:
|
||||
self.disconnect()
|
||||
|
||||
|
||||
def start_disconnect(self, to_send, on_disconnect):
|
||||
self.on_disconnect = on_disconnect
|
||||
|
||||
|
@ -412,19 +412,19 @@ class NonBlockingTcp(PlugIn, IdleObject):
|
|||
self.send('</stream:stream>')
|
||||
self.state = -1 # about to disconnect
|
||||
self.idlequeue.set_alarm(self.end_disconnect, DISCONNECT_TIMEOUT_SECONDS)
|
||||
|
||||
|
||||
def set_timeout(self, timeout):
|
||||
if self.state >= 0 and self.fd > 0:
|
||||
self.idlequeue.set_read_timeout(self.fd, timeout)
|
||||
|
||||
|
||||
def remove_timeout(self):
|
||||
if self.fd:
|
||||
self.idlequeue.remove_timeout(self.fd)
|
||||
|
||||
|
||||
def onreceive(self, recv_handler):
|
||||
''' Sets the on_receive callback. Do not confuse it with
|
||||
on_receive() method, which is the callback itself.
|
||||
|
||||
|
||||
If recv_handler==None, it tries to set that callback assuming that
|
||||
our owner also has a Dispatcher object plugged in, to its
|
||||
ProcessNonBlocking method.'''
|
||||
|
@ -438,7 +438,7 @@ class NonBlockingTcp(PlugIn, IdleObject):
|
|||
# make sure this cb is not overriden by recursive calls
|
||||
if not recv_handler(None) and _tmp == self.on_receive:
|
||||
self.on_receive = recv_handler
|
||||
|
||||
|
||||
def _do_receive(self, errors_only=False):
|
||||
''' Reads all pending incoming data. Calls owner's disconnected() method if appropriate.'''
|
||||
ERR_DISCONN = -2 # Misc error signifying that we got disconnected
|
||||
|
@ -446,7 +446,7 @@ class NonBlockingTcp(PlugIn, IdleObject):
|
|||
received = None
|
||||
errnum = 0
|
||||
errtxt = 'No Error Set'
|
||||
try:
|
||||
try:
|
||||
# get as many bites, as possible, but not more than RECV_BUFSIZE
|
||||
received = self._recv(RECV_BUFSIZE)
|
||||
except (socket.error, socket.herror, socket.gaierror), e:
|
||||
|
@ -515,7 +515,7 @@ class NonBlockingTcp(PlugIn, IdleObject):
|
|||
if self.on_connect_failure:
|
||||
self.on_connect_failure()
|
||||
return True
|
||||
|
||||
|
||||
def _do_send(self):
|
||||
if not self.sendbuff:
|
||||
if not self.sendqueue:
|
||||
|
@ -532,12 +532,12 @@ class NonBlockingTcp(PlugIn, IdleObject):
|
|||
self._on_send()
|
||||
self.disconnect()
|
||||
return
|
||||
# we are not waiting for write
|
||||
# we are not waiting for write
|
||||
self._plug_idle()
|
||||
self._on_send()
|
||||
except socket.error, e:
|
||||
if e[0] == socket.SSL_ERROR_WANT_WRITE:
|
||||
return True
|
||||
return True
|
||||
log.error("_do_send:", exc_info=True)
|
||||
#traceback.print_exc()
|
||||
if self.state < 0:
|
||||
|
@ -563,7 +563,7 @@ class NonBlockingTcp(PlugIn, IdleObject):
|
|||
self._server=ai[4]
|
||||
except socket.error, e:
|
||||
errnum, errstr = e
|
||||
|
||||
|
||||
# Ignore "Socket already connected".
|
||||
# FIXME: This happens when we switch an already
|
||||
# connected socket to SSL (STARTTLS). Instead of
|
||||
|
@ -614,16 +614,16 @@ class NonBlockingTcp(PlugIn, IdleObject):
|
|||
self.on_connect = None
|
||||
|
||||
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 self.state <= 0:
|
||||
return
|
||||
r = raw_data
|
||||
if isinstance(r, unicode):
|
||||
if isinstance(r, unicode):
|
||||
r = r.encode('utf-8')
|
||||
elif not isinstance(r, str):
|
||||
elif not isinstance(r, str):
|
||||
r = ustr(r).encode('utf-8')
|
||||
if now:
|
||||
self.sendqueue.insert(0, r)
|
||||
|
@ -639,25 +639,25 @@ class NonBlockingTcp(PlugIn, IdleObject):
|
|||
if hasattr(self._owner, 'Dispatcher'):
|
||||
self._owner.Dispatcher.Event('', DATA_SENT, self.sent_data)
|
||||
self.sent_data = None
|
||||
|
||||
|
||||
def _on_send_failure(self):
|
||||
self.DEBUG("Socket error while sending data",'error')
|
||||
self._owner.disconnected()
|
||||
self.sent_data = None
|
||||
|
||||
|
||||
def set_send_timeout(self, timeout, on_timeout):
|
||||
self.sendtimeout = timeout
|
||||
if self.sendtimeout > 0:
|
||||
self.on_timeout = on_timeout
|
||||
else:
|
||||
self.on_timeout = None
|
||||
|
||||
|
||||
def renew_send_timeout(self):
|
||||
if self.on_timeout and self.sendtimeout > 0:
|
||||
self.set_timeout(self.sendtimeout)
|
||||
else:
|
||||
self.remove_timeout()
|
||||
|
||||
|
||||
def getHost(self):
|
||||
''' Return the 'host' value that is connection is [will be] made to.'''
|
||||
return self._server[0]
|
||||
|
@ -682,10 +682,10 @@ class NonBlockingTLS(PlugIn):
|
|||
''' TLS connection used to encrypts already estabilished tcp connection.'''
|
||||
|
||||
# from ssl.h (partial extract)
|
||||
ssl_h_bits = { "SSL_ST_CONNECT": 0x1000, "SSL_ST_ACCEPT": 0x2000,
|
||||
"SSL_CB_LOOP": 0x01, "SSL_CB_EXIT": 0x02,
|
||||
"SSL_CB_READ": 0x04, "SSL_CB_WRITE": 0x08,
|
||||
"SSL_CB_ALERT": 0x4000,
|
||||
ssl_h_bits = { "SSL_ST_CONNECT": 0x1000, "SSL_ST_ACCEPT": 0x2000,
|
||||
"SSL_CB_LOOP": 0x01, "SSL_CB_EXIT": 0x02,
|
||||
"SSL_CB_READ": 0x04, "SSL_CB_WRITE": 0x08,
|
||||
"SSL_CB_ALERT": 0x4000,
|
||||
"SSL_CB_HANDSHAKE_START": 0x10, "SSL_CB_HANDSHAKE_DONE": 0x20}
|
||||
|
||||
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
|
||||
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.
|
||||
PlugIn.PlugIn(self, owner)
|
||||
self.DBG_LINE = DBG_NONBLOCKINGTLS
|
||||
|
@ -710,14 +710,14 @@ class NonBlockingTLS(PlugIn):
|
|||
self.tls_start()
|
||||
return res
|
||||
if self._owner.Dispatcher.Stream.features:
|
||||
try:
|
||||
try:
|
||||
self.FeaturesHandler(self._owner.Dispatcher, self._owner.Dispatcher.Stream.features)
|
||||
except NodeProcessed:
|
||||
except NodeProcessed:
|
||||
pass
|
||||
else:
|
||||
else:
|
||||
self._owner.RegisterHandlerOnce('features',self.FeaturesHandler, xmlns=NS_STREAMS)
|
||||
self.starttls = None
|
||||
|
||||
|
||||
def plugout(self,now=0):
|
||||
''' 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.'''
|
||||
|
@ -731,7 +731,7 @@ class NonBlockingTLS(PlugIn):
|
|||
if self.on_tls_start:
|
||||
self.on_tls_start()
|
||||
self.on_tls_start = None
|
||||
|
||||
|
||||
def FeaturesHandler(self, conn, feats):
|
||||
''' Used to analyse server <features/> tag for TLS support.
|
||||
If TLS is supported starts the encryption negotiation. Used internally '''
|
||||
|
@ -868,7 +868,7 @@ class NonBlockingTLS(PlugIn):
|
|||
def StartTLSHandler(self, conn, starttls):
|
||||
''' Handle server reply if TLS is allowed to process. Behaves accordingly.
|
||||
Used internally.'''
|
||||
if starttls.getNamespace() != NS_TLS:
|
||||
if starttls.getNamespace() != NS_TLS:
|
||||
return
|
||||
self.starttls = starttls.getName()
|
||||
if self.starttls == 'failure':
|
||||
|
@ -890,15 +890,15 @@ class NBHTTPPROXYsocket(NonBlockingTcp):
|
|||
''' This class can be used instead of transports.HTTPPROXYsocket
|
||||
HTTP (CONNECT) proxy connection class. Uses TCPsocket as the base class
|
||||
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):
|
||||
''' Caches proxy and target addresses.
|
||||
'proxy' argument is a dictionary with mandatory keys 'host' and 'port' (proxy address)
|
||||
and optional keys 'user' and 'password' to use for authentication.
|
||||
'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_connect_failure = on_connect_failure
|
||||
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
|
||||
connection to the target server. Returns non-empty sting on success. '''
|
||||
NonBlockingTcp.connect(self, (self.proxy['host'], self.proxy['port']))
|
||||
|
||||
|
||||
def _on_tcp_connect(self):
|
||||
self.DEBUG('Proxy server contacted, performing authentification','start')
|
||||
connector = ['CONNECT %s:%s HTTP/1.0'%self.server,
|
||||
|
@ -931,14 +931,14 @@ class NBHTTPPROXYsocket(NonBlockingTcp):
|
|||
connector.append('\r\n')
|
||||
self.onreceive(self._on_headers_sent)
|
||||
self.send('\r\n'.join(connector))
|
||||
|
||||
|
||||
def _on_headers_sent(self, reply):
|
||||
if reply is None:
|
||||
return
|
||||
self.reply = reply.replace('\r', '')
|
||||
try:
|
||||
try:
|
||||
proto, code, desc = reply.split('\n')[0].split(' ', 2)
|
||||
except Exception:
|
||||
except Exception:
|
||||
log.error("_on_headers_sent:", exc_info=True)
|
||||
#traceback.print_exc()
|
||||
self.on_proxy_failure('Invalid proxy reply')
|
||||
|
@ -951,7 +951,7 @@ class NBHTTPPROXYsocket(NonBlockingTcp):
|
|||
if len(reply) != 2:
|
||||
pass
|
||||
self.onreceive(self._on_proxy_auth)
|
||||
|
||||
|
||||
def _on_proxy_auth(self, reply):
|
||||
if self.reply.find('\n\n') == -1:
|
||||
if reply is None:
|
||||
|
@ -972,7 +972,7 @@ class NBHTTPPROXYsocket(NonBlockingTcp):
|
|||
class NBSOCKS5PROXYsocket(NonBlockingTcp):
|
||||
'''SOCKS5 proxy connection class. Uses TCPsocket as the base class
|
||||
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,
|
||||
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
|
||||
authentication. '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_connect_failure = 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.
|
||||
'''
|
||||
NonBlockingTcp.connect(self, (self.proxy['host'], self.proxy['port']))
|
||||
|
||||
|
||||
def _on_tcp_connect(self):
|
||||
self.DEBUG('Proxy server contacted, performing authentification', 'start')
|
||||
if 'user' in self.proxy and 'password' in self.proxy:
|
||||
|
|
|
@ -87,7 +87,7 @@ class MappingTableFromFunction:
|
|||
self.map = map_table_function
|
||||
|
||||
class EmptyMappingTable:
|
||||
|
||||
|
||||
__implements__ = IMappingTable
|
||||
|
||||
def __init__(self, in_table_function):
|
||||
|
@ -145,7 +145,7 @@ class Profile:
|
|||
for c in string:
|
||||
if stringprep.in_table_a1(c):
|
||||
raise UnicodeError, "Unassigned code point %s" % repr(c)
|
||||
|
||||
|
||||
def check_bidirectionals(self, string):
|
||||
found_LCat = False
|
||||
found_RandALCat = False
|
||||
|
@ -229,12 +229,12 @@ if crippled:
|
|||
prohibiteds=[LookupTable([u' ', u'"', u'&', u"'", u'/',
|
||||
u':', u'<', u'>', u'@'])],
|
||||
check_unassigneds=False,
|
||||
check_bidi=False)
|
||||
check_bidi=False)
|
||||
|
||||
resourceprep = Profile(normalize=False,
|
||||
check_unassigneds=False,
|
||||
check_bidi=False)
|
||||
|
||||
|
||||
else:
|
||||
C_11 = LookupTableFromFunction(stringprep.in_table_c11)
|
||||
C_12 = LookupTableFromFunction(stringprep.in_table_c12)
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
## - Nikos Kouremenos <nkour@jabber.org>
|
||||
## - Dimitur Kirov <dkirov@gmail.com>
|
||||
## - Travis Shirk <travis@pobox.com>
|
||||
## - Stefan Bethge <stefan@lanpartei.de>
|
||||
## - Stefan Bethge <stefan@lanpartei.de>
|
||||
##
|
||||
## This file is part of Gajim.
|
||||
##
|
||||
|
|
|
@ -49,7 +49,7 @@ class Roster:
|
|||
diffs[key] = self._data[key]['status']
|
||||
#print 'roster_zeroconf.py: diffs:' + str(diffs)
|
||||
return diffs
|
||||
|
||||
|
||||
def setItem(self, jid, name='', groups=''):
|
||||
#print 'roster_zeroconf.py: setItem %s' % jid
|
||||
contact = self.zeroconf.get_contact(jid)
|
||||
|
@ -80,7 +80,7 @@ class Roster:
|
|||
self._data[jid]['name'] = nm
|
||||
else:
|
||||
self._data[jid]['name'] = jid
|
||||
if status == 'avail':
|
||||
if status == 'avail':
|
||||
status = 'online'
|
||||
self._data[jid]['txt_dict'] = txt_dict
|
||||
if 'msg' not in self._data[jid]['txt_dict']:
|
||||
|
@ -92,7 +92,7 @@ class Roster:
|
|||
#print 'roster_zeroconf.py: delItem %s' % jid
|
||||
if jid in self._data:
|
||||
del self._data[jid]
|
||||
|
||||
|
||||
def getItem(self, jid):
|
||||
#print 'roster_zeroconf.py: getItem: %s' % jid
|
||||
if jid in self._data:
|
||||
|
@ -101,16 +101,16 @@ class Roster:
|
|||
def __getitem__(self, jid):
|
||||
#print 'roster_zeroconf.py: __getitem__'
|
||||
return self._data[jid]
|
||||
|
||||
|
||||
def getItems(self):
|
||||
#print 'roster_zeroconf.py: getItems'
|
||||
# Return list of all [bare] JIDs that the roster currently tracks.
|
||||
return self._data.keys()
|
||||
|
||||
|
||||
def keys(self):
|
||||
#print 'roster_zeroconf.py: keys'
|
||||
return self._data.keys()
|
||||
|
||||
|
||||
def getRaw(self):
|
||||
#print 'roster_zeroconf.py: getRaw'
|
||||
return self._data
|
||||
|
@ -118,7 +118,7 @@ class Roster:
|
|||
def getResources(self, jid):
|
||||
#print 'roster_zeroconf.py: getResources(%s)' % jid
|
||||
return {}
|
||||
|
||||
|
||||
def getGroups(self, jid):
|
||||
return self._data[jid]['groups']
|
||||
|
||||
|
@ -147,10 +147,10 @@ class Roster:
|
|||
|
||||
def Subscribe(self, jid):
|
||||
pass
|
||||
|
||||
|
||||
def Unsubscribe(self, jid):
|
||||
pass
|
||||
|
||||
|
||||
def Authorize(self, jid):
|
||||
pass
|
||||
|
||||
|
|
|
@ -27,24 +27,24 @@ except ImportError, e:
|
|||
from common.zeroconf.zeroconf import C_BARE_NAME, C_INTERFACE, C_PROTOCOL, C_DOMAIN
|
||||
|
||||
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):
|
||||
self.avahi = None
|
||||
self.domain = None # specific domain to browse
|
||||
self.stype = '_presence._tcp'
|
||||
self.port = port # listening port that gets announced
|
||||
self.stype = '_presence._tcp'
|
||||
self.port = port # listening port that gets announced
|
||||
self.username = name
|
||||
self.host = host
|
||||
self.txt = {} # service data
|
||||
|
||||
#XXX these CBs should be set to None when we destroy the object
|
||||
# (go offline), because they create a circular reference
|
||||
|
||||
#XXX these CBs should be set to None when we destroy the object
|
||||
# (go offline), because they create a circular reference
|
||||
self.new_serviceCB = new_serviceCB
|
||||
self.remove_serviceCB = remove_serviceCB
|
||||
self.name_conflictCB = name_conflictCB
|
||||
self.disconnected_CB = disconnected_CB
|
||||
self.error_CB = error_CB
|
||||
|
||||
|
||||
self.service_browser = None
|
||||
self.domain_browser = None
|
||||
self.bus = None
|
||||
|
@ -60,10 +60,10 @@ class Zeroconf:
|
|||
def entrygroup_commit_error_CB(self, err):
|
||||
# left blank for possible later usage
|
||||
pass
|
||||
|
||||
|
||||
def error_callback1(self, err):
|
||||
gajim.log.debug('Error while resolving: ' + str(err))
|
||||
|
||||
|
||||
def error_callback(self, err):
|
||||
gajim.log.debug(str(err))
|
||||
# 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))
|
||||
if not self.connected:
|
||||
return
|
||||
|
||||
|
||||
# synchronous resolving
|
||||
self.server.ResolveService( int(interface), int(protocol), name, stype, \
|
||||
domain, self.avahi.PROTO_UNSPEC, dbus.UInt32(0), \
|
||||
|
@ -93,13 +93,13 @@ class Zeroconf:
|
|||
return
|
||||
|
||||
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:
|
||||
return
|
||||
|
||||
object_path = self.server.ServiceBrowserNew(interface, protocol, \
|
||||
stype, domain, dbus.UInt32(0))
|
||||
|
||||
|
||||
self.service_browser = dbus.Interface(self.bus.get_object(self.avahi.DBUS_NAME, \
|
||||
object_path) , self.avahi.DBUS_INTERFACE_SERVICE_BROWSER)
|
||||
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):
|
||||
if domain != "local":
|
||||
self.browse_domain(interface, protocol, domain)
|
||||
|
||||
|
||||
def txt_array_to_dict(self, txt_array):
|
||||
txt_dict = {}
|
||||
for els in txt_array:
|
||||
|
@ -131,8 +131,8 @@ class Zeroconf:
|
|||
val = ''
|
||||
txt_dict[key] = val.decode('utf-8')
|
||||
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:'
|
||||
% (name, domain, interface, protocol))
|
||||
gajim.log.debug('Host %s (%s), port %i, TXT data: %s' % (host, address, port,
|
||||
|
@ -142,10 +142,10 @@ class Zeroconf:
|
|||
bare_name = name
|
||||
if name.find('@') == -1:
|
||||
name = name + '@' + name
|
||||
|
||||
|
||||
# we don't want to see ourselves in the list
|
||||
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)
|
||||
self.new_serviceCB(name)
|
||||
else:
|
||||
|
@ -230,14 +230,14 @@ class Zeroconf:
|
|||
# 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.connect_to_signal('StateChanged', self.entrygroup_state_changed_callback)
|
||||
|
||||
|
||||
txt = {}
|
||||
|
||||
|
||||
#remove empty keys
|
||||
for key,val in self.txt.iteritems():
|
||||
if val:
|
||||
txt[key] = val
|
||||
|
||||
|
||||
txt['port.p2pj'] = self.port
|
||||
txt['version'] = 1
|
||||
txt['txtvers'] = 1
|
||||
|
@ -256,16 +256,16 @@ class Zeroconf:
|
|||
'', dbus.UInt16(self.port), self.avahi_txt(),
|
||||
reply_handler=self.service_added_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)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
except dbus.DBusException, e:
|
||||
gajim.log.debug(str(e))
|
||||
return False
|
||||
|
||||
|
||||
def announce(self):
|
||||
if not self.connected:
|
||||
return False
|
||||
|
@ -288,7 +288,7 @@ class Zeroconf:
|
|||
self.entrygroup._obj = None
|
||||
self.entrygroup = None
|
||||
self.announced = False
|
||||
|
||||
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
@ -318,8 +318,8 @@ class Zeroconf:
|
|||
return True
|
||||
try:
|
||||
self.bus = dbus.SystemBus()
|
||||
self.bus.add_signal_receiver(self.avahi_dbus_connect_cb,
|
||||
"NameOwnerChanged", "org.freedesktop.DBus",
|
||||
self.bus.add_signal_receiver(self.avahi_dbus_connect_cb,
|
||||
"NameOwnerChanged", "org.freedesktop.DBus",
|
||||
arg0="org.freedesktop.Avahi")
|
||||
except Exception, e:
|
||||
# System bus is not present
|
||||
|
@ -345,7 +345,7 @@ class Zeroconf:
|
|||
try:
|
||||
self.server = dbus.Interface(self.bus.get_object(self.avahi.DBUS_NAME, \
|
||||
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)
|
||||
except Exception, e:
|
||||
# Avahi service is not present
|
||||
|
@ -359,7 +359,7 @@ class Zeroconf:
|
|||
self.name = self.username + '@' + self.host # service name
|
||||
if not self.connect_avahi():
|
||||
return False
|
||||
|
||||
|
||||
self.connected = True
|
||||
# start browsing
|
||||
if self.domain is None:
|
||||
|
@ -375,7 +375,7 @@ class Zeroconf:
|
|||
self.domain_browser.connect_to_signal('Failure', self.error_callback)
|
||||
else:
|
||||
self.browse_domain(self.avahi.IF_UNSPEC, self.avahi.PROTO_UNSPEC, self.domain)
|
||||
|
||||
|
||||
return True
|
||||
|
||||
def disconnect(self):
|
||||
|
@ -414,7 +414,7 @@ class Zeroconf:
|
|||
if not jid in self.contacts:
|
||||
return None
|
||||
return self.contacts[jid]
|
||||
|
||||
|
||||
def update_txt(self, show = None):
|
||||
if show:
|
||||
self.txt['status'] = self.replace_show(show)
|
||||
|
|
|
@ -31,23 +31,23 @@ except ImportError, e:
|
|||
resolve_timeout = 1
|
||||
|
||||
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):
|
||||
self.domain = None # specific domain to browse
|
||||
self.stype = '_presence._tcp'
|
||||
self.port = port # listening port that gets announced
|
||||
self.stype = '_presence._tcp'
|
||||
self.port = port # listening port that gets announced
|
||||
self.username = name
|
||||
self.host = host
|
||||
self.txt = pybonjour.TXTRecord() # service data
|
||||
|
||||
# XXX these CBs should be set to None when we destroy the object
|
||||
# (go offline), because they create a circular reference
|
||||
|
||||
# XXX these CBs should be set to None when we destroy the object
|
||||
# (go offline), because they create a circular reference
|
||||
self.new_serviceCB = new_serviceCB
|
||||
self.remove_serviceCB = remove_serviceCB
|
||||
self.name_conflictCB = name_conflictCB
|
||||
self.disconnected_CB = disconnected_CB
|
||||
self.error_CB = error_CB
|
||||
|
||||
|
||||
self.contacts = {} # all current local contacts with data
|
||||
self.connected = False
|
||||
self.announced = False
|
||||
|
@ -64,7 +64,7 @@ class Zeroconf:
|
|||
if not (flags & pybonjour.kDNSServiceFlagsAdd):
|
||||
self.remove_service_callback(serviceName)
|
||||
return
|
||||
|
||||
|
||||
# asynchronous resolving
|
||||
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
|
||||
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):
|
||||
|
||||
|
||||
# TODO: do proper decoding...
|
||||
escaping= {
|
||||
r'\.': '.',
|
||||
|
@ -114,7 +114,7 @@ class Zeroconf:
|
|||
result = re.split('(?<!\\\\)\.', fullname)
|
||||
name = result[0]
|
||||
protocol, domain = result[2:4]
|
||||
|
||||
|
||||
# Replace the escaped values
|
||||
for src, trg in escaping.items():
|
||||
name = name.replace(src, trg)
|
||||
|
@ -126,11 +126,11 @@ class Zeroconf:
|
|||
|
||||
if not self.connected:
|
||||
return
|
||||
|
||||
|
||||
bare_name = name
|
||||
if '@' not in name:
|
||||
name = name + '@' + name
|
||||
|
||||
|
||||
# we don't want to see ourselves in the list
|
||||
if name != self.name:
|
||||
self.contacts[name] = (name, domain, interfaceIndex, protocol, hosttarget, hosttarget, port, bare_name, txtRecord)
|
||||
|
@ -146,10 +146,10 @@ class Zeroconf:
|
|||
self.resolved.append(True)
|
||||
|
||||
# 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:
|
||||
return
|
||||
|
||||
|
||||
escaping= {
|
||||
r'\.': '.',
|
||||
r'\032': ' ',
|
||||
|
@ -157,7 +157,7 @@ class Zeroconf:
|
|||
}
|
||||
|
||||
name, stype, protocol, domain, dummy = fullname.split('.')
|
||||
|
||||
|
||||
# Replace the escaped values
|
||||
for src, trg in escaping.items():
|
||||
name = name.replace(src, trg)
|
||||
|
@ -165,7 +165,7 @@ class Zeroconf:
|
|||
bare_name = name
|
||||
if name.find('@') == -1:
|
||||
name = name + '@' + name
|
||||
|
||||
|
||||
# we don't want to see ourselves in the list
|
||||
if name != self.name:
|
||||
self.contacts[name] = (name, domain, interfaceIndex, protocol, hosttarget, hosttarget, port, bare_name, txtRecord)
|
||||
|
@ -201,12 +201,12 @@ class Zeroconf:
|
|||
|
||||
def create_service(self):
|
||||
txt = {}
|
||||
|
||||
|
||||
#remove empty keys
|
||||
for key,val in self.txt:
|
||||
if val:
|
||||
txt[key] = val
|
||||
|
||||
|
||||
txt['port.p2pj'] = self.port
|
||||
txt['version'] = 1
|
||||
txt['txtvers'] = 1
|
||||
|
@ -218,7 +218,7 @@ class Zeroconf:
|
|||
txt['status'] = 'avail'
|
||||
|
||||
self.txt = pybonjour.TXTRecord(txt, strict=True)
|
||||
|
||||
|
||||
try:
|
||||
sdRef = pybonjour.DNSServiceRegister(name = self.name,
|
||||
regtype = self.stype, port = self.port, txtRecord = self.txt,
|
||||
|
@ -257,7 +257,7 @@ class Zeroconf:
|
|||
self.name = self.username + '@' + self.host # service name
|
||||
|
||||
self.connected = True
|
||||
|
||||
|
||||
# start browsing
|
||||
if self.domain is None:
|
||||
# Explicitly browse .local
|
||||
|
@ -268,7 +268,7 @@ class Zeroconf:
|
|||
|
||||
else:
|
||||
self.browse_domain(self.domain)
|
||||
|
||||
|
||||
return True
|
||||
|
||||
def disconnect(self):
|
||||
|
@ -276,8 +276,8 @@ class Zeroconf:
|
|||
self.connected = False
|
||||
self.browse_sdRef.close()
|
||||
self.remove_announce()
|
||||
|
||||
|
||||
|
||||
|
||||
def browse_domain(self, domain=None):
|
||||
gajim.log.debug('starting to browse')
|
||||
try:
|
||||
|
@ -320,7 +320,7 @@ class Zeroconf:
|
|||
if not jid in self.contacts:
|
||||
return None
|
||||
return self.contacts[jid]
|
||||
|
||||
|
||||
def update_txt(self, show = None):
|
||||
if show:
|
||||
self.txt['status'] = self.replace_show(show)
|
||||
|
|
|
@ -101,7 +101,7 @@ class PreferencesWindow:
|
|||
# Display avatars in roster
|
||||
st = gajim.config.get('show_avatars_in_roster')
|
||||
self.xml.get_widget('show_avatars_in_roster_checkbutton'). \
|
||||
set_active(st)
|
||||
set_active(st)
|
||||
|
||||
# Display status msg under contact name in roster
|
||||
st = gajim.config.get('show_status_msgs_in_roster')
|
||||
|
@ -222,7 +222,7 @@ class PreferencesWindow:
|
|||
model.append([preview, l[i]])
|
||||
if gajim.config.get('iconset') == l[i]:
|
||||
self.iconset_combobox.set_active(i)
|
||||
|
||||
|
||||
# Use transports iconsets
|
||||
st = gajim.config.get('use_transports_iconsets')
|
||||
self.xml.get_widget('transports_iconsets_checkbutton').set_active(st)
|
||||
|
@ -512,7 +512,7 @@ class PreferencesWindow:
|
|||
self.theme_preferences = None
|
||||
|
||||
self.notebook.set_current_page(0)
|
||||
|
||||
|
||||
self.window.show_all()
|
||||
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):
|
||||
self.on_checkbutton_toggled(widget, 'log_contact_status_changes')
|
||||
|
||||
|
||||
def on_log_encrypted_chats_checkbutton_toggled(self, widget):
|
||||
self.on_checkbutton_toggled(widget, 'log_encrypted_sessions')
|
||||
|
||||
|
@ -1042,7 +1042,7 @@ class PreferencesWindow:
|
|||
model.set_sort_column_id(1, gtk.SORT_ASCENDING)
|
||||
|
||||
# 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 = {
|
||||
'first_message_received': _('First Message Received'),
|
||||
'next_message_received_focused': _('Next Message Received Focused'),
|
||||
|
@ -1377,7 +1377,7 @@ class AccountsWindow:
|
|||
gajim.connections[self.current_account].connected > 0:
|
||||
def login(account, show_before, status_before):
|
||||
''' login with previous status'''
|
||||
# first make sure connection is really closed,
|
||||
# first make sure connection is really closed,
|
||||
# 0.5 may not be enough
|
||||
gajim.connections[account].disconnect(True)
|
||||
gajim.interface.roster.send_status(account, show_before,
|
||||
|
@ -2115,7 +2115,7 @@ class AccountsWindow:
|
|||
gajim.interface.roster.setup_and_draw_roster()
|
||||
|
||||
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
|
||||
if gajim.ZEROCONF_ACC_NAME in gajim.connections and not \
|
||||
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)
|
||||
window = dialogs.DataFormWindow(form, (on_ok, node))
|
||||
title = "Configure %s" % node
|
||||
window.set_title(title)
|
||||
window.set_title(title)
|
||||
window.show_all()
|
||||
|
||||
# vim: se ts=3:
|
||||
|
|
|
@ -667,7 +667,7 @@ class ConversationTextview:
|
|||
def on_textview_populate_popup(self, textview, menu):
|
||||
'''we override the default context menu and we prepend Clear
|
||||
(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)'''
|
||||
|
||||
separator_menuitem_was_added = False
|
||||
|
|
|
@ -110,7 +110,7 @@ class DataFormWidget(gtk.Alignment, object):
|
|||
# "private" methods
|
||||
|
||||
# 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):
|
||||
pass
|
||||
|
@ -326,7 +326,7 @@ class SingleForm(gtk.Table, object):
|
|||
if field.label is None:
|
||||
commonlabel = False
|
||||
leftattach = 0
|
||||
|
||||
|
||||
commonwidget = False
|
||||
widget = gtk.Label(field.value)
|
||||
widget.set_line_wrap(True)
|
||||
|
|
|
@ -106,7 +106,7 @@ class EditGroupsDialog:
|
|||
'''add group group to all contacts and all their brothers'''
|
||||
for (contact, account) in self.list_:
|
||||
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)
|
||||
gajim.interface.roster.draw_group(_('General'), account)
|
||||
|
||||
|
@ -487,7 +487,7 @@ class ChangeMoodDialog:
|
|||
self.mood_buttons[mood].connect('clicked',
|
||||
self.on_mood_button_clicked, mood)
|
||||
table.attach(self.mood_buttons[mood], x, x + 1, y, y + 1)
|
||||
|
||||
|
||||
# Calculate the next position
|
||||
x += 1
|
||||
if x >= self.COLS:
|
||||
|
@ -1036,7 +1036,7 @@ class AboutDialog:
|
|||
dlg.set_logo(pixbuf)
|
||||
#here you write your name in the form Name FamilyName <someone@somewhere>
|
||||
dlg.set_translator_credits(_('translator-credits'))
|
||||
|
||||
|
||||
thanks_artists_file_path = self.get_path('THANKS.artists')
|
||||
if thanks_artists_file_path:
|
||||
artists_text = open(thanks_artists_file_path).read()
|
||||
|
@ -1690,7 +1690,7 @@ class JoinGroupchatWindow:
|
|||
self._password_entry.set_text(password)
|
||||
self.xml.signal_autoconnect(self)
|
||||
# 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:
|
||||
title = _('Join Group Chat with account %s') % account
|
||||
else:
|
||||
|
|
32
src/disco.py
32
src/disco.py
|
@ -522,7 +522,7 @@ _('Without a connection, you can not browse available services'))
|
|||
bannerfont = gajim.config.get_per('themes', theme, 'bannerfont')
|
||||
bannerfontattrs = gajim.config.get_per('themes', theme,
|
||||
'bannerfontattrs')
|
||||
|
||||
|
||||
if bannerfont:
|
||||
font = pango.FontDescription(bannerfont)
|
||||
else:
|
||||
|
@ -533,10 +533,10 @@ _('Without a connection, you can not browse available services'))
|
|||
font.set_weight(pango.WEIGHT_HEAVY)
|
||||
if 'I' in bannerfontattrs:
|
||||
font.set_style(pango.STYLE_ITALIC)
|
||||
|
||||
|
||||
font_attrs = 'font_desc="%s"' % font.to_string()
|
||||
font_size = font.get_size()
|
||||
|
||||
|
||||
# in case there is no font specified we use x-large font size
|
||||
if font_size == 0:
|
||||
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, font.to_string(), text_after)
|
||||
self.banner.set_markup(markup)
|
||||
|
||||
|
||||
def paint_banner(self):
|
||||
'''Repaint the banner with theme color'''
|
||||
theme = gajim.config.get('roster_theme')
|
||||
|
@ -559,7 +559,7 @@ _('Without a connection, you can not browse available services'))
|
|||
default_bg = False
|
||||
else:
|
||||
default_bg = True
|
||||
|
||||
|
||||
if textcolor:
|
||||
color = gtk.gdk.color_parse(textcolor)
|
||||
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)
|
||||
if self.browser:
|
||||
self.browser.update_theme()
|
||||
|
||||
|
||||
def disconnect_style_event(self):
|
||||
if self.style_event_id:
|
||||
self.banner.disconnect(self.style_event_id)
|
||||
self.style_event_id = 0
|
||||
|
||||
|
||||
def connect_style_event(self, set_fg = False, set_bg = False):
|
||||
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)
|
||||
|
||||
|
||||
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[1] == True -> set bg color '''
|
||||
|
||||
|
||||
self.disconnect_style_event()
|
||||
if opts[1]:
|
||||
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.ensure_style()
|
||||
self.connect_style_event(opts[0], opts[1])
|
||||
|
||||
|
||||
def destroy(self, chain = False):
|
||||
'''Close the browser. This can optionally close its children and
|
||||
propagate to the parent. This should happen on actions like register,
|
||||
|
@ -808,7 +808,7 @@ class AgentBrowser:
|
|||
if self.browse_button:
|
||||
self.browse_button.destroy()
|
||||
self.browse_button = None
|
||||
|
||||
|
||||
def _set_title(self, jid, node, identities, features, data):
|
||||
'''Set the window title based on agent info.'''
|
||||
# Set the banner and window title
|
||||
|
@ -1945,14 +1945,14 @@ class DiscussionGroupsBrowser(AgentBrowser):
|
|||
groupnode = model.get_value(iter_, 1) # 1 = groupnode
|
||||
|
||||
gajim.connections[self.account].send_pb_subscribe(self.jid, groupnode, self._subscribeCB, groupnode)
|
||||
|
||||
|
||||
def on_unsubscribe_button_clicked(self, widget):
|
||||
'''Called when 'unsubscribe' button is pressed. Send unsubscription request.'''
|
||||
model, iter_ = self.window.services_treeview.get_selection().get_selected()
|
||||
if iter_ is None: return
|
||||
|
||||
groupnode = model.get_value(iter_, 1) # 1 = groupnode
|
||||
|
||||
|
||||
gajim.connections[self.account].send_pb_unsubscribe(self.jid, groupnode, self._unsubscribeCB, groupnode)
|
||||
|
||||
def _subscriptionsCB(self, conn, request):
|
||||
|
@ -1961,7 +1961,7 @@ class DiscussionGroupsBrowser(AgentBrowser):
|
|||
try:
|
||||
subscriptions = request.getTag('pubsub').getTag('subscriptions')
|
||||
except Exception:
|
||||
return
|
||||
return
|
||||
|
||||
groups = set()
|
||||
for child in subscriptions.getTags('subscription'):
|
||||
|
|
|
@ -83,11 +83,11 @@ class FeaturesWindow:
|
|||
_('Requires python-gnome2-extras or compilation of gtkspell module from Gajim sources.'),
|
||||
_('Feature not available under Windows.')),
|
||||
_('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.'),
|
||||
_('Feature not available under Windows.')),
|
||||
_('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 PyGTK >= 2.10.')),
|
||||
_('Idle'): (self.idle_available,
|
||||
|
|
|
@ -175,7 +175,7 @@ class FileTransfersWindow:
|
|||
helpers.convert_bytes(file_props['size'])
|
||||
if file_props['type'] == 'r':
|
||||
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()
|
||||
sender = sender_name
|
||||
else:
|
||||
|
@ -185,7 +185,7 @@ class FileTransfersWindow:
|
|||
sectext += '\n\t' +_('Recipient: ')
|
||||
if file_props['type'] == 's':
|
||||
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()
|
||||
recipient = receiver_name
|
||||
else:
|
||||
|
@ -194,7 +194,7 @@ class FileTransfersWindow:
|
|||
sectext += recipient
|
||||
if file_props['type'] == 'r':
|
||||
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)
|
||||
if file_props['type'] == 'r':
|
||||
button = gtk.Button(_('_Open Containing Folder'))
|
||||
|
@ -207,13 +207,13 @@ class FileTransfersWindow:
|
|||
dialog.show_all()
|
||||
|
||||
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'''
|
||||
dialogs.InformationDialog(_('File transfer cancelled'), _('Connection with peer cannot be established.'))
|
||||
self.tree.get_selection().unselect_all()
|
||||
|
||||
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'''
|
||||
dialogs.InformationDialog(_('File transfer cancelled'),
|
||||
_('Connection with peer cannot be established.'))
|
||||
|
@ -233,9 +233,9 @@ _('Connection with peer cannot be established.'))
|
|||
self.tree.get_selection().unselect_all()
|
||||
|
||||
def show_file_send_request(self, account, contact):
|
||||
|
||||
|
||||
desc_entry = gtk.Entry()
|
||||
|
||||
|
||||
def on_ok(widget):
|
||||
file_dir = None
|
||||
files_path_list = dialog.get_filenames()
|
||||
|
@ -249,7 +249,7 @@ _('Connection with peer cannot be established.'))
|
|||
gajim.config.set('last_send_dir', file_dir)
|
||||
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.RESPONSE_OK,
|
||||
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)
|
||||
dialog.add_action_widget(btn, gtk.RESPONSE_OK)
|
||||
dialog.set_default_response(gtk.RESPONSE_OK)
|
||||
|
||||
|
||||
desc_hbox = gtk.HBox(False, 5)
|
||||
desc_hbox.pack_start(gtk.Label(_('Description: ')),False,False,0)
|
||||
desc_hbox.pack_start(desc_entry,True,True,0)
|
||||
|
||||
|
||||
dialog.vbox.pack_start(desc_hbox, False, False, 0)
|
||||
|
||||
|
||||
btn.show()
|
||||
desc_hbox.show_all()
|
||||
|
||||
|
@ -287,7 +287,7 @@ _('Connection with peer cannot be established.'))
|
|||
(jid, resource) = contact.split('/', 1)
|
||||
contact = gajim.contacts.create_contact(jid=jid, resource=resource)
|
||||
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)
|
||||
if file_props is None:
|
||||
return False
|
||||
|
@ -366,9 +366,9 @@ _('Connection with peer cannot be established.'))
|
|||
gajim.connections[account].send_file_rejection(file_props)
|
||||
|
||||
dialog2 = dialogs.FileChooserDialog(
|
||||
title_text = _('Save File as...'),
|
||||
action = gtk.FILE_CHOOSER_ACTION_SAVE,
|
||||
buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
|
||||
title_text = _('Save File as...'),
|
||||
action = gtk.FILE_CHOOSER_ACTION_SAVE,
|
||||
buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
|
||||
gtk.STOCK_SAVE, gtk.RESPONSE_OK),
|
||||
default_response = gtk.RESPONSE_OK,
|
||||
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,
|
||||
on_response_ok = (on_response_ok, account, contact, 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))
|
||||
dialog.popup()
|
||||
|
||||
|
@ -506,21 +506,21 @@ _('Connection with peer cannot be established.'))
|
|||
|
||||
# remaining time
|
||||
if 'offset' in file_props and file_props['offset']:
|
||||
transfered_size -= file_props['offset']
|
||||
transfered_size -= file_props['offset']
|
||||
full_size -= file_props['offset']
|
||||
|
||||
if file_props['elapsed-time'] > 0:
|
||||
file_props['transfered_size'].append((file_props['last-time'], transfered_size))
|
||||
if len(file_props['transfered_size']) > 6:
|
||||
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)
|
||||
|
||||
self.model.set(iter_, C_PROGRESS, text)
|
||||
self.model.set(iter_, C_PERCENT, int(percent))
|
||||
text = self._format_time(eta)
|
||||
text += '\n'
|
||||
#This should make the string Kb/s,
|
||||
#This should make the string Kb/s,
|
||||
#where 'Kb' part is taken from %s.
|
||||
#Only the 's' after / (which means second) should be translated.
|
||||
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,
|
||||
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'''
|
||||
file_props = {'file-name' : file_path, 'name' : file_name,
|
||||
file_props = {'file-name' : file_path, 'name' : file_name,
|
||||
'type' : 's', 'desc' : file_desc}
|
||||
if os.path.isfile(file_path):
|
||||
stat = os.stat(file_path)
|
||||
|
@ -566,7 +566,7 @@ _('Connection with peer cannot be established.'))
|
|||
dialogs.ErrorDialog(_('Invalid File'), _('File: ') + file_path)
|
||||
return None
|
||||
if stat[6] == 0:
|
||||
dialogs.ErrorDialog(_('Invalid File'),
|
||||
dialogs.ErrorDialog(_('Invalid File'),
|
||||
_('It is not possible to send empty files'))
|
||||
return None
|
||||
file_props['elapsed-time'] = 0
|
||||
|
@ -589,11 +589,11 @@ _('Connection with peer cannot be established.'))
|
|||
file_props['elapsed-time'] = 0
|
||||
self.files_props[file_props['type']][file_props['sid']] = file_props
|
||||
iter_ = self.model.append()
|
||||
text_labels = '<b>' + _('Name: ') + '</b>\n'
|
||||
text_labels = '<b>' + _('Name: ') + '</b>\n'
|
||||
if file_props['type'] == 'r':
|
||||
text_labels += '<b>' + _('Sender: ') + '</b>'
|
||||
text_labels += '<b>' + _('Sender: ') + '</b>'
|
||||
else:
|
||||
text_labels += '<b>' + _('Recipient: ') + '</b>'
|
||||
text_labels += '<b>' + _('Recipient: ') + '</b>'
|
||||
|
||||
if file_props['type'] == 'r':
|
||||
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:
|
||||
return
|
||||
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)
|
||||
if self.tooltip.timeout > 0:
|
||||
if not props or self.tooltip.id == props[0]:
|
||||
|
@ -686,7 +686,7 @@ _('Connection with peer cannot be established.'))
|
|||
return True
|
||||
|
||||
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'''
|
||||
if len(self.model) == 0:
|
||||
self.cleanup_button.set_sensitive(False)
|
||||
|
@ -705,7 +705,7 @@ _('Connection with peer cannot be established.'))
|
|||
self.set_cleanup_sensitivity()
|
||||
|
||||
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' '''
|
||||
if path is None:
|
||||
self.set_all_insensitive()
|
||||
|
@ -743,7 +743,7 @@ _('Connection with peer cannot be established.'))
|
|||
return True
|
||||
|
||||
def selection_changed(self, args):
|
||||
''' selection has changed - change the sensitivity of the
|
||||
''' selection has changed - change the sensitivity of the
|
||||
buttons/menuitems'''
|
||||
selection = args
|
||||
selected = selection.get_selected_rows()
|
||||
|
@ -801,7 +801,7 @@ _('Connection with peer cannot be established.'))
|
|||
def on_pause_restore_button_clicked(self, widget):
|
||||
selected = self.tree.get_selection().get_selected()
|
||||
if selected is None or selected[1] is None:
|
||||
return
|
||||
return
|
||||
s_iter = selected[1]
|
||||
sid = self.model[s_iter][C_SID].decode('utf-8')
|
||||
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):
|
||||
selected = self.tree.get_selection().get_selected()
|
||||
if selected is None or selected[1] is None:
|
||||
return
|
||||
return
|
||||
s_iter = selected[1]
|
||||
sid = self.model[s_iter][C_SID].decode('utf-8')
|
||||
file_props = self.files_props[sid[0]][sid[1:]]
|
||||
if 'tt_account' not in file_props:
|
||||
return
|
||||
return
|
||||
account = file_props['tt_account']
|
||||
if account not in gajim.connections:
|
||||
return
|
||||
|
@ -839,7 +839,7 @@ _('Connection with peer cannot be established.'))
|
|||
self.tooltip.hide_tooltip()
|
||||
return
|
||||
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)
|
||||
# check if the current pointer is at the same path
|
||||
# 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])
|
||||
# position of the treeview on the screen
|
||||
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)
|
||||
else:
|
||||
self.tooltip.hide_tooltip()
|
||||
|
||||
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())
|
||||
|
||||
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)
|
||||
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)
|
||||
|
||||
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):
|
||||
selected = self.tree.get_selection().get_selected()
|
||||
if selected is None or selected[1] is None:
|
||||
return
|
||||
return
|
||||
s_iter = selected[1]
|
||||
sid = self.model[s_iter][C_SID].decode('utf-8')
|
||||
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):
|
||||
selected = self.tree.get_selection().get_selected()
|
||||
if selected is None or selected[1] is None:
|
||||
return
|
||||
return
|
||||
s_iter = selected[1]
|
||||
sid = self.model[s_iter][C_SID].decode('utf-8')
|
||||
file_props = self.files_props[sid[0]][sid[1:]]
|
||||
|
|
36
src/gajim.py
36
src/gajim.py
|
@ -525,9 +525,9 @@ class PassphraseRequest:
|
|||
|
||||
class Interface:
|
||||
|
||||
################################################################################
|
||||
### Methods handling events from connection
|
||||
################################################################################
|
||||
################################################################################
|
||||
### Methods handling events from connection
|
||||
################################################################################
|
||||
|
||||
def handle_event_roster(self, account, data):
|
||||
#('ROSTER', account, array)
|
||||
|
@ -805,7 +805,7 @@ class Interface:
|
|||
if ji in jid_list:
|
||||
# Update existing iter and group counting
|
||||
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]:
|
||||
# transport just signed in.
|
||||
# request avatars
|
||||
|
@ -1508,7 +1508,7 @@ class Interface:
|
|||
re_draw = False
|
||||
# If contact has changed (sub, ask or group) update roster
|
||||
# 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
|
||||
old_groups = contacts[0].groups
|
||||
if contacts[0].sub != sub or contacts[0].ask != ask\
|
||||
|
@ -1587,8 +1587,8 @@ class Interface:
|
|||
senders = ',\n '.join(reversed(gmessage['From']))
|
||||
text += _('\n\nFrom: %(from_address)s\nSubject: %(subject)s\n%(snippet)s') % \
|
||||
{'from_address': senders, 'subject': gmessage['Subject'],
|
||||
'snippet': gmessage['Snippet']}
|
||||
cnt += 1
|
||||
'snippet': gmessage['Snippet']}
|
||||
cnt += 1
|
||||
|
||||
if gajim.config.get_per('soundevents', 'gmail_received', 'enabled'):
|
||||
helpers.play_sound('gmail_received')
|
||||
|
@ -1920,7 +1920,7 @@ class Interface:
|
|||
# If contact is a groupchat user
|
||||
jids = [contact.jid]
|
||||
else:
|
||||
jids = [contact.jid, contact.get_full_jid()]
|
||||
jids = [contact.jid, contact.get_full_jid()]
|
||||
for jid in jids:
|
||||
ctrl = self.msg_win_mgr.get_control(jid, account)
|
||||
if ctrl:
|
||||
|
@ -2206,7 +2206,7 @@ class Interface:
|
|||
}
|
||||
gajim.handlers = self.handlers
|
||||
|
||||
################################################################################
|
||||
################################################################################
|
||||
### Methods dealing with gajim.events
|
||||
################################################################################
|
||||
|
||||
|
@ -2366,7 +2366,7 @@ class Interface:
|
|||
tv = ctrl.conv_textview
|
||||
tv.scroll_to_end()
|
||||
|
||||
################################################################################
|
||||
################################################################################
|
||||
### Methods dealing with emoticons
|
||||
################################################################################
|
||||
|
||||
|
@ -2390,7 +2390,7 @@ class Interface:
|
|||
except AttributeError:
|
||||
self._basic_pattern_re = re.compile(self.basic_pattern, re.IGNORECASE)
|
||||
return self._basic_pattern_re
|
||||
|
||||
|
||||
@property
|
||||
def emot_and_basic_re(self):
|
||||
try:
|
||||
|
@ -2415,7 +2415,7 @@ class Interface:
|
|||
except AttributeError:
|
||||
self._invalid_XML_chars_re = re.compile(self.invalid_XML_chars)
|
||||
return self._invalid_XML_chars_re
|
||||
|
||||
|
||||
def make_regexps(self):
|
||||
# regexp meta characters are: . ^ $ * + ? { } [ ] \ | ( )
|
||||
# one escapes the metachars with \
|
||||
|
@ -2462,7 +2462,7 @@ class Interface:
|
|||
latex = r'|\$\$[^$\\]*?([\]\[0-9A-Za-z()|+*/-]|[\\][\]\[0-9A-Za-z()|{}$])(.*?[^\\])?\$\$'
|
||||
|
||||
basic_pattern = links + '|' + mail + '|' + legacy_prefixes
|
||||
|
||||
|
||||
link_pattern = basic_pattern
|
||||
self.link_pattern_re = re.compile(link_pattern, re.IGNORECASE)
|
||||
|
||||
|
@ -2657,7 +2657,7 @@ class Interface:
|
|||
# We are already in that groupchat
|
||||
gc_control = self.msg_win_mgr.get_gc_control(room_jid, account)
|
||||
gc_control.nick = nick
|
||||
gc_control.parent_win.set_active_tab(gc_control)
|
||||
gc_control.parent_win.set_active_tab(gc_control)
|
||||
else:
|
||||
# We are already in this groupchat and it is minimized
|
||||
minimized_control.nick = nick
|
||||
|
@ -2800,9 +2800,9 @@ class Interface:
|
|||
if ctrl:
|
||||
ctrl.got_disconnected()
|
||||
|
||||
################################################################################
|
||||
################################################################################
|
||||
### Other Methods
|
||||
################################################################################
|
||||
################################################################################
|
||||
|
||||
def read_sleepy(self):
|
||||
'''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('$T','%(time)s')
|
||||
auto_message = auto_message % {
|
||||
'status': gajim.status_before_autoaway[account],
|
||||
'status': gajim.status_before_autoaway[account],
|
||||
'time': gajim.config.get('autoxatime')
|
||||
}
|
||||
self.roster.send_status(account, 'xa', auto_message, auto=True)
|
||||
|
@ -2993,7 +2993,7 @@ class Interface:
|
|||
bm['password'], minimize = minimize)
|
||||
elif jid in self.minimized_controls[account]:
|
||||
# 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.
|
||||
self.roster.add_groupchat(jid, account)
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ class GajimThemesWindow:
|
|||
self.xml = gtkgui_helpers.get_glade('gajim_themes_window.glade')
|
||||
self.window = self.xml.get_widget('gajim_themes_window')
|
||||
self.window.set_transient_for(gajim.interface.roster.window)
|
||||
|
||||
|
||||
self.options = ['account', 'group', 'contact', 'banner']
|
||||
self.options_combobox = self.xml.get_widget('options_combobox')
|
||||
self.textcolor_checkbutton = self.xml.get_widget('textcolor_checkbutton')
|
||||
|
@ -69,17 +69,17 @@ class GajimThemesWindow:
|
|||
self.select_active_theme()
|
||||
self.current_option = self.options[0]
|
||||
self.set_theme_options(self.current_theme, self.current_option)
|
||||
|
||||
|
||||
self.xml.signal_autoconnect(self)
|
||||
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.window.show_all()
|
||||
|
||||
|
||||
def on_themese_window_delete_event(self, widget, event):
|
||||
self.window.hide()
|
||||
return True # do NOT destroy the window
|
||||
|
||||
|
||||
def on_close_button_clicked(self, widget):
|
||||
if 'preferences' in gajim.interface.instances:
|
||||
gajim.interface.instances['preferences'].update_theme_list()
|
||||
|
@ -138,7 +138,7 @@ class GajimThemesWindow:
|
|||
self.xml.get_widget('remove_button').set_sensitive(False)
|
||||
self.theme_options_vbox.set_sensitive(False)
|
||||
self.theme_options_table.set_sensitive(False)
|
||||
else:
|
||||
else:
|
||||
self.xml.get_widget('remove_button').set_sensitive(True)
|
||||
self.theme_options_vbox.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.theme_options_vbox.set_sensitive(False)
|
||||
self.theme_options_table.set_sensitive(False)
|
||||
else:
|
||||
else:
|
||||
self.xml.get_widget('remove_button').set_sensitive(True)
|
||||
self.theme_options_vbox.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)
|
||||
gajim.config.del_per('themes', self.current_theme)
|
||||
model.remove(iter_)
|
||||
|
||||
|
||||
def set_theme_options(self, theme, option = 'account'):
|
||||
self.no_update = True
|
||||
self.options_combobox.set_active(self.options.index(option))
|
||||
|
@ -215,7 +215,7 @@ class GajimThemesWindow:
|
|||
state = False
|
||||
self.background_checkbutton.set_active(state)
|
||||
self.background_colorbutton.set_sensitive(state)
|
||||
|
||||
|
||||
# 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_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')
|
||||
self.colorbuttons[chatstate].set_color(gtk.gdk.color_parse(color))
|
||||
|
||||
|
||||
def on_textcolor_checkbutton_toggled(self, widget):
|
||||
state = widget.get_active()
|
||||
self.text_colorbutton.set_sensitive(state)
|
||||
self._set_color(state, self.text_colorbutton,
|
||||
self._set_color(state, self.text_colorbutton,
|
||||
'textcolor')
|
||||
|
||||
|
||||
def on_background_checkbutton_toggled(self, widget):
|
||||
state = widget.get_active()
|
||||
self.background_colorbutton.set_sensitive(state)
|
||||
self._set_color(state, self.background_colorbutton,
|
||||
self._set_color(state, self.background_colorbutton,
|
||||
'bgcolor')
|
||||
|
||||
|
||||
def on_textfont_checkbutton_toggled(self, widget):
|
||||
self.text_fontbutton.set_sensitive(widget.get_active())
|
||||
self._set_font()
|
||||
|
||||
|
||||
def on_text_colorbutton_color_set(self, widget):
|
||||
self._set_color(True, widget, 'textcolor')
|
||||
|
||||
|
||||
def on_background_colorbutton_color_set(self, widget):
|
||||
self._set_color(True, widget, 'bgcolor')
|
||||
|
||||
|
||||
def on_text_fontbutton_font_set(self, widget):
|
||||
self._set_font()
|
||||
|
||||
|
||||
def on_options_combobox_changed(self, widget):
|
||||
index = self.options_combobox.get_active()
|
||||
if index == -1:
|
||||
|
@ -268,15 +268,15 @@ class GajimThemesWindow:
|
|||
self.current_option = self.options[index]
|
||||
self.set_theme_options(self.current_theme,
|
||||
self.current_option)
|
||||
|
||||
|
||||
def on_bold_togglebutton_toggled(self, widget):
|
||||
if not self.no_update:
|
||||
self._set_font()
|
||||
|
||||
|
||||
def on_italic_togglebutton_toggled(self, widget):
|
||||
if not self.no_update:
|
||||
self._set_font()
|
||||
|
||||
|
||||
def _set_color(self, state, widget, option):
|
||||
''' set color value in prefs and update the UI '''
|
||||
if state:
|
||||
|
@ -287,7 +287,7 @@ class GajimThemesWindow:
|
|||
begin_option = ''
|
||||
if not option.startswith('state'):
|
||||
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)
|
||||
# use faster functions for this
|
||||
if self.current_option == 'banner':
|
||||
|
@ -298,7 +298,7 @@ class GajimThemesWindow:
|
|||
return
|
||||
gajim.interface.roster.change_roster_style(self.current_option)
|
||||
gajim.interface.save_config()
|
||||
|
||||
|
||||
def _set_font(self):
|
||||
''' set font value in prefs and update the UI '''
|
||||
state = self.textfont_checkbutton.get_active()
|
||||
|
@ -306,10 +306,10 @@ class GajimThemesWindow:
|
|||
font_string = self.text_fontbutton.get_font_name()
|
||||
else:
|
||||
font_string = ''
|
||||
gajim.config.set_per('themes', self.current_theme,
|
||||
gajim.config.set_per('themes', self.current_theme,
|
||||
self.current_option + 'font', font_string)
|
||||
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)
|
||||
# use faster functions for this
|
||||
if self.current_option == 'banner':
|
||||
|
@ -318,14 +318,14 @@ class GajimThemesWindow:
|
|||
return
|
||||
gajim.interface.roster.change_roster_style(self.current_option)
|
||||
gajim.interface.save_config()
|
||||
|
||||
|
||||
def _toggle_font_widgets(self, font_props):
|
||||
''' toggle font buttons with the bool values of font_props tuple'''
|
||||
self.bold_togglebutton.set_active(font_props[0])
|
||||
self.italic_togglebutton.set_active(font_props[1])
|
||||
|
||||
|
||||
def _get_font_description(self):
|
||||
''' return a FontDescription from togglebuttons
|
||||
''' return a FontDescription from togglebuttons
|
||||
states'''
|
||||
fd = pango.FontDescription()
|
||||
if self.bold_togglebutton.get_active():
|
||||
|
@ -333,7 +333,7 @@ class GajimThemesWindow:
|
|||
if self.italic_togglebutton.get_active():
|
||||
fd.set_style(pango.STYLE_ITALIC)
|
||||
return fd
|
||||
|
||||
|
||||
def _set_font_widgets(self, font_attrs):
|
||||
''' set the correct toggle state of font style buttons by
|
||||
a font string of type 'BI' '''
|
||||
|
@ -344,7 +344,7 @@ class GajimThemesWindow:
|
|||
if font_attrs.find('I') != -1:
|
||||
font_props[1] = True
|
||||
self._toggle_font_widgets(font_props)
|
||||
|
||||
|
||||
def _get_font_attrs(self):
|
||||
''' get a string with letters of font attribures: 'BI' '''
|
||||
attrs = ''
|
||||
|
@ -353,7 +353,7 @@ class GajimThemesWindow:
|
|||
if self.italic_togglebutton.get_active():
|
||||
attrs += 'I'
|
||||
return attrs
|
||||
|
||||
|
||||
|
||||
def _get_font_props(self, font_name):
|
||||
''' get tuple of font properties: Weight, Style '''
|
||||
|
|
|
@ -208,27 +208,26 @@ class GroupchatControl(ChatControlBase):
|
|||
id_ = widget.connect('row_expanded', self.on_list_treeview_row_expanded)
|
||||
self.handlers[id_] = widget
|
||||
|
||||
id_ = widget.connect('row_collapsed',
|
||||
self.on_list_treeview_row_collapsed)
|
||||
id_ = widget.connect('row_collapsed', self.on_list_treeview_row_collapsed)
|
||||
self.handlers[id_] = widget
|
||||
|
||||
id_ = widget.connect('row_activated',
|
||||
id_ = widget.connect('row_activated',
|
||||
self.on_list_treeview_row_activated)
|
||||
self.handlers[id_] = widget
|
||||
|
||||
id_ = widget.connect('button_press_event',
|
||||
id_ = widget.connect('button_press_event',
|
||||
self.on_list_treeview_button_press_event)
|
||||
self.handlers[id_] = widget
|
||||
|
||||
id_ = widget.connect('key_press_event',
|
||||
id_ = widget.connect('key_press_event',
|
||||
self.on_list_treeview_key_press_event)
|
||||
self.handlers[id_] = widget
|
||||
|
||||
id_ = widget.connect('motion_notify_event',
|
||||
id_ = widget.connect('motion_notify_event',
|
||||
self.on_list_treeview_motion_notify_event)
|
||||
self.handlers[id_] = widget
|
||||
|
||||
id_ = widget.connect('leave_notify_event',
|
||||
id_ = widget.connect('leave_notify_event',
|
||||
self.on_list_treeview_leave_notify_event)
|
||||
self.handlers[id_] = widget
|
||||
|
||||
|
@ -270,7 +269,7 @@ class GroupchatControl(ChatControlBase):
|
|||
|
||||
# nickname coloring
|
||||
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').\
|
||||
split(':'))
|
||||
|
||||
|
@ -327,7 +326,7 @@ class GroupchatControl(ChatControlBase):
|
|||
|
||||
self.list_treeview = self.xml.get_widget('list_treeview')
|
||||
selection = self.list_treeview.get_selection()
|
||||
id_ = selection.connect('changed',
|
||||
id_ = selection.connect('changed',
|
||||
self.on_list_treeview_selection_changed)
|
||||
self.handlers[id_] = selection
|
||||
id_ = self.list_treeview.connect('style-set',
|
||||
|
@ -365,7 +364,7 @@ class GroupchatControl(ChatControlBase):
|
|||
renderer_image.set_property('width', 26)
|
||||
column.pack_start(renderer_image, expand = False)
|
||||
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)
|
||||
|
||||
renderer_text = gtk.CellRendererText() # nickname
|
||||
|
@ -606,8 +605,8 @@ class GroupchatControl(ChatControlBase):
|
|||
return title
|
||||
|
||||
def draw_banner_text(self):
|
||||
'''Draw the text in the fat line at the top of the window that
|
||||
houses the room jid, subject.
|
||||
'''Draw the text in the fat line at the top of the window that
|
||||
houses the room jid, subject.
|
||||
'''
|
||||
self.name_label.set_ellipsize(pango.ELLIPSIZE_END)
|
||||
self.banner_status_label.set_ellipsize(pango.ELLIPSIZE_END)
|
||||
|
@ -827,7 +826,7 @@ class GroupchatControl(ChatControlBase):
|
|||
else:
|
||||
self.gc_count_nicknames_colors += 1
|
||||
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_count_nicknames_colors
|
||||
other_tags_for_name.append('gc_nickname_color_' + \
|
||||
|
@ -846,7 +845,7 @@ class GroupchatControl(ChatControlBase):
|
|||
elif len(self.attention_list) > 6:
|
||||
self.attention_list.pop(0) # remove older
|
||||
self.attention_list.append(contact)
|
||||
|
||||
|
||||
if sound == 'received':
|
||||
helpers.play_sound('muc_message_received')
|
||||
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
|
||||
# beginning of a real word, do not highlight for this one.
|
||||
break
|
||||
else:
|
||||
else:
|
||||
return True
|
||||
else: # Special word == word, no char after in word
|
||||
return True
|
||||
return True
|
||||
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
|
||||
# without splitting by words as previously
|
||||
# We don't search this in all cases so we don't loose time
|
||||
if text.find(special_word) > -1:
|
||||
return True
|
||||
return True
|
||||
return False
|
||||
|
||||
def set_subject(self, subject):
|
||||
|
@ -1162,9 +1161,9 @@ class GroupchatControl(ChatControlBase):
|
|||
else:
|
||||
s = _('%(nick)s is now known as %(new_nick)s') % {
|
||||
'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.
|
||||
# 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
|
||||
self.add_contact_to_roster(new_nick, show, role, affiliation,
|
||||
status, jid)
|
||||
|
@ -1361,7 +1360,7 @@ class GroupchatControl(ChatControlBase):
|
|||
role_iter = self.get_role_iter(role)
|
||||
if not role_iter:
|
||||
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))
|
||||
self.draw_all_roles()
|
||||
iter_ = model.append(role_iter, (None, nick, 'contact', name, None))
|
||||
|
@ -1771,7 +1770,7 @@ class GroupchatControl(ChatControlBase):
|
|||
# destroy banner tooltip - bug #pygtk for that!
|
||||
self.subject_tooltip.destroy()
|
||||
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
|
||||
# there may be new messages since disconnection.
|
||||
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, \
|
||||
'0', '0', password, self.nick)
|
||||
|
||||
def _on_drag_data_received(self, widget, context, x, y, selection,
|
||||
target_type, timestamp):
|
||||
def _on_drag_data_received(self, widget, context, x, y, selection,
|
||||
target_type, timestamp):
|
||||
# Invite contact to groupchat
|
||||
treeview = gajim.interface.roster.tree
|
||||
model = treeview.get_model()
|
||||
|
@ -2014,7 +2013,7 @@ class GroupchatControl(ChatControlBase):
|
|||
list_nick = gajim.contacts.get_nick_list(self.account,
|
||||
self.room_jid)
|
||||
list_nick.sort(key=unicode.lower) # case-insensitive sort
|
||||
if begin == '':
|
||||
if begin == '':
|
||||
# empty message, show lasts nicks that highlighted us first
|
||||
for nick in self.attention_list:
|
||||
if nick in list_nick:
|
||||
|
@ -2027,7 +2026,7 @@ class GroupchatControl(ChatControlBase):
|
|||
# the word is the begining of a nick
|
||||
self.nick_hits.append(nick)
|
||||
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
|
||||
# at the beginning, possibly with a space in one nick
|
||||
add = gc_refer_to_nick_char + ' '
|
||||
|
@ -2117,7 +2116,7 @@ class GroupchatControl(ChatControlBase):
|
|||
(user_affiliation=='member' and target_affiliation!='none') or \
|
||||
target_affiliation in ('admin', 'owner'):
|
||||
item.set_sensitive(False)
|
||||
id_ = item.connect('activate', self.on_voice_checkmenuitem_activate,
|
||||
id_ = item.connect('activate', self.on_voice_checkmenuitem_activate,
|
||||
nick)
|
||||
self.handlers[id_] = item
|
||||
|
||||
|
@ -2129,7 +2128,7 @@ class GroupchatControl(ChatControlBase):
|
|||
id_ = item.connect('activate', self.on_moderator_checkmenuitem_activate,
|
||||
nick)
|
||||
self.handlers[id_] = item
|
||||
|
||||
|
||||
item = xml.get_widget('ban_menuitem')
|
||||
if not user_affiliation in ('admin', 'owner') or \
|
||||
(target_affiliation in ('admin', 'owner') and\
|
||||
|
@ -2143,10 +2142,9 @@ class GroupchatControl(ChatControlBase):
|
|||
if not user_affiliation in ('admin', 'owner') or \
|
||||
(user_affiliation != 'owner' and target_affiliation in ('admin','owner')):
|
||||
item.set_sensitive(False)
|
||||
id_ = item.connect('activate', self.on_member_checkmenuitem_activate,
|
||||
jid)
|
||||
id_ = item.connect('activate', self.on_member_checkmenuitem_activate, jid)
|
||||
self.handlers[id_] = item
|
||||
|
||||
|
||||
item = xml.get_widget('admin_checkmenuitem')
|
||||
item.set_active(target_affiliation in ('admin', 'owner'))
|
||||
if not user_affiliation == 'owner':
|
||||
|
@ -2336,7 +2334,7 @@ class GroupchatControl(ChatControlBase):
|
|||
if props and self.tooltip.id == props[0]:
|
||||
rect = self.list_treeview.get_cell_area(props[0],props[1])
|
||||
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)
|
||||
else:
|
||||
self.tooltip.hide_tooltip()
|
||||
|
|
|
@ -42,11 +42,11 @@ def _info(type_, value, tb):
|
|||
_excepthook_save(type_, value, tb)
|
||||
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'),
|
||||
_('It probably is not fatal, but should be reported '
|
||||
'to the developers nonetheless.'))
|
||||
|
||||
|
||||
dialog.set_modal(False)
|
||||
#FIXME: add icon to this button
|
||||
RESPONSE_REPORT_BUG = 42
|
||||
|
@ -92,7 +92,7 @@ def _info(type_, value, tb):
|
|||
dialog.show_all()
|
||||
|
||||
_exception_in_progress.release()
|
||||
|
||||
|
||||
# gdb/kdm etc if we use startx this is not True
|
||||
if os.name == 'nt' or not sys.stderr.isatty():
|
||||
#FIXME: maybe always show dialog?
|
||||
|
|
|
@ -55,7 +55,7 @@ from common import i18n
|
|||
from common import gajim
|
||||
from common import helpers
|
||||
|
||||
gtk.glade.bindtextdomain(i18n.APP, i18n.DIR)
|
||||
gtk.glade.bindtextdomain(i18n.APP, i18n.DIR)
|
||||
gtk.glade.textdomain(i18n.APP)
|
||||
|
||||
screen_w = gtk.gdk.screen_width()
|
||||
|
@ -71,11 +71,11 @@ def get_completion_liststore(entry):
|
|||
completion list consists of (Pixbuf, Text) rows'''
|
||||
completion = gtk.EntryCompletion()
|
||||
liststore = gtk.ListStore(gtk.gdk.Pixbuf, str)
|
||||
|
||||
|
||||
render_pixbuf = gtk.CellRendererPixbuf()
|
||||
completion.pack_start(render_pixbuf, expand = False)
|
||||
completion.add_attribute(render_pixbuf, 'pixbuf', 0)
|
||||
|
||||
|
||||
render_text = gtk.CellRendererText()
|
||||
completion.pack_start(render_text, expand = True)
|
||||
completion.add_attribute(render_text, 'text', 1)
|
||||
|
@ -83,15 +83,15 @@ def get_completion_liststore(entry):
|
|||
completion.set_model(liststore)
|
||||
entry.set_completion(completion)
|
||||
return liststore
|
||||
|
||||
|
||||
|
||||
|
||||
def popup_emoticons_under_button(menu, button, parent_win):
|
||||
''' pops emoticons menu under button, which is in parent_win'''
|
||||
window_x1, window_y1 = parent_win.get_origin()
|
||||
def position_menu_under_button(menu):
|
||||
# inline function, which will not keep refs, when used as CB
|
||||
button_x, button_y = button.allocation.x, button.allocation.y
|
||||
|
||||
|
||||
# now convert them to X11-relative
|
||||
window_x, window_y = window_x1, window_y1
|
||||
x = window_x + button_x
|
||||
|
@ -113,7 +113,7 @@ def popup_emoticons_under_button(menu, button, parent_win):
|
|||
return (x, y, push_in)
|
||||
|
||||
menu.popup(None, None, position_menu_under_button, 1, 0)
|
||||
|
||||
|
||||
def get_theme_font_for_option(theme, option):
|
||||
'''return string description of the font, stored in
|
||||
theme preferences'''
|
||||
|
@ -128,12 +128,12 @@ def get_theme_font_for_option(theme, option):
|
|||
fd = pango.FontDescription(font_name)
|
||||
fd.merge(font_desc, True)
|
||||
return fd.to_string()
|
||||
|
||||
|
||||
def get_default_font():
|
||||
'''Get the desktop setting for application font
|
||||
first check for GNOME, then Xfce and last KDE
|
||||
it returns None on failure or else a string 'Font Size' '''
|
||||
|
||||
|
||||
try:
|
||||
import gconf
|
||||
# in try because daemon may not be there
|
||||
|
@ -150,11 +150,11 @@ def get_default_font():
|
|||
# and http://freedesktop.org/Standards/basedir-spec
|
||||
xdg_config_home = os.environ.get('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')
|
||||
|
||||
|
||||
kde_config_file = os.path.expanduser('~/.kde/share/config/kdeglobals')
|
||||
|
||||
|
||||
if os.path.exists(xfce_config_file):
|
||||
try:
|
||||
for line in open(xfce_config_file):
|
||||
|
@ -164,7 +164,7 @@ def get_default_font():
|
|||
except Exception:
|
||||
#we talk about file
|
||||
print >> sys.stderr, _('Error: cannot open %s for reading') % xfce_config_file
|
||||
|
||||
|
||||
elif os.path.exists(kde_config_file):
|
||||
try:
|
||||
for line in open(kde_config_file):
|
||||
|
@ -179,9 +179,9 @@ def get_default_font():
|
|||
except Exception:
|
||||
#we talk about file
|
||||
print >> sys.stderr, _('Error: cannot open %s for reading') % kde_config_file
|
||||
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def autodetect_browser_mailer():
|
||||
# recognize the environment and set appropriate browser/mailer
|
||||
if user_runs_gnome():
|
||||
|
@ -241,7 +241,7 @@ def get_running_processes():
|
|||
|
||||
# list of processes
|
||||
processes = [os.path.basename(os.readlink('/proc/' + f +'/exe')) for f in files]
|
||||
|
||||
|
||||
return processes
|
||||
return []
|
||||
|
||||
|
@ -376,12 +376,12 @@ def get_abspath_for_script(scriptname, want_type = False):
|
|||
|
||||
if scriptname == 'gajim-remote':
|
||||
path_to_script = cwd + '/gajim-remote.py'
|
||||
|
||||
|
||||
elif scriptname == 'gajim':
|
||||
script = '#!/bin/sh\n' # the script we may create
|
||||
script += 'cd %s' % cwd
|
||||
path_to_script = cwd + '/../scripts/gajim_sm_script'
|
||||
|
||||
|
||||
try:
|
||||
if os.path.exists(path_to_script):
|
||||
os.remove(path_to_script)
|
||||
|
@ -400,8 +400,8 @@ def get_abspath_for_script(scriptname, want_type = False):
|
|||
type_ = 'install'
|
||||
# always make it like '/usr/local/bin/gajim'
|
||||
path_to_script = helpers.is_in_path(scriptname, True)
|
||||
|
||||
|
||||
|
||||
|
||||
if want_type:
|
||||
return path_to_script, type_
|
||||
else:
|
||||
|
@ -458,7 +458,7 @@ def possibly_move_window_in_current_desktop(window):
|
|||
root_window = gtk.gdk.screen_get_default().get_root_window()
|
||||
# current user's vd
|
||||
current_virtual_desktop_no = get_current_desktop(root_window)
|
||||
|
||||
|
||||
# vd roster window is in
|
||||
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)'''
|
||||
if os.name != 'nt': # just in case
|
||||
return
|
||||
|
||||
|
||||
if not HAS_PYWIN32:
|
||||
return
|
||||
|
||||
|
||||
secur_att = pywintypes.SECURITY_ATTRIBUTES()
|
||||
secur_att.Initialize()
|
||||
|
||||
|
||||
try:
|
||||
# try make a handle for READING the file
|
||||
hfile = win32file.CreateFile(
|
||||
|
@ -523,7 +523,7 @@ def _get_fade_color(treeview, selected, focused):
|
|||
def get_scaled_pixbuf(pixbuf, kind):
|
||||
'''returns scaled pixbuf, keeping ratio etc or None
|
||||
kind is either "chat", "roster", "notification", "tooltip", "vcard"'''
|
||||
|
||||
|
||||
# resize to a width / height for the avatar not to have distortion
|
||||
# (keep aspect ratio)
|
||||
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'):
|
||||
path_to_local_file_full = path_to_local_file + extension
|
||||
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'):
|
||||
path_to_file_full = path_to_file + extension
|
||||
if os.path.exists(path_to_file_full):
|
||||
|
@ -641,7 +641,7 @@ def decode_filechooser_file_paths(file_paths):
|
|||
ask sys.getfilesystemencoding() in POSIX
|
||||
file_paths MUST be LIST'''
|
||||
file_paths_list = list()
|
||||
|
||||
|
||||
if os.name == 'nt': # decode as UTF-8 under Windows
|
||||
for file_path in file_paths:
|
||||
file_path = file_path.decode('utf8')
|
||||
|
@ -656,14 +656,14 @@ def decode_filechooser_file_paths(file_paths):
|
|||
except Exception:
|
||||
pass
|
||||
file_paths_list.append(file_path)
|
||||
|
||||
|
||||
return file_paths_list
|
||||
|
||||
def possibly_set_gajim_as_xmpp_handler():
|
||||
'''registers (by default only the first time) xmmp: to Gajim.'''
|
||||
path_to_dot_kde = os.path.expanduser('~/.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')
|
||||
else:
|
||||
path_to_kde_file = None
|
||||
|
@ -814,7 +814,7 @@ default_name = ''):
|
|||
# check if we have write permissions
|
||||
if not os.access(file_path, os.W_OK):
|
||||
file_name = os.path.basename(file_path)
|
||||
dialogs.ErrorDialog(_('Cannot overwrite existing file "%s"' %
|
||||
dialogs.ErrorDialog(_('Cannot overwrite existing file "%s"' %
|
||||
file_name),
|
||||
_('A file with this name already exists and you do not have '
|
||||
'permission to overwrite it.'))
|
||||
|
@ -837,7 +837,7 @@ default_name = ''):
|
|||
def on_cancel(widget):
|
||||
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,
|
||||
gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK),
|
||||
default_response=gtk.RESPONSE_OK,
|
||||
|
|
|
@ -55,7 +55,7 @@ import time
|
|||
import locale
|
||||
|
||||
from common import i18n
|
||||
import common.configpaths
|
||||
import common.configpaths
|
||||
common.configpaths.gajimpaths.init()
|
||||
common.configpaths.gajimpaths.init_profile()
|
||||
from common import exceptions
|
||||
|
@ -63,9 +63,9 @@ import dialogs
|
|||
import gtkgui_helpers
|
||||
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 \
|
||||
constants.__dict__.keys() if i.startswith('SHOW_'))
|
||||
constants.__dict__.keys() if i.startswith('SHOW_'))
|
||||
from common import gajim
|
||||
from common import helpers
|
||||
|
||||
|
@ -92,12 +92,12 @@ class HistoryManager:
|
|||
path_to_file = os.path.join(gajim.DATA_DIR, 'pixmaps/gajim.png')
|
||||
pix = gtk.gdk.pixbuf_new_from_file(path_to_file)
|
||||
gtk.window_set_default_icon(pix) # set the icon to all newly opened windows
|
||||
|
||||
|
||||
if not os.path.exists(LOG_DB_PATH):
|
||||
dialogs.ErrorDialog(_('Cannot find history logs database'),
|
||||
'%s does not exist.' % LOG_DB_PATH)
|
||||
sys.exit()
|
||||
|
||||
|
||||
xml = gtkgui_helpers.get_glade('history_manager.glade')
|
||||
self.window = xml.get_widget('history_manager_window')
|
||||
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.AT_LEAST_ONE_DELETION_DONE = False
|
||||
|
||||
|
||||
self.con = sqlite.connect(LOG_DB_PATH, timeout = 20.0,
|
||||
isolation_level = 'IMMEDIATE')
|
||||
self.cur = self.con.cursor()
|
||||
|
@ -119,15 +119,15 @@ class HistoryManager:
|
|||
self._init_jids_listview()
|
||||
self._init_logs_listview()
|
||||
self._init_search_results_listview()
|
||||
|
||||
|
||||
self._fill_jids_listview()
|
||||
|
||||
|
||||
self.search_entry.grab_focus()
|
||||
|
||||
self.window.show_all()
|
||||
|
||||
|
||||
xml.signal_autoconnect(self)
|
||||
|
||||
|
||||
def _init_jids_listview(self):
|
||||
self.jids_liststore = gtk.ListStore(str, str) # jid, jid_id
|
||||
self.jids_listview.set_model(self.jids_liststore)
|
||||
|
@ -136,7 +136,7 @@ class HistoryManager:
|
|||
renderer_text = gtk.CellRendererText() # holds jid
|
||||
col = gtk.TreeViewColumn(_('Contacts'), renderer_text, text = 0)
|
||||
self.jids_listview.append_column(col)
|
||||
|
||||
|
||||
self.jids_listview.get_selection().connect('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_resizable(True)
|
||||
self.logs_listview.append_column(col)
|
||||
|
||||
|
||||
renderer_text = gtk.CellRendererText() # holds nickname
|
||||
col = gtk.TreeViewColumn(_('Nickname'), renderer_text, text = C_NICKNAME)
|
||||
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
|
||||
self.search_results_liststore = gtk.ListStore(str, str, str, str, str, str)
|
||||
self.search_results_listview.set_model(self.search_results_liststore)
|
||||
|
||||
|
||||
renderer_text = gtk.CellRendererText() # holds JID (who said this)
|
||||
col = gtk.TreeViewColumn(_('JID'), renderer_text, text = 1)
|
||||
col.set_sort_column_id(1) # user can click this header and sort
|
||||
col.set_resizable(True)
|
||||
self.search_results_listview.append_column(col)
|
||||
|
||||
|
||||
renderer_text = gtk.CellRendererText() # holds time
|
||||
col = gtk.TreeViewColumn(_('Date'), renderer_text, text = C_UNIXTIME)
|
||||
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_resizable(True)
|
||||
self.search_results_listview.append_column(col)
|
||||
|
||||
|
||||
renderer_text = gtk.CellRendererText() # holds 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_resizable(True)
|
||||
self.search_results_listview.append_column(col)
|
||||
|
||||
|
||||
def on_history_manager_window_delete_event(self, widget, event):
|
||||
if self.AT_LEAST_ONE_DELETION_DONE:
|
||||
def on_yes(clicked):
|
||||
|
@ -229,9 +229,9 @@ class HistoryManager:
|
|||
'\n\nIn case you click YES, please wait...'),
|
||||
on_response_yes=on_yes, on_response_no=on_no)
|
||||
return
|
||||
|
||||
|
||||
gtk.main_quit()
|
||||
|
||||
|
||||
def _fill_jids_listview(self):
|
||||
# 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 '
|
||||
|
@ -240,7 +240,7 @@ class HistoryManager:
|
|||
for row in rows:
|
||||
self.jids_already_in.append(row[0]) # jid
|
||||
self.jids_liststore.append(row) # jid, jid_id
|
||||
|
||||
|
||||
def on_jids_listview_selection_changed(self, widget, data = None):
|
||||
liststore, list_of_paths = self.jids_listview.get_selection()\
|
||||
.get_selected_rows()
|
||||
|
@ -249,7 +249,7 @@ class HistoryManager:
|
|||
return
|
||||
|
||||
self.logs_liststore.clear() # clear the store
|
||||
|
||||
|
||||
self.welcome_vbox.hide()
|
||||
self.search_results_scrolledwindow.hide()
|
||||
self.logs_scrolledwindow.show()
|
||||
|
@ -257,14 +257,14 @@ class HistoryManager:
|
|||
list_of_rowrefs = []
|
||||
for path in list_of_paths: # make them treerowrefs (it's needed)
|
||||
list_of_rowrefs.append(gtk.TreeRowReference(liststore, path))
|
||||
|
||||
|
||||
for rowref in list_of_rowrefs: # FILL THE STORE, for all rows selected
|
||||
path = rowref.get_path()
|
||||
if path is None:
|
||||
continue
|
||||
jid = liststore[path][0] # jid
|
||||
self._fill_logs_listview(jid)
|
||||
|
||||
|
||||
def _get_jid_id(self, jid):
|
||||
'''jids table has jid and jid_id
|
||||
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
|
||||
(user will see the first pm as if it was message in room's public chat)
|
||||
and after that all okay'''
|
||||
|
||||
|
||||
possible_room_jid = jid.split('/', 1)[0]
|
||||
|
||||
|
||||
self.cur.execute('SELECT jid_id FROM jids WHERE jid = ? AND type = ?',
|
||||
(possible_room_jid, constants.JID_ROOM_TYPE))
|
||||
row = self.cur.fetchone()
|
||||
|
@ -317,7 +317,7 @@ class HistoryManager:
|
|||
return True
|
||||
else: # normal type
|
||||
return False
|
||||
|
||||
|
||||
def _fill_logs_listview(self, jid):
|
||||
'''fill the listview with all messages that user sent to or
|
||||
received from JID'''
|
||||
|
@ -332,7 +332,7 @@ class HistoryManager:
|
|||
''', (jid_id,))
|
||||
|
||||
results = self.cur.fetchall()
|
||||
|
||||
|
||||
if self._jid_is_room_type(jid): # is it room?
|
||||
self.nickname_col_for_logs.set_visible(True)
|
||||
self.subject_col_for_logs.set_visible(False)
|
||||
|
@ -367,7 +367,7 @@ class HistoryManager:
|
|||
if message is None:
|
||||
message = ''
|
||||
else:
|
||||
message = ' : ' + message
|
||||
message = ' : ' + message
|
||||
message = helpers.get_uf_show(gajim.SHOW_LIST[show]) + message
|
||||
|
||||
message_ = '<span'
|
||||
|
@ -388,7 +388,7 @@ class HistoryManager:
|
|||
WHERE message LIKE ? OR subject LIKE ?
|
||||
ORDER BY time
|
||||
''', (like_sql, like_sql))
|
||||
|
||||
|
||||
results = self.cur.fetchall()
|
||||
for row in results:
|
||||
# exposed in UI (TreeViewColumns) are only
|
||||
|
@ -403,7 +403,7 @@ class HistoryManager:
|
|||
pass
|
||||
else:
|
||||
jid = self._get_jid_from_jid_id(jid_id)
|
||||
|
||||
|
||||
self.search_results_liststore.append((log_line_id, jid, time_,
|
||||
message, subject, nickname))
|
||||
|
||||
|
@ -412,7 +412,7 @@ class HistoryManager:
|
|||
.get_selected_rows()
|
||||
if event.keyval == gtk.keysyms.Delete:
|
||||
self._delete_logs(liststore, list_of_paths)
|
||||
|
||||
|
||||
def on_listview_button_press_event(self, widget, event):
|
||||
if event.button == 3: # right click
|
||||
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('delete_menuitem').connect('activate',
|
||||
self.on_delete_menuitem_activate, widget)
|
||||
|
||||
|
||||
xml.signal_autoconnect(self)
|
||||
xml.get_widget('context_menu').popup(None, None, None,
|
||||
event.button, event.time)
|
||||
|
@ -429,21 +429,21 @@ class HistoryManager:
|
|||
def on_export_menuitem_activate(self, widget):
|
||||
xml = gtkgui_helpers.get_glade('history_manager.glade', 'filechooserdialog')
|
||||
xml.signal_autoconnect(self)
|
||||
|
||||
|
||||
dlg = xml.get_widget('filechooserdialog')
|
||||
dlg.set_title(_('Exporting History Logs...'))
|
||||
dlg.set_current_folder(gajim.HOME_DIR)
|
||||
dlg.props.do_overwrite_confirmation = True
|
||||
response = dlg.run()
|
||||
|
||||
|
||||
if response == gtk.RESPONSE_OK: # user want us to export ;)
|
||||
liststore, list_of_paths = self.jids_listview.get_selection()\
|
||||
.get_selected_rows()
|
||||
path_to_file = dlg.get_filename()
|
||||
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):
|
||||
liststore, list_of_paths = listview.get_selection().get_selected_rows()
|
||||
if listview.name == 'jids_listview':
|
||||
|
@ -467,7 +467,7 @@ class HistoryManager:
|
|||
list_of_rowrefs = []
|
||||
for path in list_of_paths: # make them treerowrefs (it's needed)
|
||||
list_of_rowrefs.append(gtk.TreeRowReference(liststore, path))
|
||||
|
||||
|
||||
for rowref in list_of_rowrefs:
|
||||
path = rowref.get_path()
|
||||
if path is None:
|
||||
|
@ -508,7 +508,7 @@ class HistoryManager:
|
|||
|
||||
file_.write(_('%(who)s on %(time)s said: %(message)s\n') % {'who': who,
|
||||
'time': time_, 'message': message})
|
||||
|
||||
|
||||
def _delete_jid_logs(self, liststore, list_of_paths):
|
||||
paths_len = len(list_of_paths)
|
||||
if paths_len == 0: # nothing is selected
|
||||
|
@ -577,7 +577,7 @@ class HistoryManager:
|
|||
|
||||
self.AT_LEAST_ONE_DELETION_DONE = True
|
||||
|
||||
|
||||
|
||||
pri_text = i18n.ngettext(
|
||||
'Do you really want to delete the selected message?',
|
||||
'Do you really want to delete the selected messages?', paths_len)
|
||||
|
@ -593,7 +593,7 @@ class HistoryManager:
|
|||
self.welcome_vbox.hide()
|
||||
self.logs_scrolledwindow.hide()
|
||||
self.search_results_scrolledwindow.show()
|
||||
|
||||
|
||||
self._fill_search_results_listview(text)
|
||||
|
||||
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
|
||||
# as this is what db returns so I don't have to fight with types
|
||||
jid_id = self._get_jid_id(jid)
|
||||
|
||||
|
||||
|
||||
|
||||
iter_ = self.jids_liststore.get_iter_root()
|
||||
while iter_:
|
||||
# self.jids_liststore[iter_][1] holds jid_ids
|
||||
if self.jids_liststore[iter_][1] == jid_id:
|
||||
break
|
||||
iter_ = self.jids_liststore.iter_next(iter_)
|
||||
|
||||
|
||||
if iter_ is None:
|
||||
return
|
||||
|
||||
path = self.jids_liststore.get_path(iter_)
|
||||
self.jids_listview.set_cursor(path)
|
||||
|
||||
|
||||
iter_ = self.logs_liststore.get_iter_root()
|
||||
while iter_:
|
||||
# self.logs_liststore[iter_][0] holds lon_line_ids
|
||||
if self.logs_liststore[iter_][0] == log_line_id:
|
||||
break
|
||||
iter_ = self.logs_liststore.iter_next(iter_)
|
||||
|
||||
|
||||
path = self.logs_liststore.get_path(iter_)
|
||||
self.logs_listview.scroll_to_cell(path)
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ class HistoryWindow:
|
|||
self.query_combobox.set_active(0)
|
||||
self.results_treeview = xml.get_widget('results_treeview')
|
||||
self.results_window = xml.get_widget('results_scrolledwindow')
|
||||
|
||||
|
||||
# contact_name, date, message, time
|
||||
model = gtk.ListStore(str, str, str, str, str)
|
||||
self.results_treeview.set_model(model)
|
||||
|
@ -91,7 +91,7 @@ class HistoryWindow:
|
|||
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_resizable(True)
|
||||
|
||||
|
||||
col = gtk.TreeViewColumn(_('Date'))
|
||||
self.results_treeview.append_column(col)
|
||||
renderer = gtk.CellRendererText()
|
||||
|
@ -99,14 +99,14 @@ class HistoryWindow:
|
|||
col.set_attributes(renderer, text = C_UNIXTIME)
|
||||
col.set_sort_column_id(C_UNIXTIME) # user can click this header and sort
|
||||
col.set_resizable(True)
|
||||
|
||||
|
||||
col = gtk.TreeViewColumn(_('Message'))
|
||||
self.results_treeview.append_column(col)
|
||||
renderer = gtk.CellRendererText()
|
||||
col.pack_start(renderer)
|
||||
col.set_attributes(renderer, text = C_MESSAGE)
|
||||
col.set_resizable(True)
|
||||
|
||||
|
||||
self.jid = None # The history we are currently viewing
|
||||
self.account = None
|
||||
self.completion_dict = {}
|
||||
|
@ -117,7 +117,7 @@ class HistoryWindow:
|
|||
gobject.idle_add(self._fill_completion_dict().next)
|
||||
|
||||
if jid:
|
||||
self.jid_entry.set_text(jid)
|
||||
self.jid_entry.set_text(jid)
|
||||
|
||||
gtkgui_helpers.resize_window(self.window,
|
||||
gajim.config.get('history_window_width'),
|
||||
|
@ -125,17 +125,17 @@ class HistoryWindow:
|
|||
gtkgui_helpers.move_window(self.window,
|
||||
gajim.config.get('history_window_x-position'),
|
||||
gajim.config.get('history_window_y-position'))
|
||||
|
||||
|
||||
xml.signal_autoconnect(self)
|
||||
self.window.show_all()
|
||||
|
||||
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).
|
||||
|
||||
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....")
|
||||
|
||||
|
||||
{key : (jid, account, nick_name, full_completion_name}
|
||||
this is a generator and does pseudo-threading via idle_add()
|
||||
'''
|
||||
|
@ -144,19 +144,19 @@ class HistoryWindow:
|
|||
# Add all jids in logs.db:
|
||||
db_jids = gajim.logger.get_jids_in_db()
|
||||
self.completion_dict = dict.fromkeys(db_jids)
|
||||
|
||||
|
||||
self.accounts_seen_online = gajim.contacts.get_accounts()[:]
|
||||
|
||||
# Enhance contacts of online accounts with contact. Needed for mapping below
|
||||
for account in self.accounts_seen_online:
|
||||
self.completion_dict.update(
|
||||
helpers.get_contact_dict_for_account(account))
|
||||
|
||||
|
||||
muc_active_img = gtkgui_helpers.load_icon('muc_active')
|
||||
contact_img = gajim.interface.jabber_state_images['16']['online']
|
||||
muc_active_pix = muc_active_img.get_pixbuf()
|
||||
contact_pix = contact_img.get_pixbuf()
|
||||
|
||||
|
||||
keys = self.completion_dict.keys()
|
||||
# Move the actual jid at first so we load history faster
|
||||
actual_jid = self.jid_entry.get_text().decode('utf-8')
|
||||
|
@ -166,7 +166,7 @@ class HistoryWindow:
|
|||
if None in keys:
|
||||
keys.remove(None)
|
||||
# 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:
|
||||
completed = key
|
||||
contact = self.completion_dict[completed]
|
||||
|
@ -179,9 +179,9 @@ class HistoryWindow:
|
|||
info_name = completed.split('@')[0]
|
||||
info_completion = completed
|
||||
info_jid = completed
|
||||
|
||||
|
||||
info_acc = self._get_account_for_jid(info_jid)
|
||||
|
||||
|
||||
if gajim.logger.jid_is_room_jid(completed) or\
|
||||
gajim.logger.jid_is_from_pm(completed):
|
||||
pix = muc_active_pix
|
||||
|
@ -204,7 +204,7 @@ class HistoryWindow:
|
|||
yield True
|
||||
keys.sort()
|
||||
yield False
|
||||
|
||||
|
||||
def _get_account_for_jid(self, jid):
|
||||
'''Return the corresponding account of the jid.
|
||||
May be None if an account could not be found'''
|
||||
|
@ -245,8 +245,8 @@ class HistoryWindow:
|
|||
widget.select_region(0, -1) # select text
|
||||
|
||||
def _load_history(self, jid_or_name, account = None):
|
||||
'''Load history for the given jid/name and show it'''
|
||||
if jid_or_name and jid_or_name in self.completion_dict:
|
||||
'''Load history for the given jid/name and show it'''
|
||||
if jid_or_name and jid_or_name in self.completion_dict:
|
||||
# a full qualified jid or a contact name was entered
|
||||
info_jid, info_account, info_name, info_completion = self.completion_dict[jid_or_name]
|
||||
self.jids_to_search = [info_jid]
|
||||
|
@ -256,7 +256,7 @@ class HistoryWindow:
|
|||
self.account = account
|
||||
else:
|
||||
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
|
||||
# account not connected.
|
||||
# Disable possibility to say if we want to log or not
|
||||
|
@ -275,7 +275,7 @@ class HistoryWindow:
|
|||
log = False
|
||||
self.checkbutton.set_active(log)
|
||||
self.checkbutton.set_sensitive(True)
|
||||
|
||||
|
||||
self.jids_to_search = [info_jid]
|
||||
|
||||
# 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)
|
||||
self.calendar.select_month(gtk_month, y)
|
||||
self.calendar.select_day(d)
|
||||
|
||||
|
||||
self.query_entry.set_sensitive(True)
|
||||
self.query_entry.grab_focus()
|
||||
|
||||
|
@ -301,7 +301,7 @@ class HistoryWindow:
|
|||
# we have got nothing to show or to search in
|
||||
self.jid = None
|
||||
self.account = None
|
||||
|
||||
|
||||
self.history_buffer.set_text('') # clear the buffer
|
||||
self.query_entry.set_sensitive(False)
|
||||
|
||||
|
@ -310,7 +310,7 @@ class HistoryWindow:
|
|||
self.calendar.clear_marks()
|
||||
|
||||
self.results_window.set_property('visible', False)
|
||||
|
||||
|
||||
title = _('Conversation History')
|
||||
self.window.set_title(title)
|
||||
|
||||
|
@ -320,9 +320,9 @@ class HistoryWindow:
|
|||
year, month, day = widget.get_date() # integers
|
||||
month = gtkgui_helpers.make_gtk_month_python_month(month)
|
||||
self._add_lines_for_date(year, month, day)
|
||||
|
||||
|
||||
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)
|
||||
'''
|
||||
if not self.jid:
|
||||
|
@ -371,7 +371,7 @@ class HistoryWindow:
|
|||
# line[0] is contact_name, line[1] is time of 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])
|
||||
|
||||
|
||||
def _add_new_line(self, contact_name, tim, kind, show, message):
|
||||
'''add a new line in textbuffer'''
|
||||
if not message and kind not in (constants.KIND_STATUS,
|
||||
|
@ -379,7 +379,7 @@ class HistoryWindow:
|
|||
return
|
||||
buf = self.history_buffer
|
||||
end_iter = buf.get_end_iter()
|
||||
|
||||
|
||||
if gajim.config.get('print_time') == 'always':
|
||||
timestamp_str = gajim.config.get('time_stamp')
|
||||
timestamp_str = helpers.from_one_line(timestamp_str)
|
||||
|
@ -397,9 +397,9 @@ class HistoryWindow:
|
|||
|
||||
tag_name = ''
|
||||
tag_msg = ''
|
||||
|
||||
|
||||
show = self._get_string_show_from_constant_int(show)
|
||||
|
||||
|
||||
if kind == constants.KIND_GC_MSG:
|
||||
tag_name = 'incoming'
|
||||
elif kind in (constants.KIND_SINGLE_MSG_RECV,
|
||||
|
@ -410,10 +410,10 @@ class HistoryWindow:
|
|||
constants.KIND_CHAT_MSG_SENT):
|
||||
if self.account:
|
||||
contact_name = gajim.nicks[self.account]
|
||||
else:
|
||||
else:
|
||||
# we don't have roster, we don't know our own nick, use first
|
||||
# account one (urk!)
|
||||
account = gajim.contacts.get_accounts()[0]
|
||||
account = gajim.contacts.get_accounts()[0]
|
||||
contact_name = gajim.nicks[account]
|
||||
tag_name = 'outgoing'
|
||||
elif kind == constants.KIND_GCSTATUS:
|
||||
|
@ -458,7 +458,7 @@ class HistoryWindow:
|
|||
model = self.results_treeview.get_model()
|
||||
model.clear()
|
||||
if text == '':
|
||||
self.results_window.set_property('visible', False)
|
||||
self.results_window.set_property('visible', False)
|
||||
return
|
||||
else:
|
||||
self.results_window.set_property('visible', True)
|
||||
|
@ -493,7 +493,7 @@ class HistoryWindow:
|
|||
local_time = time.localtime(tim)
|
||||
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)
|
||||
model.append((jid, contact_name, date, message, tim))
|
||||
|
||||
|
@ -513,14 +513,14 @@ class HistoryWindow:
|
|||
# Groupchat Histories
|
||||
self.query_entry.set_sensitive(True)
|
||||
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 self.query_combobox.get_active() == 2:
|
||||
# All Chat Histories
|
||||
self.query_entry.set_sensitive(True)
|
||||
self.query_entry.grab_focus()
|
||||
self.jids_to_search = gajim.logger.get_jids_in_db()
|
||||
|
||||
|
||||
def on_results_treeview_row_activated(self, widget, path, column):
|
||||
'''a row was double clicked, get date from row, and select it in calendar
|
||||
which results to showing conversation logs for that date'''
|
||||
|
@ -534,7 +534,7 @@ class HistoryWindow:
|
|||
gtk_month = tim[1]
|
||||
month = gtkgui_helpers.make_python_month_gtk_month(gtk_month)
|
||||
day = tim[2]
|
||||
|
||||
|
||||
# switch to belonging logfile if necessary
|
||||
log_jid = model[path][C_LOG_JID]
|
||||
if log_jid != self.jid:
|
||||
|
@ -543,7 +543,7 @@ class HistoryWindow:
|
|||
# avoid reruning mark days algo if same month and year!
|
||||
if year != cur_year or gtk_month != cur_month:
|
||||
self.calendar.select_month(month, year)
|
||||
|
||||
|
||||
self.calendar.select_day(day)
|
||||
unix_time = model[path][C_TIME]
|
||||
self._scroll_to_result(unix_time)
|
||||
|
@ -564,7 +564,7 @@ class HistoryWindow:
|
|||
match_end_iter.forward_line() # highlight all message not just time
|
||||
self.history_buffer.apply_tag_by_name('highlight', match_start_iter,
|
||||
match_end_iter)
|
||||
|
||||
|
||||
match_start_mark = self.history_buffer.create_mark('match_start',
|
||||
match_start_iter, 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)
|
||||
else:
|
||||
# Only in that case because it's called by self._fill_completion_dict()
|
||||
# otherwise
|
||||
# otherwise
|
||||
self._load_history(jid, account)
|
||||
self.results_window.set_property('visible', False)
|
||||
|
||||
|
|
|
@ -241,7 +241,7 @@ def _parse_css_color(color):
|
|||
|
||||
def style_iter(style):
|
||||
return (map(lambda x:x.strip(),item.split(':', 1)) for item in style.split(';') if len(item.strip()))
|
||||
|
||||
|
||||
|
||||
class HtmlHandler(xml.sax.handler.ContentHandler):
|
||||
"""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.forward_char()
|
||||
return attrs
|
||||
|
||||
|
||||
else:
|
||||
|
||||
|
||||
# Workaround http://bugzilla.gnome.org/show_bug.cgi?id=317455
|
||||
def _get_current_style_attr(self, propname, comb_oper=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)
|
||||
# limits: 1% to 500%
|
||||
val = sign*max(1,min(abs(val),500))
|
||||
frac = val/100
|
||||
frac = val/100
|
||||
if font_relative:
|
||||
attrs = self._get_current_attributes()
|
||||
font_size = attrs.font.get_size() / pango.SCALE
|
||||
|
@ -378,7 +378,7 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
|
|||
callback(val, *args)
|
||||
except Exception:
|
||||
warnings.warn('Unable to parse length value "%s"' % value)
|
||||
|
||||
|
||||
def __parse_font_size_cb(length, tag):
|
||||
tag.set_property('size-points', length/display_resolution)
|
||||
__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)
|
||||
tag.set_property(propname, length)
|
||||
#__frac_length_tag_cb = staticmethod(__frac_length_tag_cb)
|
||||
|
||||
|
||||
def _parse_style_margin_left(self, tag, value):
|
||||
# block relative
|
||||
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)
|
||||
else:
|
||||
tag.set_property('justification', align)
|
||||
|
||||
|
||||
def _parse_style_text_decoration(self, tag, value):
|
||||
values = value.split(' ')
|
||||
if 'none' in values:
|
||||
|
@ -497,7 +497,7 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
|
|||
warnings.warn('text-decoration:blink not implemented')
|
||||
if 'overline' in values:
|
||||
warnings.warn('text-decoration:overline not implemented')
|
||||
|
||||
|
||||
def _parse_style_white_space(self, tag, value):
|
||||
if value == 'pre':
|
||||
tag.set_property('wrap_mode', gtk.WRAP_NONE)
|
||||
|
@ -511,7 +511,7 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
|
|||
tag.set_property(propname, value)
|
||||
except Exception:
|
||||
gajim.log.warn( "Error with prop: " + propname + " for tag: " + str(tag))
|
||||
|
||||
|
||||
|
||||
def _parse_style_width(self, tag, value):
|
||||
if value == 'auto':
|
||||
|
@ -523,8 +523,8 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
|
|||
return
|
||||
self._parse_length(value, False, False, 1, 1000, self.__length_tag_cb,
|
||||
tag, "height")
|
||||
|
||||
|
||||
|
||||
|
||||
# build a dictionary mapping styles to methods, for greater speed
|
||||
__style_methods = dict()
|
||||
for style in ('background-color', 'color', 'font-family', 'font-size',
|
||||
|
@ -562,20 +562,20 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
|
|||
'''Process a img tag.
|
||||
'''
|
||||
try:
|
||||
# Wait maximum 1s for connection
|
||||
# Wait maximum 1s for connection
|
||||
socket.setdefaulttimeout(1)
|
||||
try:
|
||||
f = urllib2.urlopen(attrs['src'])
|
||||
except Exception, ex:
|
||||
try:
|
||||
f = urllib2.urlopen(attrs['src'])
|
||||
except Exception, ex:
|
||||
gajim.log.debug('Error loading image %s ' % attrs['src'] + str(ex))
|
||||
pixbuf = None
|
||||
alt = attrs.get('alt', 'Broken image')
|
||||
else:
|
||||
# Wait 0.1s between each byte
|
||||
try:
|
||||
f.fp._sock.fp._sock.settimeout(0.5)
|
||||
except Exception:
|
||||
pass
|
||||
pixbuf = None
|
||||
alt = attrs.get('alt', 'Broken image')
|
||||
else:
|
||||
# Wait 0.1s between each byte
|
||||
try:
|
||||
f.fp._sock.fp._sock.settimeout(0.5)
|
||||
except Exception:
|
||||
pass
|
||||
# Max image size = 2 MB (to try to prevent DoS)
|
||||
mem = ''
|
||||
deadline = time.time() + 3
|
||||
|
@ -717,7 +717,7 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
|
|||
|
||||
def _starts_line(self):
|
||||
return self.starting or self.iter.starts_line()
|
||||
|
||||
|
||||
def _flush_text(self):
|
||||
if not self.text: return
|
||||
text, self.text = self.text, ''
|
||||
|
@ -762,7 +762,7 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
|
|||
img = gtk.Image()
|
||||
img.set_from_file(self.textview.interface.emoticons[emot_ascii])
|
||||
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)
|
||||
elif af:
|
||||
# now print it
|
||||
|
@ -779,7 +779,7 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
|
|||
self.endElement('i')
|
||||
if index < len(text):
|
||||
self._insert_text(text[index:])
|
||||
|
||||
|
||||
def characters(self, content):
|
||||
if self.preserve:
|
||||
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
|
||||
# the whole textview, so we need to add something like the
|
||||
# message-id to it.
|
||||
#id_ = attrs.get('id',None)
|
||||
#id_ = attrs.get('id',None)
|
||||
id_ = None
|
||||
if name == 'a':
|
||||
#TODO: accesskey, charset, hreflang, rel, rev, tabindex, type
|
||||
|
@ -827,11 +827,11 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
|
|||
tag = self._process_img(attrs)
|
||||
if name in element_styles:
|
||||
style += element_styles[name]
|
||||
# so that explicit styles override implicit ones,
|
||||
# so that explicit styles override implicit ones,
|
||||
# we add the attribute last
|
||||
style += ";"+attrs.get('style','')
|
||||
if style == '':
|
||||
style = None
|
||||
style = None
|
||||
self._begin_span(style, tag, id_)
|
||||
|
||||
if name == 'br':
|
||||
|
@ -917,7 +917,7 @@ class HtmlHandler(xml.sax.handler.ContentHandler):
|
|||
# self.text = ' '
|
||||
|
||||
class HtmlTextView(gtk.TextView):
|
||||
|
||||
|
||||
def __init__(self):
|
||||
gobject.GObject.__init__(self)
|
||||
self.set_wrap_mode(gtk.WRAP_CHAR)
|
||||
|
@ -992,7 +992,7 @@ class HtmlTextView(gtk.TextView):
|
|||
parser = xml.sax.make_parser()
|
||||
parser.setContentHandler(HtmlHandler(self, eob))
|
||||
parser.parse(StringIO(html))
|
||||
|
||||
|
||||
# too much space after :)
|
||||
#if not eob.starts_line():
|
||||
# buffer_.insert(eob, '\n')
|
||||
|
@ -1075,7 +1075,7 @@ if __name__ == '__main__':
|
|||
htmlview.display_html('<hr />')
|
||||
htmlview.display_html('''
|
||||
<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'm <span style='color:green'>green</span>
|
||||
with <span style='font-weight: bold'>envy</span>!
|
||||
</p>
|
||||
|
@ -1094,8 +1094,8 @@ if __name__ == '__main__':
|
|||
<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:right'><img src='http://www.jabber.org/images/psa-license.jpg'
|
||||
alt='A License to Jabber'
|
||||
width='50%' height='50%'
|
||||
alt='A License to Jabber'
|
||||
width='50%' height='50%'
|
||||
/></p>
|
||||
</body>
|
||||
''')
|
||||
|
@ -1107,7 +1107,7 @@ if __name__ == '__main__':
|
|||
<li> Two </li>
|
||||
<li> Three </li>
|
||||
</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
|
||||
return faciter(n-1, acc*n)
|
||||
if n<0: raise ValueError('Must be non-negative')
|
||||
|
|
|
@ -37,8 +37,8 @@ Provides IPython console widget.
|
|||
@copyright: Copyright (c) 2007 IBM Corporation
|
||||
@license: BSD
|
||||
|
||||
All rights reserved. This program and the accompanying materials are made
|
||||
available under the terms of the BSD which accompanies this distribution, and
|
||||
All rights reserved. This program and the accompanying materials are made
|
||||
available under the terms of the BSD which accompanies this distribution, and
|
||||
is available at U{http://www.opensource.org/licenses/bsd-license.php}
|
||||
'''
|
||||
|
||||
|
@ -57,7 +57,7 @@ except ImportError:
|
|||
class IterableIPShell:
|
||||
'''
|
||||
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.
|
||||
|
||||
@ivar IP: IPython instance.
|
||||
|
@ -65,17 +65,17 @@ class IterableIPShell:
|
|||
@ivar iter_more: Indicates if the line executed was a complete command,
|
||||
or we should wait for more.
|
||||
@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.
|
||||
@type history_level: integer
|
||||
@ivar complete_sep: Seperation delimeters for completion function.
|
||||
@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):
|
||||
'''
|
||||
|
||||
|
||||
|
||||
|
||||
@param argv: Command line options for IPython
|
||||
@type argv: list
|
||||
@param user_ns: User namespace.
|
||||
|
@ -85,7 +85,7 @@ class IterableIPShell:
|
|||
@param cin: Console standard input.
|
||||
@type cin: IO stream
|
||||
@param cout: Console standard output.
|
||||
@type cout: IO stream
|
||||
@type cout: IO stream
|
||||
@param cerr: Console standard error.
|
||||
@type cerr: IO stream
|
||||
@param input_func: Replacement for builtin raw_input()
|
||||
|
@ -100,13 +100,13 @@ class IterableIPShell:
|
|||
if 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.iplib.raw_input = lambda x: None
|
||||
|
||||
self.term = IPython.genutils.IOTerm(cin=cin, cout=cout, cerr=cerr)
|
||||
os.environ['TERM'] = 'dumb'
|
||||
excepthook = sys.excepthook
|
||||
excepthook = sys.excepthook
|
||||
self.IP = IPython.Shell.make_IPython(
|
||||
argv,user_ns=user_ns,
|
||||
user_global_ns=user_global_ns,
|
||||
|
@ -136,7 +136,7 @@ class IterableIPShell:
|
|||
self.IP.resetbuffer()
|
||||
# keep cache in sync with the prompt counter:
|
||||
self.IP.outputcache.prompt_count -= 1
|
||||
|
||||
|
||||
if self.IP.autoindent:
|
||||
self.IP.indent_current_nsp = 0
|
||||
self.iter_more = 0
|
||||
|
@ -158,27 +158,27 @@ class IterableIPShell:
|
|||
def historyBack(self):
|
||||
'''
|
||||
Provides one history command back.
|
||||
|
||||
|
||||
@return: The command string.
|
||||
@rtype: string
|
||||
'''
|
||||
self.history_level -= 1
|
||||
return self._getHistory()
|
||||
|
||||
|
||||
def historyForward(self):
|
||||
'''
|
||||
Provides one history command forward.
|
||||
|
||||
|
||||
@return: The command string.
|
||||
@rtype: string
|
||||
'''
|
||||
self.history_level += 1
|
||||
return self._getHistory()
|
||||
|
||||
|
||||
def _getHistory(self):
|
||||
'''
|
||||
Get's the command string of the current history level.
|
||||
|
||||
|
||||
@return: Historic command string.
|
||||
@rtype: string
|
||||
'''
|
||||
|
@ -192,7 +192,7 @@ class IterableIPShell:
|
|||
def updateNamespace(self, ns_dict):
|
||||
'''
|
||||
Add the current dictionary to the shell namespace.
|
||||
|
||||
|
||||
@param ns_dict: A dictionary of symbol-values.
|
||||
@type ns_dict: dictionary
|
||||
'''
|
||||
|
@ -201,11 +201,11 @@ class IterableIPShell:
|
|||
def complete(self, line):
|
||||
'''
|
||||
Returns an auto completed line and/or posibilities for completion.
|
||||
|
||||
|
||||
@param line: Given line so far.
|
||||
@type line: string
|
||||
|
||||
@return: Line completed as for as possible,
|
||||
|
||||
@return: Line completed as for as possible,
|
||||
and possible further completions.
|
||||
@rtype: tuple
|
||||
'''
|
||||
|
@ -230,12 +230,12 @@ class IterableIPShell:
|
|||
else:
|
||||
completed = line
|
||||
return completed, possibilities
|
||||
|
||||
|
||||
|
||||
def shell(self, cmd,verbose=0,debug=0,header=''):
|
||||
'''
|
||||
Replacement method to allow shell commands without them blocking.
|
||||
|
||||
|
||||
@param cmd: Shell command to execute.
|
||||
@type cmd: string
|
||||
@param verbose: Verbosity
|
||||
|
@ -286,28 +286,28 @@ class ConsoleView(gtk.TextView):
|
|||
self.modify_font(pango.FontDescription('Mono'))
|
||||
self.set_cursor_visible(True)
|
||||
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(),
|
||||
False)
|
||||
for code in self.ANSI_COLORS:
|
||||
self.text_buffer.create_tag(code,
|
||||
foreground=self.ANSI_COLORS[code],
|
||||
self.text_buffer.create_tag(code,
|
||||
foreground=self.ANSI_COLORS[code],
|
||||
weight=700)
|
||||
self.text_buffer.create_tag('0')
|
||||
self.text_buffer.create_tag('notouch', editable=False)
|
||||
self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
|
||||
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.connect('key-press-event', self.onKeyPress)
|
||||
|
||||
|
||||
def write(self, text, editable=False):
|
||||
gobject.idle_add(self._write, text, editable)
|
||||
|
||||
def _write(self, text, editable=False):
|
||||
'''
|
||||
Write given text to buffer.
|
||||
|
||||
|
||||
@param text: Text to append.
|
||||
@type text: string
|
||||
@param editable: If true, added text is editable.
|
||||
|
@ -315,8 +315,8 @@ class ConsoleView(gtk.TextView):
|
|||
'''
|
||||
segments = self.color_pat.split(text)
|
||||
segment = segments.pop(0)
|
||||
start_mark = self.text_buffer.create_mark(None,
|
||||
self.text_buffer.get_end_iter(),
|
||||
start_mark = self.text_buffer.create_mark(None,
|
||||
self.text_buffer.get_end_iter(),
|
||||
True)
|
||||
self.text_buffer.insert(self.text_buffer.get_end_iter(), segment)
|
||||
|
||||
|
@ -341,7 +341,7 @@ class ConsoleView(gtk.TextView):
|
|||
def _showPrompt(self, prompt):
|
||||
'''
|
||||
Prints prompt at start of line.
|
||||
|
||||
|
||||
@param prompt: Prompt to print.
|
||||
@type prompt: string
|
||||
'''
|
||||
|
@ -355,7 +355,7 @@ class ConsoleView(gtk.TextView):
|
|||
def _changeLine(self, text):
|
||||
'''
|
||||
Replace currently entered command line with given text.
|
||||
|
||||
|
||||
@param text: Text to use as replacement.
|
||||
@type text: string
|
||||
'''
|
||||
|
@ -367,7 +367,7 @@ class ConsoleView(gtk.TextView):
|
|||
def getCurrentLine(self):
|
||||
'''
|
||||
Get text in current command line.
|
||||
|
||||
|
||||
@return: Text of current command line.
|
||||
@rtype: string
|
||||
'''
|
||||
|
@ -382,14 +382,14 @@ class ConsoleView(gtk.TextView):
|
|||
def _showReturned(self, text):
|
||||
'''
|
||||
Show returned text from last command and print new prompt.
|
||||
|
||||
|
||||
@param text: Text to show.
|
||||
@type text: string
|
||||
'''
|
||||
iter_ = self.text_buffer.get_iter_at_mark(self.line_start)
|
||||
iter_.forward_to_line_end()
|
||||
self.text_buffer.apply_tag_by_name(
|
||||
'notouch',
|
||||
'notouch',
|
||||
self.text_buffer.get_iter_at_mark(self.line_start),
|
||||
iter_)
|
||||
self._write('\n'+text)
|
||||
|
@ -401,15 +401,15 @@ class ConsoleView(gtk.TextView):
|
|||
|
||||
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
|
||||
line.
|
||||
|
||||
|
||||
@param widget: Widget that key press accored in.
|
||||
@type widget: gtk.Widget
|
||||
@param event: Event object
|
||||
@type event: gtk.gdk.Event
|
||||
|
||||
|
||||
@return: Return True if event should not trickle.
|
||||
@rtype: boolean
|
||||
'''
|
||||
|
@ -419,7 +419,7 @@ class ConsoleView(gtk.TextView):
|
|||
selection_iter = self.text_buffer.get_iter_at_mark(selection_mark)
|
||||
start_iter = self.text_buffer.get_iter_at_mark(self.line_start)
|
||||
if event.keyval == gtk.keysyms.Home:
|
||||
if event.state == 0:
|
||||
if event.state == 0:
|
||||
self.text_buffer.place_cursor(start_iter)
|
||||
return True
|
||||
elif event.state == gtk.gdk.SHIFT_MASK:
|
||||
|
@ -440,7 +440,7 @@ class ConsoleView(gtk.TextView):
|
|||
elif insert_iter.compare(selection_iter) < 0:
|
||||
self.text_buffer.move_mark(insert_mark, start_iter)
|
||||
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)
|
||||
|
||||
|
@ -461,7 +461,7 @@ class IPythonView(ConsoleView, IterableIPShell):
|
|||
'''
|
||||
ConsoleView.__init__(self)
|
||||
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)
|
||||
# self.connect('key_press_event', self.keyPress)
|
||||
self.execute()
|
||||
|
@ -472,10 +472,10 @@ class IPythonView(ConsoleView, IterableIPShell):
|
|||
def raw_input(self, prompt=''):
|
||||
'''
|
||||
Custom raw_input() replacement. Get's current line from console buffer.
|
||||
|
||||
|
||||
@param prompt: Prompt to print. Here for compatability as replacement.
|
||||
@type prompt: string
|
||||
|
||||
|
||||
@return: The current command line text.
|
||||
@rtype: string
|
||||
'''
|
||||
|
@ -486,14 +486,14 @@ class IPythonView(ConsoleView, IterableIPShell):
|
|||
|
||||
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.
|
||||
|
||||
|
||||
@param widget: Widget that key press occured in.
|
||||
@type widget: gtk.Widget
|
||||
@param event: Event object.
|
||||
@type event: gtk.gdk.Event
|
||||
|
||||
|
||||
@return: True if event should not trickle.
|
||||
@rtype: boolean
|
||||
'''
|
||||
|
@ -533,6 +533,6 @@ class IPythonView(ConsoleView, IterableIPShell):
|
|||
if rv: rv = rv.strip('\n')
|
||||
self.showReturned(rv)
|
||||
self.cout.truncate(0)
|
||||
|
||||
|
||||
|
||||
# vim: se ts=3:
|
||||
|
|
|
@ -35,7 +35,7 @@ class MessageTextView(gtk.TextView):
|
|||
(int, gtk.gdk.ModifierType ) # arguments
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def __init__(self):
|
||||
gtk.TextView.__init__(self)
|
||||
|
||||
|
@ -56,7 +56,7 @@ class MessageTextView(gtk.TextView):
|
|||
self.end_tags = {}
|
||||
self.color_tags = []
|
||||
self.fonts_tags = []
|
||||
self.other_tags = {}
|
||||
self.other_tags = {}
|
||||
self.other_tags['bold'] = buffer.create_tag('bold')
|
||||
self.other_tags['bold'].set_property('weight', pango.WEIGHT_BOLD)
|
||||
self.begin_tags['bold'] = '<strong>'
|
||||
|
@ -80,7 +80,7 @@ class MessageTextView(gtk.TextView):
|
|||
start = 0
|
||||
end = 0
|
||||
index = 0
|
||||
|
||||
|
||||
new_text = ''
|
||||
iterator = gajim.interface.link_pattern_re.finditer(text)
|
||||
for match in iterator:
|
||||
|
@ -94,7 +94,7 @@ class MessageTextView(gtk.TextView):
|
|||
# we insert normal text
|
||||
new_text += text_before_special_text + \
|
||||
'<a href="'+ url +'">' + url + '</a>'
|
||||
|
||||
|
||||
index = end # update index
|
||||
|
||||
if end < len(text):
|
||||
|
@ -128,7 +128,7 @@ class MessageTextView(gtk.TextView):
|
|||
buffer.remove_tag_by_name('strike', start, finish)
|
||||
elif tag == 'strike':
|
||||
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):
|
||||
buffer = self.get_buffer()
|
||||
|
@ -190,7 +190,7 @@ class MessageTextView(gtk.TextView):
|
|||
self.begin_tags[tag_name] = \
|
||||
'<span style="font-family: ' + family + '; ' + \
|
||||
'font-size: ' + str(size) + 'px">'
|
||||
self.end_tags[tag_name] = '</span>'
|
||||
self.end_tags[tag_name] = '</span>'
|
||||
self.fonts_tags.append(tag_name)
|
||||
|
||||
return_val = buffer.get_selection_bounds()
|
||||
|
@ -198,7 +198,7 @@ class MessageTextView(gtk.TextView):
|
|||
start, finish = return_val[0], return_val[1]
|
||||
else:
|
||||
start, finish = buffer.get_bounds()
|
||||
|
||||
|
||||
for tag in self.fonts_tags:
|
||||
buffer.remove_tag_by_name(tag, start, finish)
|
||||
|
||||
|
@ -247,14 +247,14 @@ class MessageTextView(gtk.TextView):
|
|||
if tag_name not in self.begin_tags:
|
||||
continue
|
||||
new_tags.append(tag_name)
|
||||
|
||||
|
||||
for tag in iter.get_tags():
|
||||
tag_name = tag.get_property('name')
|
||||
if tag_name not in self.begin_tags or tag_name not in self.end_tags:
|
||||
continue
|
||||
if tag_name not in new_tags:
|
||||
old_tags.append(tag_name)
|
||||
|
||||
|
||||
for tag in iter.get_toggled_tags(False):
|
||||
tag_name = tag.get_property('name')
|
||||
if tag_name not in self.end_tags:
|
||||
|
@ -268,7 +268,7 @@ class MessageTextView(gtk.TextView):
|
|||
for tag in new_tags:
|
||||
texte += self.begin_tags[tag]
|
||||
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()))
|
||||
for tag in iter.get_toggled_tags(False):
|
||||
|
@ -281,7 +281,7 @@ class MessageTextView(gtk.TextView):
|
|||
return '<p>' + self.make_clickable_urls(texte) + '</p>'
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
|
||||
def destroy(self):
|
||||
import gc
|
||||
|
@ -308,41 +308,41 @@ gtk.binding_entry_add_signal(MessageTextView, gtk.keysyms.ISO_Left_Tab,
|
|||
gtk.gdk.ModifierType, gtk.gdk.CONTROL_MASK)
|
||||
|
||||
# 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.ModifierType, gtk.gdk.CONTROL_MASK)
|
||||
|
||||
|
||||
# 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)
|
||||
|
||||
# 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.ModifierType, gtk.gdk.CONTROL_MASK)
|
||||
|
||||
# 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.ModifierType, gtk.gdk.CONTROL_MASK)
|
||||
|
||||
# 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,
|
||||
gtk.gdk.ModifierType, 0)
|
||||
|
||||
# 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.ModifierType, gtk.gdk.CONTROL_MASK)
|
||||
|
||||
# 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,
|
||||
gtk.gdk.ModifierType, 0)
|
||||
|
||||
# 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.ModifierType, gtk.gdk.CONTROL_MASK)
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ class MessageWindow(object):
|
|||
orig_window.destroy()
|
||||
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
|
||||
# state when closing it, and it should be called before
|
||||
# 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
|
||||
first_composing_ind = ind
|
||||
if ind == current:
|
||||
break # a complete cycle without finding an unread tab
|
||||
break # a complete cycle without finding an unread tab
|
||||
if found:
|
||||
self.notebook.set_current_page(ind)
|
||||
elif first_composing_ind != -1:
|
||||
|
|
|
@ -48,11 +48,11 @@ class MusicTrackListener(gobject.GObject):
|
|||
if cls._instance is None:
|
||||
cls._instance = cls()
|
||||
return cls._instance
|
||||
|
||||
|
||||
def __init__(self):
|
||||
super(MusicTrackListener, self).__init__()
|
||||
self._last_playing_music = None
|
||||
|
||||
|
||||
bus = dbus.SessionBus()
|
||||
|
||||
## MPRIS
|
||||
|
@ -168,7 +168,7 @@ class MusicTrackListener(gobject.GObject):
|
|||
'/org/bansheeproject/Banshee/PlayerEngine')
|
||||
currentTrack = banshee.GetCurrentTrack()
|
||||
self._last_playing_music = self._banshee_properties_extract(
|
||||
currentTrack)
|
||||
currentTrack)
|
||||
self.emit('music-track-changed', self._last_playing_music)
|
||||
elif state == 'paused':
|
||||
self.emit('music-track-changed', None)
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
A Python module that enables posting notifications to the Growl daemon.
|
||||
See <http://growl.info/> for more information.
|
||||
"""
|
||||
__version__ = "0.7"
|
||||
__version__ = "0.7"
|
||||
__author__ = "Mark Rowe <bdash@users.sourceforge.net>"
|
||||
__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)",
|
||||
"Jeremy Rossi <jeremy@jeremyrossi.com>"
|
||||
]
|
||||
|
@ -35,7 +35,7 @@ GROWL_NOTIFICATION_DESCRIPTION="NotificationDescription"
|
|||
GROWL_NOTIFICATION_ICON="NotificationIcon"
|
||||
GROWL_NOTIFICATION_APP_ICON="NotificationAppIcon"
|
||||
GROWL_NOTIFICATION_PRIORITY="NotificationPriority"
|
||||
|
||||
|
||||
GROWL_NOTIFICATION_STICKY="NotificationSticky"
|
||||
GROWL_NOTIFICATION_CLICK_CONTEXT="NotificationClickContext"
|
||||
|
||||
|
@ -51,7 +51,7 @@ GROWL_NOTIFICATION_CLICKED="GrowlClicked!"
|
|||
GROWL_NOTIFICATION_TIMED_OUT="GrowlTimedOut!"
|
||||
GROWL_KEY_CLICKED_CONTEXT="ClickedContext"
|
||||
|
||||
|
||||
|
||||
growlPriority = {"Very Low":-2,"Moderate":-1,"Normal":0,"High":1,"Emergency":2}
|
||||
|
||||
class netgrowl:
|
||||
|
@ -67,7 +67,7 @@ class netgrowl:
|
|||
|
||||
def send(self, data):
|
||||
self.socket.sendto(data, (self.hostname, GROWL_UDP_PORT))
|
||||
|
||||
|
||||
def PostNotification(self, userInfo):
|
||||
priority = userInfo.get(GROWL_NOTIFICATION_PRIORITY, 0)
|
||||
if GROWL_NOTIFICATION_STICKY in userInfo:
|
||||
|
@ -113,9 +113,9 @@ class netgrowl:
|
|||
title = title.encode("utf-8")
|
||||
description = description.encode("utf-8")
|
||||
flags = (priority & 0x07) * 2
|
||||
if priority < 0:
|
||||
if priority < 0:
|
||||
flags |= 0x08
|
||||
if sticky:
|
||||
if sticky:
|
||||
flags = flags | 0x0001
|
||||
data = struct.pack("!BBHHHHH",
|
||||
GROWL_PROTOCOL_VERSION,
|
||||
|
|
|
@ -8,7 +8,7 @@ setup(
|
|||
url = 'http://www.gajim.org/',
|
||||
download_url = 'http://www.gajim.org/downloads.php',
|
||||
license = 'GPL',
|
||||
|
||||
|
||||
ext_modules=[
|
||||
Extension('idle', ['idle.c'],
|
||||
extra_compile_args=['-Wall'],
|
||||
|
|
|
@ -130,11 +130,11 @@ class ProfileWindow:
|
|||
'avatar_scaled.png')
|
||||
scaled_pixbuf.save(path_to_file, 'png')
|
||||
must_delete = True
|
||||
|
||||
|
||||
fd = open(path_to_file, 'rb')
|
||||
data = fd.read()
|
||||
pixbuf = gtkgui_helpers.get_pixbuf_from_data(data)
|
||||
try:
|
||||
try:
|
||||
# rescale it
|
||||
pixbuf = gtkgui_helpers.get_scaled_pixbuf(pixbuf, 'vcard')
|
||||
except AttributeError: # unknown format
|
||||
|
@ -151,10 +151,10 @@ class ProfileWindow:
|
|||
self.avatar_encoded = base64.encodestring(data)
|
||||
# returns None if unknown type
|
||||
self.avatar_mime_type = mimetypes.guess_type(path_to_file)[0]
|
||||
if must_delete:
|
||||
try:
|
||||
os.remove(path_to_file)
|
||||
except OSError:
|
||||
if must_delete:
|
||||
try:
|
||||
os.remove(path_to_file)
|
||||
except OSError:
|
||||
gajim.log.debug('Cannot remove %s' % path_to_file)
|
||||
|
||||
def on_clear(widget):
|
||||
|
@ -176,7 +176,7 @@ class ProfileWindow:
|
|||
'''If right-clicked, show popup'''
|
||||
if event.button == 3 and self.avatar_encoded: # right click
|
||||
menu = gtk.Menu()
|
||||
|
||||
|
||||
# Try to get pixbuf
|
||||
pixbuf = gtkgui_helpers.get_avatar_pixbuf_from_cache(self.jid,
|
||||
use_local = False)
|
||||
|
@ -192,7 +192,7 @@ class ProfileWindow:
|
|||
menuitem = gtk.ImageMenuItem(gtk.STOCK_CLEAR)
|
||||
menuitem.connect('activate', self.on_clear_button_clicked)
|
||||
menu.append(menuitem)
|
||||
menu.connect('selection-done', lambda w:w.destroy())
|
||||
menu.connect('selection-done', lambda w:w.destroy())
|
||||
# show the menu
|
||||
menu.show_all()
|
||||
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_REGION', 'ADR_WORK_PCODE', 'ADR_WORK_CTRY']
|
||||
vcard_ = {}
|
||||
for e in entries:
|
||||
for e in entries:
|
||||
txt = self.xml.get_widget(e + '_entry').get_text().decode('utf-8')
|
||||
if txt != '':
|
||||
vcard_ = self.add_to_vcard(vcard_, e, txt)
|
||||
|
|
|
@ -90,7 +90,7 @@ def get_dbus_struct(obj):
|
|||
return DBUS_NONE()
|
||||
return result
|
||||
# unknown type
|
||||
return DBUS_NONE()
|
||||
return DBUS_NONE()
|
||||
|
||||
class Remote:
|
||||
def __init__(self):
|
||||
|
@ -265,7 +265,7 @@ class SignalObject(dbus.service.Object):
|
|||
|
||||
@dbus.service.method(INTERFACE, in_signature='sss', out_signature='b')
|
||||
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' '''
|
||||
jid = self._get_real_jid(jid, account)
|
||||
connected_account, contact = self._get_account_and_contact(account, jid)
|
||||
|
@ -355,7 +355,7 @@ class SignalObject(dbus.service.Object):
|
|||
break
|
||||
# we send the message to jid not in roster, because account is
|
||||
# specified, or there is only one account
|
||||
elif account:
|
||||
elif account:
|
||||
connected_account = acct
|
||||
elif first_connected_acct is None:
|
||||
first_connected_acct = acct
|
||||
|
@ -378,7 +378,7 @@ class SignalObject(dbus.service.Object):
|
|||
def change_status(self, status, message, account):
|
||||
''' change_status(status, message, account). account is optional -
|
||||
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'):
|
||||
return DBUS_BOOLEAN(False)
|
||||
if account:
|
||||
|
@ -546,7 +546,7 @@ class SignalObject(dbus.service.Object):
|
|||
if account:
|
||||
if account in gajim.connections and \
|
||||
gajim.connections[account].connected > 1:
|
||||
# if given account is active, use it
|
||||
# if given account is active, use it
|
||||
AddNewContactWindow(account = account, jid = jid)
|
||||
else:
|
||||
# wrong account
|
||||
|
|
|
@ -358,7 +358,7 @@ class RosterWindow:
|
|||
contact.groups = big_brother_contact.get_shown_groups()[:]
|
||||
|
||||
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))
|
||||
added_iters.append(it)
|
||||
else:
|
||||
|
@ -366,13 +366,13 @@ class RosterWindow:
|
|||
if not groups:
|
||||
groups = contact.get_shown_groups()
|
||||
for group in groups:
|
||||
child_iterG = self._get_group_iter(group, account,
|
||||
child_iterG = self._get_group_iter(group, account,
|
||||
model = self.model)
|
||||
if not child_iterG:
|
||||
# Group is not yet in roster, add it!
|
||||
child_iterA = self._get_account_iter(account, self.model)
|
||||
child_iterG = self.model.append(child_iterA,
|
||||
[gajim.interface.jabber_state_images['16']['closed'],
|
||||
child_iterG = self.model.append(child_iterA,
|
||||
[gajim.interface.jabber_state_images['16']['closed'],
|
||||
gobject.markup_escape_text(group),
|
||||
'group', group, account, None, None, None, None, None])
|
||||
self.draw_group(group, account)
|
||||
|
@ -425,7 +425,7 @@ class RosterWindow:
|
|||
if groups:
|
||||
# Only remove from specified groups
|
||||
all_iters = iters[:]
|
||||
group_iters = [self._get_group_iter(group, account)
|
||||
group_iters = [self._get_group_iter(group, account)
|
||||
for group in groups]
|
||||
iters = [titer for titer in all_iters
|
||||
if self.model.iter_parent(titer) in group_iters]
|
||||
|
@ -546,7 +546,7 @@ class RosterWindow:
|
|||
|
||||
if not family_in_roster:
|
||||
return False
|
||||
|
||||
|
||||
assert old_big_jid, 'No Big Brother in nearby family % (Family: %)' % \
|
||||
(nearby_family, family)
|
||||
iters = self._get_contact_iter(old_big_jid, old_big_account,
|
||||
|
@ -585,7 +585,7 @@ class RosterWindow:
|
|||
|
||||
self._remove_metacontact_family(family, account)
|
||||
brothers = self._add_metacontact_family(family, account)
|
||||
|
||||
|
||||
for c, acc in brothers:
|
||||
self.draw_completely(c.jid, acc)
|
||||
|
||||
|
@ -874,7 +874,7 @@ class RosterWindow:
|
|||
gajim.connections[account].update_contact(jid, contact.name,
|
||||
contact.groups)
|
||||
self.add_contact(jid, account)
|
||||
|
||||
|
||||
# Also redraw old groups
|
||||
for group in groups:
|
||||
self.draw_group(group, account)
|
||||
|
@ -1145,7 +1145,7 @@ class RosterWindow:
|
|||
bb_jid, bb_account = \
|
||||
self._get_nearby_family_and_big_brother(family, account)[1:]
|
||||
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 \
|
||||
and self.modelfilter.iter_has_child(iters[0])
|
||||
|
||||
|
@ -1174,7 +1174,7 @@ class RosterWindow:
|
|||
state_images = self.get_appropriate_state_images(
|
||||
jid, size = 'closed',
|
||||
icon_name = icon_name)
|
||||
|
||||
|
||||
# Expand/collapse icon might differ per iter
|
||||
# (group)
|
||||
img = state_images[icon_name]
|
||||
|
@ -1285,7 +1285,7 @@ class RosterWindow:
|
|||
for child_iter in iters:
|
||||
self.model[child_iter][C_AVATAR_PIXBUF] = scaled_pixbuf
|
||||
return False
|
||||
|
||||
|
||||
def draw_completely(self, jid, account):
|
||||
self.draw_contact(jid, account)
|
||||
self.draw_mood(jid, account)
|
||||
|
@ -4684,7 +4684,7 @@ class RosterWindow:
|
|||
for account in gajim.connections:
|
||||
if gajim.account_is_connected(account) and \
|
||||
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):
|
||||
item.set_sensitive(False)
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ class SearchWindow:
|
|||
|
||||
def request_form(self):
|
||||
gajim.connections[self.account].request_search_fields(self.jid)
|
||||
|
||||
|
||||
def pulse_callback(self):
|
||||
self.progressbar.pulse()
|
||||
return True
|
||||
|
@ -101,7 +101,7 @@ class SearchWindow:
|
|||
return
|
||||
jid = model[iter_][self.jid_column]
|
||||
dialogs.AddNewContactWindow(self.account, jid)
|
||||
|
||||
|
||||
def on_information_button_clicked(self, widget):
|
||||
(model, iter_) = self.result_treeview.get_selection().get_selected()
|
||||
if not iter_:
|
||||
|
|
|
@ -54,7 +54,7 @@ class Secrets:
|
|||
except KeyError:
|
||||
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
|
||||
def save_new_srs(self, account, jid, secret, verified):
|
||||
if not account in self.srs:
|
||||
|
|
|
@ -44,7 +44,7 @@ class StatusIcon(systray.Systray):
|
|||
def __init__(self):
|
||||
systray.Systray.__init__(self)
|
||||
self.status_icon = None
|
||||
|
||||
|
||||
def show_icon(self):
|
||||
if not self.status_icon:
|
||||
self.status_icon = gtk.StatusIcon()
|
||||
|
@ -86,7 +86,7 @@ class StatusIcon(systray.Systray):
|
|||
else:
|
||||
state = self.status
|
||||
self.status_icon.set_blinking(False)
|
||||
|
||||
|
||||
#FIXME: do not always use 16x16 (ask actually used size and use that)
|
||||
image = gajim.interface.jabber_state_images['16'][state]
|
||||
if image.get_storage_type() == gtk.IMAGE_PIXBUF:
|
||||
|
|
|
@ -61,7 +61,7 @@ class Systray:
|
|||
self.new_chat_handler_id = None
|
||||
self.t = None
|
||||
# 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.status = 'offline'
|
||||
self.double_click = False
|
||||
|
@ -107,7 +107,7 @@ class Systray:
|
|||
|
||||
def change_status(self, 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:
|
||||
self.status = global_status
|
||||
self.set_img()
|
||||
|
@ -226,7 +226,7 @@ class Systray:
|
|||
self.on_single_message_menuitem_activate, account)
|
||||
account_menu_for_single_message.append(item)
|
||||
|
||||
# join gc
|
||||
# join gc
|
||||
gc_item = gtk.MenuItem(_('using account %s') % account, False)
|
||||
gc_sub_menu.append(gc_item)
|
||||
gc_menuitem_menu = gtk.Menu()
|
||||
|
@ -283,7 +283,7 @@ class Systray:
|
|||
gajim.interface.handle_event(account, jid, event.type_)
|
||||
|
||||
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()
|
||||
|
||||
def on_show_roster_menuitem_activate(self, widget):
|
||||
|
@ -296,7 +296,7 @@ class Systray:
|
|||
else:
|
||||
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()
|
||||
|
||||
def on_left_click(self):
|
||||
|
|
124
src/tooltips.py
124
src/tooltips.py
|
@ -44,17 +44,17 @@ class BaseTooltip:
|
|||
''' Base Tooltip class;
|
||||
Usage:
|
||||
tooltip = BaseTooltip()
|
||||
....
|
||||
....
|
||||
tooltip.show_tooltip(data, widget_height, widget_y_position)
|
||||
....
|
||||
if tooltip.timeout != 0:
|
||||
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)
|
||||
* 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
|
||||
|
||||
|
||||
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.
|
||||
'''
|
||||
|
@ -63,14 +63,14 @@ class BaseTooltip:
|
|||
self.preferred_position = [0, 0]
|
||||
self.win = None
|
||||
self.id = None
|
||||
|
||||
|
||||
def populate(self, data):
|
||||
''' this method must be overriden by all extenders
|
||||
This is the most simple implementation: show data as value of a label
|
||||
'''
|
||||
self.create_window()
|
||||
self.win.add(gtk.Label(data))
|
||||
|
||||
|
||||
def create_window(self):
|
||||
''' create a popup window each time tooltip is requested '''
|
||||
self.win = gtk.Window(gtk.WINDOW_POPUP)
|
||||
|
@ -79,15 +79,15 @@ class BaseTooltip:
|
|||
self.win.set_name('gtk-tooltips')
|
||||
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_events(gtk.gdk.POINTER_MOTION_MASK)
|
||||
self.win.connect_after('expose_event', self.expose)
|
||||
self.win.connect('size-request', self.on_size_request)
|
||||
self.win.connect('motion-notify-event', self.motion_notify_event)
|
||||
self.screen = self.win.get_screen()
|
||||
|
||||
|
||||
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
|
||||
real status of the account
|
||||
'''
|
||||
|
@ -102,14 +102,14 @@ class BaseTooltip:
|
|||
|
||||
def on_size_request(self, widget, requisition):
|
||||
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
|
||||
elif self.preferred_position[0] + requisition.width > \
|
||||
self.screen.get_width() + half_width:
|
||||
self.preferred_position[0] = self.screen.get_width() - \
|
||||
requisition.width
|
||||
else:
|
||||
self.preferred_position[0] -= half_width
|
||||
self.preferred_position[0] -= half_width
|
||||
self.screen.get_height()
|
||||
if self.preferred_position[1] + requisition.height > \
|
||||
self.screen.get_height():
|
||||
|
@ -132,23 +132,23 @@ class BaseTooltip:
|
|||
style.paint_flat_box(self.win.window, gtk.STATE_NORMAL, gtk.SHADOW_OUT,
|
||||
None, self.win, 'tooltip', size[0] - 1, 0, 1, -1)
|
||||
return True
|
||||
|
||||
|
||||
def show_tooltip(self, data, widget_height, widget_y_position):
|
||||
''' show tooltip on widget.
|
||||
data contains needed data for tooltip contents
|
||||
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
|
||||
'''
|
||||
# set tooltip contents
|
||||
# set tooltip contents
|
||||
self.populate(data)
|
||||
|
||||
|
||||
# get the X position of mouse pointer on the screen
|
||||
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
|
||||
preferred_y = widget_y_position + widget_height + 4
|
||||
|
||||
|
||||
self.preferred_position = [pointer_x, preferred_y]
|
||||
self.widget_height = widget_height
|
||||
self.win.ensure_style()
|
||||
|
@ -164,18 +164,18 @@ class BaseTooltip:
|
|||
self.id = None
|
||||
|
||||
class StatusTable:
|
||||
''' Contains methods for creating status table. This
|
||||
''' Contains methods for creating status table. This
|
||||
is used in Roster and NotificationArea tooltips '''
|
||||
def __init__(self):
|
||||
self.current_row = 1
|
||||
self.table = None
|
||||
self.text_label = None
|
||||
self.spacer_label = ' '
|
||||
|
||||
|
||||
def create_table(self):
|
||||
self.table = gtk.Table(4, 1)
|
||||
self.table.set_property('column-spacing', 2)
|
||||
|
||||
|
||||
def add_text_row(self, text, col_inc = 0):
|
||||
self.current_row += 1
|
||||
self.text_label = gtk.Label()
|
||||
|
@ -185,7 +185,7 @@ class StatusTable:
|
|||
self.text_label.set_markup(text)
|
||||
self.table.attach(self.text_label, 1 + col_inc, 4, self.current_row,
|
||||
self.current_row + 1)
|
||||
|
||||
|
||||
def get_status_info(self, resource, priority, show, status):
|
||||
str_status = resource + ' (' + unicode(priority) + ')'
|
||||
if status:
|
||||
|
@ -200,7 +200,7 @@ class StatusTable:
|
|||
status = gobject.markup_escape_text(status)
|
||||
str_status += ' - <i>' + status + '</i>'
|
||||
return str_status
|
||||
|
||||
|
||||
def add_status_row(self, file_path, show, str_status, status_time=None,
|
||||
show_lock=False, indent=True):
|
||||
''' appends a new row with status icon to the table '''
|
||||
|
@ -218,9 +218,9 @@ class StatusTable:
|
|||
spacer = gtk.Label(self.spacer_label)
|
||||
image.set_alignment(1, 0.5)
|
||||
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.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)
|
||||
status_label = gtk.Label()
|
||||
status_label.set_markup(str_status)
|
||||
|
@ -230,11 +230,11 @@ class StatusTable:
|
|||
self.current_row + 1, gtk.FILL | gtk.EXPAND, 0, 0, 0)
|
||||
if show_lock:
|
||||
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)
|
||||
self.table.attach(lock_image, 4, 5, self.current_row,
|
||||
self.current_row + 1, 0, 0, 0, 0)
|
||||
|
||||
|
||||
class NotificationAreaTooltip(BaseTooltip, StatusTable):
|
||||
''' Tooltip that is shown in the notification area '''
|
||||
def __init__(self):
|
||||
|
@ -248,7 +248,7 @@ class NotificationAreaTooltip(BaseTooltip, StatusTable):
|
|||
file_path = os.path.join(helpers.get_iconset_path(iconset), '16x16')
|
||||
for acct in accounts:
|
||||
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'
|
||||
if isinstance(message, str):
|
||||
message = unicode(message, encoding = 'utf-8')
|
||||
|
@ -260,12 +260,12 @@ class NotificationAreaTooltip(BaseTooltip, StatusTable):
|
|||
else:
|
||||
show_lock = False
|
||||
if message:
|
||||
self.add_status_row(file_path, acct['show'],
|
||||
self.add_status_row(file_path, acct['show'],
|
||||
gobject.markup_escape_text(acct['name']) + \
|
||||
' - ' + message, show_lock=show_lock, indent=False)
|
||||
else:
|
||||
self.add_status_row(file_path, acct['show'],
|
||||
gobject.markup_escape_text(acct['name'])
|
||||
self.add_status_row(file_path, acct['show'],
|
||||
gobject.markup_escape_text(acct['name'])
|
||||
, show_lock=show_lock, indent=False)
|
||||
for line in acct['event_lines']:
|
||||
self.add_text_row(' ' + line, 1)
|
||||
|
@ -294,7 +294,7 @@ class GCTooltip(BaseTooltip):
|
|||
self.avatar_image = gtk.Image()
|
||||
|
||||
BaseTooltip.__init__(self)
|
||||
|
||||
|
||||
def populate(self, contact):
|
||||
if not contact:
|
||||
return
|
||||
|
@ -307,10 +307,10 @@ class GCTooltip(BaseTooltip):
|
|||
|
||||
nick_markup = '<b>' + \
|
||||
gobject.markup_escape_text(contact.get_shown_name()) \
|
||||
+ '</b>'
|
||||
+ '</b>'
|
||||
properties.append((nick_markup, None))
|
||||
|
||||
if contact.status: # status message
|
||||
if contact.status: # status message
|
||||
status = contact.status.strip()
|
||||
if status != '':
|
||||
# escape markup entities
|
||||
|
@ -327,7 +327,7 @@ class GCTooltip(BaseTooltip):
|
|||
properties.append((_('Jabber ID: '), contact.jid))
|
||||
|
||||
if hasattr(contact, 'resource') and contact.resource.strip() != '':
|
||||
properties.append((_('Resource: '),
|
||||
properties.append((_('Resource: '),
|
||||
gobject.markup_escape_text(contact.resource) ))
|
||||
if contact.affiliation != 'none':
|
||||
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': uf_affiliation}
|
||||
properties.append((affiliation_str, None))
|
||||
|
||||
|
||||
# Add avatar
|
||||
puny_name = helpers.sanitize_filename(contact.name)
|
||||
puny_room = helpers.sanitize_filename(contact.room_jid)
|
||||
|
@ -372,9 +372,9 @@ class GCTooltip(BaseTooltip):
|
|||
label.set_line_wrap(True)
|
||||
vcard_table.attach(label, 1, 3, vcard_current_row,
|
||||
vcard_current_row + 1, gtk.FILL, vertical_fill, 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)
|
||||
self.win.add(vcard_table)
|
||||
|
||||
|
@ -385,7 +385,7 @@ class RosterTooltip(NotificationAreaTooltip):
|
|||
self.image = gtk.Image()
|
||||
self.image.set_alignment(0, 0)
|
||||
# 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()
|
||||
NotificationAreaTooltip.__init__(self)
|
||||
|
||||
|
@ -401,11 +401,11 @@ class RosterTooltip(NotificationAreaTooltip):
|
|||
self.fill_table_with_accounts(accounts)
|
||||
self.win.add(self.table)
|
||||
return
|
||||
|
||||
|
||||
# primary contact
|
||||
prim_contact = gajim.contacts.get_highest_prio_contact_from_contacts(
|
||||
contacts)
|
||||
|
||||
|
||||
puny_jid = helpers.sanitize_filename(prim_contact.jid)
|
||||
table_size = 3
|
||||
|
||||
|
@ -466,7 +466,7 @@ class RosterTooltip(NotificationAreaTooltip):
|
|||
for acontact in contacts_dict[priority]:
|
||||
status_line = self.get_status_info(acontact.resource,
|
||||
acontact.priority, acontact.show, acontact.status)
|
||||
|
||||
|
||||
icon_name = self._get_icon_name_for_tooltip(acontact)
|
||||
self.add_status_row(file_path, icon_name, status_line,
|
||||
acontact.last_status_time)
|
||||
|
@ -474,14 +474,14 @@ class RosterTooltip(NotificationAreaTooltip):
|
|||
|
||||
else: # only one resource
|
||||
if contact.show:
|
||||
show = helpers.get_uf_show(contact.show)
|
||||
show = helpers.get_uf_show(contact.show)
|
||||
if contact.last_status_time:
|
||||
vcard_current_row += 1
|
||||
if contact.show == 'offline':
|
||||
text = ' - ' + _('Last status: %s')
|
||||
else:
|
||||
text = _(' since %s')
|
||||
|
||||
|
||||
if time.strftime('%j', time.localtime())== \
|
||||
time.strftime('%j', contact.last_status_time):
|
||||
# it's today, show only the locale hour representation
|
||||
|
@ -493,7 +493,7 @@ class RosterTooltip(NotificationAreaTooltip):
|
|||
contact.last_status_time)
|
||||
local_time = local_time.decode(
|
||||
locale.getpreferredencoding())
|
||||
text = text % local_time
|
||||
text = text % local_time
|
||||
show += text
|
||||
if self.account and \
|
||||
prim_contact.jid in gajim.gc_connected[self.account]:
|
||||
|
@ -503,7 +503,7 @@ class RosterTooltip(NotificationAreaTooltip):
|
|||
show = _('Disconnected')
|
||||
show = '<i>' + show + '</i>'
|
||||
# we append show below
|
||||
|
||||
|
||||
if contact.status:
|
||||
status = contact.status.strip()
|
||||
if status:
|
||||
|
@ -511,13 +511,13 @@ class RosterTooltip(NotificationAreaTooltip):
|
|||
# (no more than 300 chars on line and no more than 5 lines)
|
||||
# status is wrapped
|
||||
status = helpers.reduce_chars_newlines(status, 300, 5)
|
||||
# escape markup entities.
|
||||
# escape markup entities.
|
||||
status = gobject.markup_escape_text(status)
|
||||
properties.append(('<i>%s</i>' % status, None))
|
||||
properties.append((show, None))
|
||||
|
||||
|
||||
self._append_pep_info(contact, properties)
|
||||
|
||||
|
||||
properties.append((_('Jabber ID: '), prim_contact.jid ))
|
||||
|
||||
# contact has only one ressource
|
||||
|
@ -525,13 +525,13 @@ class RosterTooltip(NotificationAreaTooltip):
|
|||
properties.append((_('Resource: '),
|
||||
gobject.markup_escape_text(contact.resource) +\
|
||||
' (' + unicode(contact.priority) + ')'))
|
||||
|
||||
|
||||
if self.account and prim_contact.sub and prim_contact.sub != 'both' and\
|
||||
prim_contact.jid not in gajim.gc_connected[self.account]:
|
||||
# ('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))))
|
||||
|
||||
|
||||
if prim_contact.keyID:
|
||||
keyID = None
|
||||
if len(prim_contact.keyID) == 8:
|
||||
|
@ -541,7 +541,7 @@ class RosterTooltip(NotificationAreaTooltip):
|
|||
if keyID:
|
||||
properties.append((_('OpenPGP: '),
|
||||
gobject.markup_escape_text(keyID)))
|
||||
|
||||
|
||||
while properties:
|
||||
property_ = properties.pop(0)
|
||||
vcard_current_row += 1
|
||||
|
@ -563,7 +563,7 @@ class RosterTooltip(NotificationAreaTooltip):
|
|||
vertical_fill, 0, 0)
|
||||
else:
|
||||
if isinstance(property_[0], (unicode, str)): #FIXME: rm unicode?
|
||||
label.set_markup(property_[0])
|
||||
label.set_markup(property_[0])
|
||||
label.set_line_wrap(True)
|
||||
else:
|
||||
label = property_[0]
|
||||
|
@ -640,7 +640,7 @@ class RosterTooltip(NotificationAreaTooltip):
|
|||
'from <i>%(source)s</i>') % {'title': title,
|
||||
'artist': artist, 'source': source}
|
||||
properties.append((tune_string, None))
|
||||
|
||||
|
||||
|
||||
class FileTransfersTooltip(BaseTooltip):
|
||||
''' 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]
|
||||
else:
|
||||
file_name = file_props['name']
|
||||
properties.append((_('Name: '),
|
||||
properties.append((_('Name: '),
|
||||
gobject.markup_escape_text(file_name)))
|
||||
if file_props['type'] == 'r':
|
||||
type_ = _('Download')
|
||||
actor = _('Sender: ')
|
||||
actor = _('Sender: ')
|
||||
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()
|
||||
else:
|
||||
type_ = _('Upload')
|
||||
|
@ -676,10 +676,10 @@ class FileTransfersTooltip(BaseTooltip):
|
|||
name = receiver.split('/')[0]
|
||||
properties.append((_('Type: '), type_))
|
||||
properties.append((actor, gobject.markup_escape_text(name)))
|
||||
|
||||
|
||||
transfered_len = file_props.get('received-len', 0)
|
||||
properties.append((_('Transferred: '), helpers.convert_bytes(transfered_len)))
|
||||
status = ''
|
||||
status = ''
|
||||
if 'started' not in file_props or not file_props['started']:
|
||||
status = _('Not started')
|
||||
elif 'connected' in file_props:
|
||||
|
@ -714,15 +714,15 @@ class FileTransfersTooltip(BaseTooltip):
|
|||
label = gtk.Label()
|
||||
label.set_alignment(0, 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)
|
||||
label = gtk.Label()
|
||||
label.set_alignment(0, 0)
|
||||
label.set_line_wrap(True)
|
||||
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)
|
||||
|
||||
|
||||
self.win.add(ft_table)
|
||||
|
||||
|
||||
|
|
10
src/vcard.py
10
src/vcard.py
|
@ -155,7 +155,7 @@ class VcardWindow:
|
|||
self.contact.jid, self.account, self.contact.get_shown_name() +
|
||||
'.jpeg')
|
||||
menu.append(menuitem)
|
||||
menu.connect('selection-done', lambda w:w.destroy())
|
||||
menu.connect('selection-done', lambda w:w.destroy())
|
||||
# show the menu
|
||||
menu.show_all()
|
||||
menu.popup(None, None, None, event.button, event.time)
|
||||
|
@ -300,7 +300,7 @@ class VcardWindow:
|
|||
self.contact.get_shown_name() +
|
||||
'</span></b>')
|
||||
self.xml.get_widget('jid_label').set_text(self.contact.jid)
|
||||
|
||||
|
||||
subscription_label = self.xml.get_widget('subscription_label')
|
||||
ask_label = self.xml.get_widget('ask_label')
|
||||
if self.gc_contact:
|
||||
|
@ -442,7 +442,7 @@ class ZeroconfVcardWindow:
|
|||
self.contact.jid, self.account, self.contact.get_shown_name() +
|
||||
'.jpeg')
|
||||
menu.append(menuitem)
|
||||
menu.connect('selection-done', lambda w:w.destroy())
|
||||
menu.connect('selection-done', lambda w:w.destroy())
|
||||
# show the menu
|
||||
menu.show_all()
|
||||
menu.popup(None, None, None, event.button, event.time)
|
||||
|
@ -493,7 +493,7 @@ class ZeroconfVcardWindow:
|
|||
tip = gtk.Tooltips()
|
||||
status_label_eventbox = self.xml.get_widget('status_label_eventbox')
|
||||
tip.set_tip(status_label_eventbox, stats)
|
||||
|
||||
|
||||
def fill_contact_page(self):
|
||||
tooltips = gtk.Tooltips()
|
||||
self.xml.get_widget('nickname_label').set_markup(
|
||||
|
@ -521,7 +521,7 @@ class ZeroconfVcardWindow:
|
|||
self.fill_status_label()
|
||||
|
||||
# gajim.connections[self.account].request_vcard(self.contact.jid, self.is_fake)
|
||||
|
||||
|
||||
def fill_personal_page(self):
|
||||
contact = gajim.connections[gajim.ZEROCONF_ACC_NAME].roster.getItem(self.contact.jid)
|
||||
for key in ('1st', 'last', 'jid', 'email'):
|
||||
|
|
Loading…
Reference in New Issue