Newer
Older
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published
## by the Free Software Foundation; version 2 only.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##

Yann Leboulanger
committed
def usage():
#TODO: use i18n
print "usage :", sys.argv[0], ' [OPTION]'
print " -p\tport on whitch the sock plugin listen"
print " -h, --help\tdisplay this help and exit"
if __name__ == "__main__":
import getopt, pickle, sys, socket
try:
opts, args = getopt.getopt(sys.argv[1:], "p:h", ["help"])
except getopt.GetoptError:
# print help information and exit:
usage()
sys.exit(2)
port = 8255
for o, a in opts:
if o == '-p':
port = a
if o in ("-h", "--help"):
usage()
sys.exit()
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
sock.connect(('', 8255))
except:
#TODO: use i18n
print "unable to connect to localhost on port "+str(port)
else:
evp = pickle.dumps(('EXEC_PLUGIN', '', 'gtkgui'))
sock.send('<'+evp+'>')
sock.close()
sys.exit()
import pygtk
pygtk.require('2.0')
import gtk
from gtk import TRUE, FALSE
import os,string,time,Queue, sys
from common import i18n
_ = i18n._
APP = i18n.APP
gtk.glade.bindtextdomain (APP, i18n.DIR)
gtk.glade.textdomain (APP)
from config import *

Yann Leboulanger
committed
USE_TABBED_CHAT = 0

Yann Leboulanger
committed
class ImageCellRenderer(gtk.GenericCellRenderer):
__gproperties__ = {
"image": (gobject.TYPE_OBJECT, "Image",
"Image", gobject.PARAM_READWRITE),
}
def __init__(self):
self.__gobject_init__()
self.image = None
def do_set_property(self, pspec, value):
setattr(self, pspec.name, value)
def do_get_property(self, pspec):
return getattr(self, pspec.name)
def func(self, model, path, iter, (image, tree)):
if model.get_value(iter, 0) == image:
self.redraw = 1
cell_area = tree.get_cell_area(path, tree.get_column(0))
tree.queue_draw_area(cell_area.x, cell_area.y, cell_area.width, cell_area.height)

Yann Leboulanger
committed
def animation_timeout(self, tree, image):
if image.get_storage_type() == gtk.IMAGE_ANIMATION:

Yann Leboulanger
committed
image.get_data('iter').advance()
model = tree.get_model()
model.foreach(self.func, (image, tree))
if self.redraw:
gobject.timeout_add(image.get_data('iter').get_delay_time(), self.animation_timeout, tree, image)
else:
image.set_data('iter', None)

Yann Leboulanger
committed
def on_render(self, window, widget, background_area,cell_area, \
expose_area, flags):
pix_rect = gtk.gdk.Rectangle()
pix_rect.x, pix_rect.y, pix_rect.width, pix_rect.height = self.on_get_size(widget, cell_area)
pix_rect.x += cell_area.x
pix_rect.y += cell_area.y
pix_rect.width -= 2 * self.get_property("xpad")
pix_rect.height -= 2 * self.get_property("ypad")
draw_rect = cell_area.intersect(pix_rect)
draw_rect = expose_area.intersect(draw_rect)

Yann Leboulanger
committed
if self.image.get_storage_type() == gtk.IMAGE_ANIMATION:
if not self.image.get_data('iter'):
animation = self.image.get_animation()
self.image.set_data('iter', animation.get_iter())
gobject.timeout_add(self.image.get_data('iter').get_delay_time(), self.animation_timeout, widget, self.image)
pix = self.image.get_data('iter').get_pixbuf()
elif self.image.get_storage_type() == gtk.IMAGE_PIXBUF:
pix = self.image.get_pixbuf()
else:
return
window.draw_pixbuf(widget.style.black_gc, pix, \
draw_rect.x-pix_rect.x, draw_rect.y-pix_rect.y, draw_rect.x, \
draw_rect.y+2, draw_rect.width, draw_rect.height, \
gtk.gdk.RGB_DITHER_NONE, 0, 0)

Yann Leboulanger
committed
def on_get_size(self, widget, cell_area):
if self.image.get_storage_type() == gtk.IMAGE_ANIMATION:
animation = self.image.get_animation()
pix = animation.get_iter().get_pixbuf()
elif self.image.get_storage_type() == gtk.IMAGE_PIXBUF:
pix = self.image.get_pixbuf()

Yann Leboulanger
committed
pixbuf_width = pix.get_width()
pixbuf_height = pix.get_height()
calc_width = self.get_property("xpad") * 2 + pixbuf_width
calc_height = self.get_property("ypad") * 2 + pixbuf_height
x_offset = 0
y_offset = 0
if cell_area and pixbuf_width > 0 and pixbuf_height > 0:
x_offset = self.get_property("xalign") * (cell_area.width - calc_width - self.get_property("xpad"))
y_offset = self.get_property("yalign") * (cell_area.height - calc_height - self.get_property("ypad"))
return x_offset, y_offset, calc_width, calc_height
gobject.type_register(ImageCellRenderer)
def __init__(self, *args):
if len(args) == 0:
self.jid = ''
self.name = ''
self.groups = []
self.show = ''
self.status = ''

Yann Leboulanger
committed
self.ask = ''

Yann Leboulanger
committed
self.priority = 1

Yann Leboulanger
committed
elif len(args) == 10:
self.jid = args[0]
self.name = args[1]
self.groups = args[2]
self.show = args[3]
self.status = args[4]
self.sub = args[5]

Yann Leboulanger
committed
self.ask = args[6]
self.resource = args[7]
self.priority = args[8]
self.keyID = args[9]
else: raise TypeError, _('bad arguments')
class tabbed_chat_Window:
"""Class for tabbed chat window"""
def __init__(self, user, plugin, account):
self.xml = gtk.glade.XML(GTKGUI_GLADE, 'tabbed_chat', APP)
self.xml.get_widget('notebook').remove_page(0)
self.plugin = plugin
self.account = account
self.widgets = {}
self.tagIn = {}
self.tagOut = {}
self.tagStatus = {}
self.users = {user.jid: user}
self.nb_unread = {user.jid: 0}
self.window = self.xml.get_widget('tabbed_chat')
self.show_title()
self.xml.signal_connect('gtk_widget_destroy', self.delete_event)
self.xml.signal_connect('on_focus', self.on_focus)
self.xml.signal_connect('on_chat_key_press_event', \
self.on_chat_key_press_event)
self.xml.signal_connect('on_notebook_switch_page', \
self.on_notebook_switch_page)

Yann Leboulanger
committed
def update_tags(self):
for jid in self.tagIn:
self.tagIn[jid].set_property("foreground", \
self.plugin.config['inmsgcolor'])
self.tagOut[jid].set_property("foreground", \
self.plugin.config['outmsgcolor'])
self.tagStatus[jid].set_property("foreground", \
self.plugin.config['statusmsgcolor'])
for jid in self.nb_unread:
unread += self.nb_unread[jid]
start = ""
if unread > 1:
start = "[" + str(unread) + "] "
elif unread == 1:
start = "* "
self.window.set_title(start + "Chat (" + self.account + ")")
def draw_widgets(self, user):
widget_img = self.widgets[user.jid]['image_status']
image = self.plugin.roster.pixbufs[user.show]
if image.get_storage_type() == gtk.IMAGE_ANIMATION:
widget_img.set_from_animation(image.get_animation())
elif image.get_storage_type() == gtk.IMAGE_PIXBUF:
widget_img.set_from_pixbuf(image.get_pixbuf())
self.widgets[user.jid]['button_contact'].set_label(\
user.name + ' <' + user.jid + '>')
self.widgets[user.jid]['toggle_gpg'].set_sensitive(False)
def redraw_tab(self, jid):
if self.nb_unread[jid] > 1:
start = "[" + str(self.nb_unread[jid]) + "] "
elif self.nb_unread[jid] == 1:
nb = self.xml.get_widget("notebook")
child = self.widgets[jid]['vbox_tab']
nb.set_tab_label_text(child, start + self.users[jid].name)
def set_image(self, image, jid):
if image.get_storage_type() == gtk.IMAGE_ANIMATION:
self.widgets[jid]['image_status'].\
set_from_animation(image.get_animation())
elif image.get_storage_type() == gtk.IMAGE_PIXBUF:
self.widgets[jid]['image_status'].\
set_from_pixbuf(image.get_pixbuf())
def delete_event(self, widget):
"""close window"""
#clean self.plugin.windows[self.account]['chats']
for jid in self.users:
del self.plugin.windows[self.account]['chats'][jid]
del self.plugin.windows[self.account]['chats']['tabbed']
def get_active_jid(self):
nb = self.xml.get_widget("notebook")
child = nb.get_nth_page(nb.get_current_page())
jid = ''
for j in self.widgets:
c = self.widgets[j]['vbox_tab']
if c == child:
jid = j
break
return jid
def on_clear(self, widget):
"""When clear button is pressed :
clear the conversation"""
jid = self.get_active_jid()
buffer = self.widgets[jid]['conversation'].get_buffer()
deb, end = buffer.get_bounds()
buffer.delete(deb, end)
def on_close_clicked(self, button):
"""When close button is pressed :
close a tab"""
jid = self.get_active_jid()
if len(self.widgets) == 1:
button.get_toplevel().destroy()
else:
nb = self.xml.get_widget('notebook')
nb.remove_page(nb.get_current_page())
del self.plugin.windows[self.account]['chats'][jid]
del self.users[jid]
del self.nb_unread[jid]
del self.widgets[jid]
del self.tagIn[jid]
del self.tagOut[jid]
del self.tagStatus[jid]
def on_focus(self, widget, event):
"""When window get focus"""
jid = self.get_active_jid()
if self.nb_unread[jid] > 0:
self.nb_unread[jid] = 0
self.redraw_tab(jid)
self.plugin.systray.remove_jid(jid, self.account)
def on_history(self, widget):
"""When history button is pressed : call log window"""
jid = self.get_active_jid()
if not self.plugin.windows['logs'].has_key(jid):
self.plugin.windows['logs'][jid] = log_Window(self.plugin, jid)
def on_notebook_switch_page(self, nb, page, page_num):
child = nb.get_nth_page(page_num)
jid = ''
for j in self.widgets:
c = self.widgets[j]['vbox_tab']
if c == child:
jid = j
break
if self.nb_unread[jid] > 0:
self.nb_unread[jid] = 0
self.redraw_tab(jid)
self.plugin.systray.remove_jid(jid, self.account)

Yann Leboulanger
committed
def active_tab(self, jid):
child = self.widgets[jid]['vbox_tab']

Yann Leboulanger
committed
nb = self.xml.get_widget("notebook")
nb.set_current_page(nb.page_num(child))
self.widgets[jid]['message'].grab_focus()
self.users[user.jid] = user
self.widgets[user.jid] = {}
vb = gtk.VBox()
self.widgets[user.jid]['vbox_tab'] = vb
hb = gtk.HBox(spacing=5)
hb.set_border_width(5)
vb.pack_start(hb, expand=False)
button = gtk.Button(stock=gtk.STOCK_JUSTIFY_FILL)
button.get_children()[0].get_children()[0].get_children()[1].set_text("History")
button.connect("clicked", self.on_history)
hb.pack_start(button, expand=False, fill=False)
button = gtk.Button(stock=gtk.STOCK_CLEAR)
button.connect("clicked", self.on_clear)
hb.pack_start(button, expand=False, fill=False)
img = gtk.Image()
hb.pack_start(img, expand=False, fill=False)
self.widgets[user.jid]['image_status'] = img
img = gtk.Image()
img.set_from_stock(gtk.STOCK_DIALOG_AUTHENTICATION, gtk.ICON_SIZE_BUTTON)
button = gtk.ToggleButton()
button.add(img)
button.set_relief(gtk.RELIEF_NONE)
hb.pack_start(button, expand=False, fill=False)
self.widgets[user.jid]['toggle_gpg'] = button
fixed = gtk.Fixed()
fixed.set_size_request(20, -1)
hb.pack_start(fixed)
button = gtk.Button("Anonymous")
button.set_relief(gtk.RELIEF_NONE)
button.connect("clicked", self.on_button_contact_clicked)
button.set_use_underline(False)
self.widgets[user.jid]['button_contact'] = button
img = gtk.Image()
img.set_from_stock(gtk.STOCK_CLOSE, gtk.ICON_SIZE_BUTTON)
button = gtk.Button()
button.add(img)
button.connect("clicked", self.on_close_clicked)
hb.pack_start(button, expand=False, fill=False)
vp = gtk.VPaned()
vb.pack_start(vp)
vp.set_position(170)
sw = gtk.ScrolledWindow()
vp.add1(sw)
sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
tv = gtk.TextView()
tv.set_wrap_mode(gtk.WRAP_WORD)
tv.set_editable(False)
tv.set_cursor_visible(False)
sw.add(tv)
self.widgets[user.jid]['conversation'] = tv
buffer = tv.get_buffer()
end_iter = buffer.get_end_iter()
buffer.create_mark('end', end_iter, 0)
self.tagIn[user.jid] = buffer.create_tag("incoming")
color = self.plugin.config['inmsgcolor']
self.tagIn[user.jid].set_property("foreground", color)
self.tagOut[user.jid] = buffer.create_tag("outgoing")
color = self.plugin.config['outmsgcolor']
self.tagOut[user.jid].set_property("foreground", color)
self.tagStatus[user.jid] = buffer.create_tag("status")
color = self.plugin.config['statusmsgcolor']
self.tagStatus[user.jid].set_property("foreground", color)
vp.add2(sw)
sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
tv = gtk.TextView()
tv.set_wrap_mode(gtk.WRAP_WORD)
self.widgets[user.jid]['message'] = tv
tv.connect('key_press_event', self.on_msg_key_press_event)
vb.show_all()
nb = self.xml.get_widget("notebook")
nb.set_current_page(nb.append_page(vb))
self.redraw_tab(user.jid)
self.draw_widgets(user)

Yann Leboulanger
committed
tv.grab_focus()
#print queued messages
if self.plugin.queues[self.account].has_key(user.jid):
self.read_queue(self.plugin.queues[self.account][user.jid])
if user.show != 'online':
self.print_conversation(_("%s is now %s (%s)") % (user.name, \
user.show, user.status), user.jid, 'status')
def on_msg_key_press_event(self, widget, event):
"""When a key is pressed :
if enter is pressed without the shit key, message (if not empty) is sent
and printed in the conversation"""
if event.keyval == gtk.keysyms.Return:
if (event.state & gtk.gdk.SHIFT_MASK):
return 0
txt_buffer = widget.get_buffer()
start_iter = txt_buffer.get_start_iter()
end_iter = txt_buffer.get_end_iter()
txt = txt_buffer.get_text(start_iter, end_iter, 0)
if txt != '':
keyID = ''
jid = self.get_active_jid()
if self.widgets[jid]['toggle_gpg'].get_active():
keyID = self.users[jid].keyID
self.plugin.send('MSG', self.account, (jid, txt, keyID))
self.print_conversation(txt, jid, jid)
return 1
return 0
def on_chat_key_press_event(self, widget, event):

Yann Leboulanger
committed
nb = self.xml.get_widget("notebook")
st = "1234567890"
jid = self.get_active_jid()
if len(self.widgets) == 1:
widget.get_toplevel().destroy()
else:
nb.remove_page(nb.get_current_page())
del self.plugin.windows[self.account]['chats'][jid]
del self.users[jid]
del self.nb_unread[jid]
del self.widgets[jid]
del self.tagIn[jid]
del self.tagOut[jid]
del self.tagStatus[jid]
elif event.string and event.string in st \

Yann Leboulanger
committed
and (event.state & gtk.gdk.MOD1_MASK):
nb.set_current_page(st.index(event.string))
elif event.keyval == gtk.keysyms.Page_Down and \
(event.state & gtk.gdk.CONTROL_MASK):
current = nb.get_current_page()
if current > 0:
nb.set_current_page(current-1)
else:
nb.set_current_page(nb.get_n_pages()-1)
elif event.keyval == gtk.keysyms.Page_Up and \
(event.state & gtk.gdk.CONTROL_MASK):
current = nb.get_current_page()
if current < (nb.get_n_pages()-1):
nb.set_current_page(current+1)
else:
nb.set_current_page(0)
def on_button_contact_clicked(self, widget):
"""When button contact is clicked"""
jid = self.get_active_jid()
user = self.users[jid]
self.plugin.roster.on_info(widget, user, self.account)
def read_queue(self, q):
"""read queue and print messages containted in it"""
jid = self.get_active_jid()
user = self.users[jid]
self.print_conversation(evt[0], jid, tim = evt[1])
self.plugin.roster.nb_unread -= 1
self.plugin.roster.show_title()
del self.plugin.queues[self.account][jid]
self.plugin.roster.redraw_jid(jid, self.account)
self.plugin.systray.remove_jid(jid, self.account)
showOffline = self.plugin.config['showoffline']
if (user.show == 'offline' or user.show == 'error') and \
not showOffline:
if len(self.plugin.roster.contacts[self.account][jid]) == 1:
self.plugin.roster.remove_user(user, self.account)
def print_conversation(self, txt, jid, contact = None, tim = None):
"""Print a line in the conversation :
if contact is set to status : it's a status message
if contact is set to another value : it's an outgoing message
if contact is not set : it's an incomming message"""
user = self.users[jid]
conversation = self.widgets[jid]['conversation']
buffer = conversation.get_buffer()
if not txt:
txt = ""
end_iter = buffer.get_end_iter()
if not tim:
tim = time.localtime()
tims = time.strftime("[%H:%M:%S]", tim)
buffer.insert(end_iter, tims + ' ')
otxt = ''
ttxt = ''
if contact == 'status':
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
tag = 'status'
ttxt = txt + '\n'
else:
if contact:
tag = 'outgoing'
name = self.plugin.nicks[self.account]
else:
tag = 'incoming'
name = user.name
if string.find(txt, '/me ') == 0:
ttxt = name + ' ' + txt[4:] + '\n'
else:
ttxt = '<' + name + '> '
otxt = txt + '\n'
buffer.insert_with_tags_by_name(end_iter, ttxt, tag)
if len(otxt) > 0:
beg = 0
if self.plugin.config['useemoticons']:
index = 0
while index < len(otxt):
if otxt[index] in self.plugin.roster.begin_emot:
for s in self.plugin.roster.emoticons:
l = len(s)
if s == otxt[index:index+l]:
buffer.insert(end_iter, otxt[beg:index])
buffer.insert_pixbuf(end_iter, \
self.plugin.roster.emoticons[s])
index+=l
beg = index
index+=1
buffer.insert(end_iter, otxt[beg:])
#scroll to the end of the textview
conversation.scroll_to_mark(buffer.get_mark('end'), 0.1, 0, 0, 0)
if (jid != self.get_active_jid() or not self.window.is_active()) and \
contact != 'status':
self.nb_unread[jid] += 1
self.redraw_tab(jid)
del self.plugin.windows[self.account]['chats'][self.user.jid]
def print_conversation(self, txt, jid, contact = None, tim = None):
"""Print a line in the conversation :
if contact is set to status : it's a status message
if contact is set to another value : it's an outgoing message
if contact is not set : it's an incomming message"""

Yann Leboulanger
committed
conversation_textview = self.xml.get_widget('conversation_textview')
conversation_buffer = conversation_textview.get_buffer()
if not txt:
txt = ""

Yann Leboulanger
committed
end_iter = conversation_buffer.get_end_iter()

Yann Leboulanger
committed
if not tim:
tim = time.localtime()
tims = time.strftime("[%H:%M:%S]", tim)

Yann Leboulanger
committed
conversation_buffer.insert(end_iter, tims + ' ')
otxt = ''
ttxt = ''
if contact and contact == 'status':
tag = 'status'
ttxt = txt + '\n'
if contact:
tag = 'outgoing'
name = self.plugin.nicks[self.account]
else:
tag = 'incoming'
name = self.user.name
if string.find(txt, '/me ') == 0:
ttxt = name + ' ' + txt[4:] + '\n'
else:
ttxt = '<' + name + '> '
otxt = txt + '\n'

Yann Leboulanger
committed
conversation_buffer.insert_with_tags_by_name(end_iter, ttxt, tag)
beg = 0
if self.plugin.config['useemoticons']:
index = 0
while index < len(otxt):
if otxt[index] in self.plugin.roster.begin_emot:
for s in self.plugin.roster.emoticons:
l = len(s)
if s == otxt[index:index+l]:

Yann Leboulanger
committed
conversation_buffer.insert(end_iter, otxt[beg:index])
conversation_buffer.insert_pixbuf(end_iter, self.plugin.roster.emoticons[s])

Yann Leboulanger
committed
conversation_buffer.insert(end_iter, otxt[beg:])
#scroll to the end of the textview

Yann Leboulanger
committed
conversation_textview.scroll_to_mark(conversation_buffer.get_mark('end'),\
0.1, 0, 0, 0)
if not self.window.is_active() and contact != 'status':

Yann Leboulanger
committed
self.nb_unread += 1
self.show_title()
def show_title(self):
start = ""
if self.nb_unread > 1:
start = "[" + str(self.nb_unread) + "] "
elif self.nb_unread == 1:
start = "* "
self.window.set_title(start + self.user.name + " (" + self.account + ")")

Yann Leboulanger
committed
def update_tags(self):
self.tagIn.set_property("foreground", self.plugin.config['inmsgcolor'])
self.tagOut.set_property("foreground", self.plugin.config['outmsgcolor'])
self.tagStatus.set_property("foreground", \
self.plugin.config['statusmsgcolor'])
def set_image(self, image, jid):
if image.get_storage_type() == gtk.IMAGE_ANIMATION:

Yann Leboulanger
committed
self.status_image.set_from_animation(image.get_animation())
elif image.get_storage_type() == gtk.IMAGE_PIXBUF:

Yann Leboulanger
committed
self.status_image.set_from_pixbuf(image.get_pixbuf())
"""read queue and print messages containted in it"""

Yann Leboulanger
committed
evt = q.get()
self.print_conversation(evt[0], self.user.jid, tim = evt[1])
self.plugin.roster.nb_unread -= 1
self.plugin.roster.show_title()
del self.plugin.queues[self.account][self.user.jid]

Yann Leboulanger
committed
self.plugin.roster.redraw_jid(self.user.jid, self.account)

Yann Leboulanger
committed
self.plugin.systray.remove_jid(self.user.jid, self.account)
showOffline = self.plugin.config['showoffline']
if (self.user.show == 'offline' or self.user.show == 'error') and \
not showOffline:
if len(self.plugin.roster.contacts[self.account][self.user.jid]) == 1:
self.plugin.roster.remove_user(self.user, self.account)
def on_chat_key_press_event(self, widget, event):
if event.keyval == gtk.keysyms.Escape:
widget.get_toplevel().destroy()
def on_msg_key_press_event(self, widget, event):
if enter is pressed without the shit key, message (if not empty) is sent
and printed in the conversation"""
if event.keyval == gtk.keysyms.Return:
if (event.state & gtk.gdk.SHIFT_MASK):
return 0

Yann Leboulanger
committed
message_buffer = widget.get_buffer()
start_iter = message_buffer.get_start_iter()
end_iter = message_buffer.get_end_iter()
txt = message_buffer.get_text(start_iter, end_iter, 0)

Yann Leboulanger
committed
if self.xml.get_widget('gpg_toggle_button').get_active():
keyID = self.keyID
self.plugin.send('MSG', self.account, (self.user.jid, txt, keyID))

Yann Leboulanger
committed
message_buffer.set_text('', -1)
self.print_conversation(txt, self.user.jid, self.user.jid)
"""When clear button is pressed :
clear the conversation"""

Yann Leboulanger
committed
conversation_buffer = self.xml.get_widget('conversation_textview').\
get_buffer()
deb, end = conversation_buffer.get_bounds()
conversation_buffer.delete(deb, end)
def on_history(self, widget):
"""When history button is pressed : call log window"""
if not self.plugin.windows['logs'].has_key(self.user.jid):
self.plugin.windows['logs'][self.user.jid] = log_Window(self.plugin, self.user.jid)
def on_focus(self, widget, event):
"""When window get focus"""

Yann Leboulanger
committed
self.plugin.systray.remove_jid(self.user.jid, self.account)

Yann Leboulanger
committed
if self.nb_unread > 0:
self.nb_unread = 0
self.show_title()
def on_button_contact_clicked(self, widget):
"""When button contact is clicked"""
self.plugin.roster.on_info(widget, self.user, self.account)
def __init__(self, user, plugin, account):
self.plugin = plugin
self.account = account

Yann Leboulanger
committed
self.nb_unread = 0
self.xml = gtk.glade.XML(GTKGUI_GLADE, 'Chat', APP)

Yann Leboulanger
committed
self.show_title()

Yann Leboulanger
committed
self.status_image = self.xml.get_widget('status_image')

Yann Leboulanger
committed
image = self.plugin.roster.pixbufs[user.show]
if image.get_storage_type() == gtk.IMAGE_ANIMATION:

Yann Leboulanger
committed
self.status_image.set_from_animation(image.get_animation())

Yann Leboulanger
committed
elif image.get_storage_type() == gtk.IMAGE_PIXBUF:

Yann Leboulanger
committed
self.status_image.set_from_pixbuf(image.get_pixbuf())
contact_button = self.xml.get_widget('contact_button')
contact_button.set_label(user.name + ' <' + user.jid + '>')

Yann Leboulanger
committed
self.xml.get_widget('gpg_toggle_button').set_sensitive(False)
message_textview = self.xml.get_widget('message_textview')
message_textview.grab_focus()
conversation_textview = self.xml.get_widget('conversation_textview')
conversation_buffer = conversation_textview.get_buffer()
end_iter = conversation_buffer.get_end_iter()
conversation_buffer.create_mark('end', end_iter, 0)
self.xml.signal_connect('gtk_widget_destroy', self.delete_event)
self.xml.signal_connect('on_clear_clicked', self.on_clear)
self.xml.signal_connect('on_button_contact_clicked', \
self.on_button_contact_clicked)

Yann Leboulanger
committed
self.xml.get_widget('button_contact').set_use_underline(False)
self.xml.signal_connect('on_focus', self.on_focus)
self.xml.signal_connect('on_history_clicked', self.on_history)
self.xml.signal_connect('on_msg_key_press_event', \
self.on_msg_key_press_event)
self.xml.signal_connect('on_chat_key_press_event', \
self.on_chat_key_press_event)

Yann Leboulanger
committed
self.tagIn = conversation_buffer.create_tag("incoming")
color = self.plugin.config['inmsgcolor']

Yann Leboulanger
committed
self.tagIn.set_property("foreground", color)

Yann Leboulanger
committed
self.tagOut = conversation_buffer.create_tag("outgoing")
color = self.plugin.config['outmsgcolor']

Yann Leboulanger
committed
self.tagOut.set_property("foreground", color)

Yann Leboulanger
committed
self.tagStatus = conversation_buffer.create_tag("status")
color = self.plugin.config['statusmsgcolor']

Yann Leboulanger
committed
self.tagStatus.set_property("foreground", color)
#print queued messages
if plugin.queues[account].has_key(user.jid):
self.read_queue(plugin.queues[account][user.jid])
if self.user.show != 'online':
self.print_conversation(_("%s is now %s (%s)") % (user.name, \
user.show, user.status), user.jid, 'status')
class gc:
def delete_event(self, widget):
"""close window"""
self.plugin.send('GC_STATUS', self.account, (self.nick, self.jid,\
'offline', 'offline'))
del self.plugin.windows[self.account]['gc'][self.jid]
def on_close(self, widget):
"""When Cancel button is clicked"""
widget.get_toplevel().destroy()
def get_role_iter(self, name):
model = self.tree.get_model()
iter = model.get_iter_root()
if not iter:
return None
while not fin:
account_name = model.get_value(iter, 1)
if name == account_name:
return iter
iter = model.iter_next(iter)
if not iter:
fin = True
return None
def get_user_iter(self, jid):
model = self.tree.get_model()
fin = False
role = model.get_iter_root()
if not role:
return None
while not fin:
fin2 = False
user = model.iter_children(role)
if not user:
fin2=True
while not fin2:
if jid == model.get_value(user, 1):
return user
user = model.iter_next(user)
if not user:
fin2 = True
role = model.iter_next(role)
if not role:
fin = True
return None
def remove_user(self, nick):
"""Remove a user from the roster"""
model = self.tree.get_model()
iter = self.get_user_iter(nick)
parent_iter = model.iter_parent(iter)
if model.iter_n_children(parent_iter) == 0:
model.remove(parent_iter)
def add_user_to_roster(self, nick, show, role):
model = self.tree.get_model()
role_iter = self.get_role_iter(role)
if not role_iter:
role_iter = model.append(None, (self.plugin.roster.pixbufs['closed']\
, role))
iter = model.append(role_iter, (img, nick))
self.tree.expand_row((model.get_path(role_iter)), False)
return iter
def get_role(self, jid_iter):
model = self.tree.get_model()
path = model.get_path(jid_iter)[0]
iter = model.get_iter(path)
return model.get_value(iter, 1)
def chg_user_status(self, nick, show, status, role, affiliation, jid, \
reason, actor, statusCode, account):
"""When a user change his status"""
model = self.tree.get_model()
if show == 'offline' or show == 'error':
if statusCode == '307':
self.print_conversation(_("%s has been kicked by %s: %s") % (nick, \
iter = self.get_user_iter(nick)
if not iter:
iter = self.add_user_to_roster(nick, show, role)
actual_role = self.get_role(iter)
if role != actual_role:
self.remove_user(nick)
self.add_user_to_roster(nick, show, role)
else:
img = self.plugin.roster.pixbufs[show]
model.set_value(iter, 0, img)
def on_msg_key_press_event(self, widget, event):
"""When a key is pressed :
if enter is pressed without the shit key, message (if not empty) is sent
and printed in the conversation"""
if event.keyval == gtk.keysyms.Return:
if (event.state & gtk.gdk.SHIFT_MASK):
return 0
txt_buffer = widget.get_buffer()
start_iter = txt_buffer.get_start_iter()
end_iter = txt_buffer.get_end_iter()
txt = txt_buffer.get_text(start_iter, end_iter, 0)
if txt != '':
self.plugin.send('GC_MSG', self.account, (self.jid, txt))
txt_buffer.set_text('', -1)
widget.grab_focus()
return 1
return 0
def print_conversation(self, txt, jid, contact = None, tim = None):
"""Print a line in the conversation :
if contact is set : it's a message from someone
if contact is not set : it's a message from the server"""
conversation = self.xml.get_widget('conversation')
buffer = conversation.get_buffer()
if not txt:
txt = ""
end_iter = buffer.get_end_iter()
if not tim:
tim = time.localtime()
tims = time.strftime("[%H:%M:%S]", tim)
buffer.insert(end_iter, tims)
if contact == self.nick:
buffer.insert_with_tags_by_name(end_iter, '<'+contact+'> ', \
'outgoing')
buffer.insert_with_tags_by_name(end_iter, '<' + contact + '> ', \
'incoming')
buffer.insert(end_iter, txt+'\n')
else:
buffer.insert_with_tags_by_name(end_iter, txt+'\n', \
'status')
#scroll to the end of the textview
conversation.scroll_to_mark(buffer.get_mark('end'), 0.1, 0, 0, 0)
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
def kick(self, widget, room_jid, nick):
"""kick a user"""
self.plugin.send('SET_ROLE', self.account, (room_jid, nick, 'none'))
def grant_voice(self, widget, room_jid, nick):
"""grant voice privilege to a user"""
self.plugin.send('SET_ROLE', self.account, (room_jid, nick, \
'participant'))
def revoke_voice(self, widget, room_jid, nick):
"""revoke voice privilege to a user"""
self.plugin.send('SET_ROLE', self.account, (room_jid, nick, 'visitor'))
def grant_moderator(self, widget, room_jid, nick):
"""grant moderator privilege to a user"""
self.plugin.send('SET_ROLE', self.account, (room_jid, nick, 'moderator'))
def revoke_moderator(self, widget, room_jid, nick):
"""revoke moderator privilege to a user"""
self.plugin.send('SET_ROLE', self.account, (room_jid, nick, \
'participant'))
def ban(self, widget, room_jid, nick):
"""ban a user"""
self.plugin.send('SET_AFFILIATION', self.account, (room_jid, nick, \
'outcast'))
def grant_membership(self, widget, room_jid, nick):
"""grant membership privilege to a user"""
self.plugin.send('SET_AFFILIATION', self.account, (room_jid, nick, \
'member'))
def revoke_membership(self, widget, room_jid, nick):
"""revoke membership privilege to a user"""
self.plugin.send('SET_AFFILIATION', self.account, (room_jid, nick, \
'none'))
def grant_admin(self, widget, room_jid, nick):
"""grant administrative privilege to a user"""
self.plugin.send('SET_AFFILIATION', self.account, (room_jid, nick, \
'admin'))
def revoke_admin(self, widget, room_jid, nick):
"""revoke administrative privilege to a user"""
self.plugin.send('SET_AFFILIATION', self.account, (room_jid, nick, \
'member'))
def grant_owner(self, widget, room_jid, nick):
"""grant owner privilege to a user"""
self.plugin.send('SET_AFFILIATION', self.account, (room_jid, nick, \
'owner'))
def revoke_owner(self, widget, room_jid, nick):
"""revoke owner privilege to a user"""
self.plugin.send('SET_AFFILIATION', self.account, (room_jid, nick, \
'admin'))
def mk_menu(self, event, iter):
"""Make user's popup menu"""
model = self.tree.get_model()
nick = model.get_value(iter, 1)
menu = gtk.Menu()
item = gtk.MenuItem(_("MUC"))
menu.append(item)
menu_sub = gtk.Menu()
item.set_submenu(menu_sub)
item = gtk.MenuItem(_("Kick"))
menu_sub.append(item)
item.connect("activate", self.kick, self.jid, nick)
item = gtk.MenuItem(_("Grant voice"))
menu_sub.append(item)
item.connect("activate", self.grant_voice, self.jid, nick)
item = gtk.MenuItem(_("Revoke voice"))
menu_sub.append(item)
item.connect("activate", self.revoke_voice, self.jid, nick)
item = gtk.MenuItem(_("Grant moderator"))
menu_sub.append(item)