def connect_with_roster_draw_contact(self, roster, jid, account, contact): if not self.active: return if gajim.jid_is_transport(jid): return child_iters = roster._get_contact_iter(jid, account, contact, roster.model) if not child_iters: return icon_name = helpers.get_icon_name_to_show(contact, account) if gajim.events.get_events(account, jid) or icon_name == 'requested': return host = jid.split('@')[1] server = self.known_servers.get(host, False) if not server: return if server not in roster.transports_state_images['16']: # we don't have iconset for this transport loaded yet. Let's do it self.make_transport_state_images(roster, server) if server in roster.transports_state_images['16'] and \ icon_name in roster.transports_state_images['16'][server]: state_images = roster.transports_state_images['16'][server] img = state_images[icon_name] for child_iter in child_iters: roster.model[child_iter][0] = img
def connect_with_roster_draw_contact(self, roster, jid, account, contact): if not self.active: return if gajim.jid_is_transport(jid): return child_iters = roster._get_contact_iter(jid, account, contact, roster.model) if not child_iters: return icon_name = helpers.get_icon_name_to_show(contact, account) if gajim.events.get_events(account, jid) or icon_name == 'requested': return host = jid.split('@')[1] server = self.known_servers.get(host, False) if not server: return if server not in roster.transports_state_images['16']: # we don't have iconset for this transport loaded yet. Let's do it self.make_transport_state_images(roster, server) if server in roster.transports_state_images['16'] and \ icon_name in roster.transports_state_images['16'][server]: state_images = roster.transports_state_images['16'][server] img = state_images[icon_name] for child_iter in child_iters: roster.model[child_iter][0] = img
def handle_agent_info_received(self, event): global jid_to_servers if NS_HTTPUPLOAD in event.features and gajim.jid_is_transport(event.jid): own_jid = gajim.get_jid_without_resource(str(event.stanza.getTo())) jid_to_servers[own_jid] = event.jid # map own jid to upload component's jid log.info(own_jid + " can do http uploads via component " + event.jid) # update all buttons for base in self.controls: self.update_button_state(base.chat_control)
def get_avatar_pixbuf_from_cache(fjid, use_local=True): """ Check if jid has cached avatar and if that avatar is valid image (can be shown) Returns None if there is no image in vcard/ Returns 'ask' if cached vcard should not be used (user changed his vcard, so we have new sha) or if we don't have the vcard """ jid, nick = gajim.get_room_and_nick_from_fjid(fjid) if gajim.config.get('hide_avatar_of_transport') and\ gajim.jid_is_transport(jid): # don't show avatar for the transport itself return None if any(jid in gajim.contacts.get_gc_list(acc) for acc in \ gajim.contacts.get_accounts()): is_groupchat_contact = True else: is_groupchat_contact = False puny_jid = helpers.sanitize_filename(jid) if is_groupchat_contact: puny_nick = helpers.sanitize_filename(nick) path = os.path.join(gajim.VCARD_PATH, puny_jid, puny_nick) local_avatar_basepath = os.path.join(gajim.AVATAR_PATH, puny_jid, puny_nick) + '_local' else: path = os.path.join(gajim.VCARD_PATH, puny_jid) local_avatar_basepath = os.path.join(gajim.AVATAR_PATH, puny_jid) + \ '_local' if use_local: for extension in ('.png', '.jpeg'): local_avatar_path = local_avatar_basepath + extension if os.path.isfile(local_avatar_path): avatar_file = open(local_avatar_path, 'rb') avatar_data = avatar_file.read() avatar_file.close() return get_pixbuf_from_data(avatar_data) if not os.path.isfile(path): return 'ask' vcard_dict = gajim.connections.values()[0].get_cached_vcard(fjid, is_groupchat_contact) if not vcard_dict: # This can happen if cached vcard is too old return 'ask' if 'PHOTO' not in vcard_dict: return None pixbuf = vcard.get_avatar_pixbuf_encoded_mime(vcard_dict['PHOTO'])[0] return pixbuf
def get_avatar_pixbuf_from_cache(fjid, use_local=True): """ Check if jid has cached avatar and if that avatar is valid image (can be shown) Returns None if there is no image in vcard/ Returns 'ask' if cached vcard should not be used (user changed his vcard, so we have new sha) or if we don't have the vcard """ jid, nick = gajim.get_room_and_nick_from_fjid(fjid) if gajim.config.get('hide_avatar_of_transport') and\ gajim.jid_is_transport(jid): # don't show avatar for the transport itself return None if any(jid in gajim.contacts.get_gc_list(acc) for acc in \ gajim.contacts.get_accounts()): is_groupchat_contact = True else: is_groupchat_contact = False puny_jid = helpers.sanitize_filename(jid) if is_groupchat_contact: puny_nick = helpers.sanitize_filename(nick) path = os.path.join(gajim.VCARD_PATH, puny_jid, puny_nick) local_avatar_basepath = os.path.join(gajim.AVATAR_PATH, puny_jid, puny_nick) + '_local' else: path = os.path.join(gajim.VCARD_PATH, puny_jid) local_avatar_basepath = os.path.join(gajim.AVATAR_PATH, puny_jid) + \ '_local' if use_local: for extension in ('.png', '.jpeg'): local_avatar_path = local_avatar_basepath + extension if os.path.isfile(local_avatar_path): avatar_file = open(local_avatar_path, 'rb') avatar_data = avatar_file.read() avatar_file.close() return get_pixbuf_from_data(avatar_data) if not os.path.isfile(path): return 'ask' vcard_dict = list(gajim.connections.values())[0].get_cached_vcard( fjid, is_groupchat_contact) if not vcard_dict: # This can happen if cached vcard is too old return 'ask' if 'PHOTO' not in vcard_dict: return None pixbuf = vcard.get_avatar_pixbuf_encoded_mime(vcard_dict['PHOTO'])[0] return pixbuf
def get_avatar_pixbuf_from_cache(jid): """checks if jid has cached avatar and if that avatar is valid image (can be shown) returns None if there is no image in vcard returns 'ask' if cached vcard should not be used (user changed his vcard, so we have new sha) or if we don't have the vcard""" if gajim.config.get("hide_avatar_of_transport") and gajim.jid_is_transport(jid): # don't show avatar for the transport itself return None if jid not in os.listdir(gajim.VCARDPATH): return "ask" vcard_dict = gajim.connections.values()[0].get_cached_vcard(jid) if not vcard_dict: # This can happen if cached vcard is too old return "ask" if not vcard_dict.has_key("PHOTO"): return None pixbuf = vcard.get_avatar_pixbuf_encoded_mime(vcard_dict["PHOTO"])[0] return pixbuf
def restore_conversation(self, jid): # don't restore lines if it's a transport if gajim.jid_is_transport(jid): return # How many lines to restore and when to time them out restore_how_many = gajim.config.get('restore_lines') timeout = gajim.config.get('restore_timeout') # in minutes # number of messages that are in queue and are already logged pending_how_many = 0 # we want to avoid duplication if gajim.awaiting_events[self.account].has_key(jid): events = gajim.awaiting_events[self.account][jid] for event in events: if event[0] == 'chat': pending_how_many += 1 rows = gajim.logger.get_last_conversation_lines(jid, restore_how_many, pending_how_many, timeout) for row in rows: # row[0] time, row[1] has kind, row[2] the message if not row[2]: # message is empty, we don't print it continue if row[1] in (constants.KIND_CHAT_MSG_SENT, constants.KIND_SINGLE_MSG_SENT): kind = 'outgoing' name = gajim.nicks[self.account] elif row[1] in (constants.KIND_SINGLE_MSG_RECV, constants.KIND_CHAT_MSG_RECV): kind = 'incoming' name = self.contacts[jid].name tim = time.localtime(float(row[0])) chat.Chat.print_conversation_line(self, row[2], jid, kind, name, tim, ['small'], ['small', 'restored_message'], ['small', 'restored_message'], False) if len(rows): conv_textview = self.conversation_textviews[jid] conv_textview.print_empty_line()
def get_contact_menu(contact, account, use_multiple_contacts=True, show_start_chat=True, show_encryption=False, show_buttonbar_items=True, control=None, gc_contact=None, is_anonymous=True): """ Build contact popup menu for roster and chat window. If control is not set, we hide invite_contacts_menuitem """ if not contact: return jid = contact.jid our_jid = jid == gajim.get_jid_from_account(account) roster = gajim.interface.roster xml = gtkgui_helpers.get_gtk_builder('contact_context_menu.ui') contact_context_menu = xml.get_object('contact_context_menu') start_chat_menuitem = xml.get_object('start_chat_menuitem') execute_command_menuitem = xml.get_object('execute_command_menuitem') rename_menuitem = xml.get_object('rename_menuitem') edit_groups_menuitem = xml.get_object('edit_groups_menuitem') send_file_menuitem = xml.get_object('send_file_menuitem') assign_openpgp_key_menuitem = xml.get_object('assign_openpgp_key_menuitem') add_special_notification_menuitem = xml.get_object( 'add_special_notification_menuitem') information_menuitem = xml.get_object('information_menuitem') history_menuitem = xml.get_object('history_menuitem') send_custom_status_menuitem = xml.get_object('send_custom_status_menuitem') send_single_message_menuitem = xml.get_object('send_single_message_menuitem') invite_menuitem = xml.get_object('invite_menuitem') block_menuitem = xml.get_object('block_menuitem') unblock_menuitem = xml.get_object('unblock_menuitem') ignore_menuitem = xml.get_object('ignore_menuitem') unignore_menuitem = xml.get_object('unignore_menuitem') set_custom_avatar_menuitem = xml.get_object('set_custom_avatar_menuitem') # Subscription submenu subscription_menuitem = xml.get_object('subscription_menuitem') send_auth_menuitem, ask_auth_menuitem, revoke_auth_menuitem = \ subscription_menuitem.get_submenu().get_children() add_to_roster_menuitem = xml.get_object('add_to_roster_menuitem') remove_from_roster_menuitem = xml.get_object( 'remove_from_roster_menuitem') manage_contact_menuitem = xml.get_object('manage_contact') convert_to_gc_menuitem = xml.get_object('convert_to_groupchat_menuitem') encryption_separator = xml.get_object('encryption_separator') toggle_gpg_menuitem = xml.get_object('toggle_gpg_menuitem') toggle_e2e_menuitem = xml.get_object('toggle_e2e_menuitem') last_separator = xml.get_object('last_separator') items_to_hide = [] contacts = gajim.contacts.get_contacts(account, jid) if len(contacts) > 1 and use_multiple_contacts: # several resources start_chat_menuitem.set_submenu(build_resources_submenu(contacts, account, gajim.interface.on_open_chat_window)) send_file_menuitem.set_submenu(build_resources_submenu(contacts, account, roster.on_send_file_menuitem_activate, cap=NS_FILE)) execute_command_menuitem.set_submenu(build_resources_submenu( contacts, account, roster.on_execute_command, cap=NS_COMMANDS)) else: start_chat_menuitem.connect('activate', gajim.interface.on_open_chat_window, contact, account) if contact.supports(NS_FILE) or contact.supports(NS_JINGLE_FILE_TRANSFER): send_file_menuitem.set_sensitive(True) send_file_menuitem.connect('activate', roster.on_send_file_menuitem_activate, contact, account) else: send_file_menuitem.set_sensitive(False) if contact.supports(NS_COMMANDS): execute_command_menuitem.set_sensitive(True) if gc_contact and gc_contact.jid and not is_anonymous: execute_command_menuitem.connect('activate', roster.on_execute_command, gc_contact, account, gc_contact.resource) else: execute_command_menuitem.connect('activate', roster.on_execute_command, contact, account, contact.resource) else: execute_command_menuitem.set_sensitive(False) rename_menuitem.connect('activate', roster.on_rename, 'contact', jid, account) history_menuitem.connect('activate', roster.on_history, contact, account) if control: convert_to_gc_menuitem.connect('activate', control._on_convert_to_gc_menuitem_activate) else: items_to_hide.append(convert_to_gc_menuitem) if _('Not in Roster') not in contact.get_shown_groups(): # contact is in normal group edit_groups_menuitem.connect('activate', roster.on_edit_groups, [(contact, account)]) if gajim.connections[account].gpg: assign_openpgp_key_menuitem.connect('activate', roster.on_assign_pgp_key, contact, account) else: assign_openpgp_key_menuitem.set_sensitive(False) else: # contact is in group 'Not in Roster' edit_groups_menuitem.set_sensitive(False) assign_openpgp_key_menuitem.set_sensitive(False) # Hide items when it's self contact row if our_jid: items_to_hide += [rename_menuitem, edit_groups_menuitem] # Unsensitive many items when account is offline if gajim.account_is_disconnected(account): for widget in (start_chat_menuitem, rename_menuitem, edit_groups_menuitem, send_file_menuitem, convert_to_gc_menuitem, information_menuitem): widget.set_sensitive(False) if not show_start_chat: items_to_hide.append(start_chat_menuitem) if not show_encryption or not control: items_to_hide += [encryption_separator, toggle_gpg_menuitem, toggle_e2e_menuitem] else: e2e_is_active = control.session is not None and \ control.session.enable_encryption # check if we support and use gpg if not gajim.config.get_per('accounts', account, 'keyid') or \ not gajim.connections[account].USE_GPG or gajim.jid_is_transport( contact.jid): toggle_gpg_menuitem.set_sensitive(False) else: toggle_gpg_menuitem.set_sensitive(control.gpg_is_active or \ not e2e_is_active) toggle_gpg_menuitem.set_active(control.gpg_is_active) toggle_gpg_menuitem.connect('activate', control._on_toggle_gpg_menuitem_activate) # disable esessions if we or the other client don't support them if not gajim.HAVE_PYCRYPTO or not contact.supports(NS_ESESSION) or \ not gajim.config.get_per('accounts', account, 'enable_esessions'): toggle_e2e_menuitem.set_sensitive(False) else: toggle_e2e_menuitem.set_active(e2e_is_active) toggle_e2e_menuitem.set_sensitive(e2e_is_active or \ not control.gpg_is_active) toggle_e2e_menuitem.connect('activate', control._on_toggle_e2e_menuitem_activate) if not show_buttonbar_items: items_to_hide += [history_menuitem, send_file_menuitem, information_menuitem, convert_to_gc_menuitem, last_separator] if not control: items_to_hide.append(convert_to_gc_menuitem) # Hide items when it's a pm if gc_contact: items_to_hide += [rename_menuitem, edit_groups_menuitem, subscription_menuitem, remove_from_roster_menuitem] for item in items_to_hide: item.set_no_show_all(True) item.hide() # Zeroconf Account if gajim.config.get_per('accounts', account, 'is_zeroconf'): for item in (send_custom_status_menuitem, send_single_message_menuitem, invite_menuitem, block_menuitem, unblock_menuitem, ignore_menuitem, unignore_menuitem, set_custom_avatar_menuitem, subscription_menuitem, manage_contact_menuitem, convert_to_gc_menuitem): item.set_no_show_all(True) item.hide() if contact.show in ('offline', 'error'): information_menuitem.set_sensitive(False) send_file_menuitem.set_sensitive(False) else: information_menuitem.connect('activate', roster.on_info_zeroconf, contact, account) contact_context_menu.connect('selection-done', gtkgui_helpers.destroy_widget) contact_context_menu.show_all() return contact_context_menu # normal account # send custom status icon blocked = False if helpers.jid_is_blocked(account, jid): blocked = True else: for group in contact.get_shown_groups(): if helpers.group_is_blocked(account, group): blocked = True break transport = gajim.get_transport_name_from_jid(jid, use_config_setting=False) if transport and transport != 'jabber': # Transport contact, send custom status unavailable send_custom_status_menuitem.set_sensitive(False) elif blocked: send_custom_status_menuitem.set_sensitive(False) if gc_contact: if not gc_contact.jid: # it's a pm and we don't know real JID invite_menuitem.set_sensitive(False) else: bookmarked = False c_ = gajim.contacts.get_contact(account, gc_contact.jid, gc_contact.resource) if c_ and c_.supports(NS_CONFERENCE): bookmarked=True build_invite_submenu(invite_menuitem, [(gc_contact, account)], show_bookmarked=bookmarked) else: force_resource = False if control and control.resource: force_resource = True build_invite_submenu(invite_menuitem, [(contact, account)], show_bookmarked=contact.supports(NS_CONFERENCE), force_resource=force_resource) if gajim.account_is_disconnected(account): invite_menuitem.set_sensitive(False) # One or several resource, we do the same for send_custom_status status_menuitems = Gtk.Menu() send_custom_status_menuitem.set_submenu(status_menuitems) for s in ('online', 'chat', 'away', 'xa', 'dnd', 'offline'): # icon MUST be different instance for every item status_menuitem = Gtk.MenuItem.new_with_label(helpers.get_uf_show(s)) status_menuitem.connect('activate', roster.on_send_custom_status, [(contact, account)], s) status_menuitems.append(status_menuitem) send_single_message_menuitem.connect('activate', roster.on_send_single_message_menuitem_activate, account, contact) remove_from_roster_menuitem.connect('activate', roster.on_req_usub, [(contact, account)]) information_menuitem.connect('activate', roster.on_info, contact, account) if _('Not in Roster') not in contact.get_shown_groups(): # contact is in normal group add_to_roster_menuitem.hide() add_to_roster_menuitem.set_no_show_all(True) if contact.sub in ('from', 'both'): send_auth_menuitem.set_sensitive(False) else: send_auth_menuitem.connect('activate', roster.authorize, jid, account) if contact.sub in ('to', 'both'): ask_auth_menuitem.set_sensitive(False) add_special_notification_menuitem.connect('activate', roster.on_add_special_notification_menuitem_activate, jid) else: ask_auth_menuitem.connect('activate', roster.req_sub, jid, _('I would like to add you to my roster'), account, contact.groups, contact.name) transport = gajim.get_transport_name_from_jid(jid, use_config_setting=False) if contact.sub in ('to', 'none') or transport not in ['jabber', None]: revoke_auth_menuitem.set_sensitive(False) else: revoke_auth_menuitem.connect('activate', roster.revoke_auth, jid, account) elif gajim.connections[account].roster_supported: # contact is in group 'Not in Roster' add_to_roster_menuitem.set_no_show_all(False) subscription_menuitem.set_sensitive(False) add_to_roster_menuitem.connect('activate', roster.on_add_to_roster, contact, account) else: add_to_roster_menuitem.hide() add_to_roster_menuitem.set_no_show_all(True) subscription_menuitem.set_sensitive(False) set_custom_avatar_menuitem.connect('activate', roster.on_set_custom_avatar_activate, contact, account) # Hide items when it's self contact row if our_jid: manage_contact_menuitem.set_sensitive(False) # Unsensitive items when account is offline if gajim.account_is_disconnected(account): for widget in (send_single_message_menuitem, subscription_menuitem, add_to_roster_menuitem, remove_from_roster_menuitem, execute_command_menuitem, send_custom_status_menuitem): widget.set_sensitive(False) if gajim.connections[account] and (gajim.connections[account].\ privacy_rules_supported or gajim.connections[account].blocking_supported): if helpers.jid_is_blocked(account, jid): block_menuitem.set_no_show_all(True) block_menuitem.hide() if gajim.get_transport_name_from_jid(jid, use_config_setting=False)\ and transport != 'jabber': unblock_menuitem.set_no_show_all(True) unblock_menuitem.hide() unignore_menuitem.set_no_show_all(False) unignore_menuitem.connect('activate', roster.on_unblock, [(contact, account)]) else: unblock_menuitem.connect('activate', roster.on_unblock, [(contact, account)]) else: unblock_menuitem.set_no_show_all(True) unblock_menuitem.hide() if gajim.get_transport_name_from_jid(jid, use_config_setting=False)\ and transport != 'jabber': block_menuitem.set_no_show_all(True) block_menuitem.hide() ignore_menuitem.set_no_show_all(False) ignore_menuitem.connect('activate', roster.on_block, [(contact, account)]) else: block_menuitem.connect('activate', roster.on_block, [(contact, account)]) else: unblock_menuitem.set_no_show_all(True) block_menuitem.set_sensitive(False) unblock_menuitem.hide() contact_context_menu.connect('selection-done', gtkgui_helpers.destroy_widget) contact_context_menu.show_all() return contact_context_menu
def get_contact_menu(contact, account, use_multiple_contacts=True, show_start_chat=True, show_encryption=False, show_buttonbar_items=True, control=None, gc_contact=None, is_anonymous=True): """ Build contact popup menu for roster and chat window. If control is not set, we hide invite_contacts_menuitem """ if not contact: return jid = contact.jid our_jid = jid == gajim.get_jid_from_account(account) roster = gajim.interface.roster xml = gtkgui_helpers.get_gtk_builder('contact_context_menu.ui') contact_context_menu = xml.get_object('contact_context_menu') start_chat_menuitem = xml.get_object('start_chat_menuitem') execute_command_menuitem = xml.get_object('execute_command_menuitem') rename_menuitem = xml.get_object('rename_menuitem') edit_groups_menuitem = xml.get_object('edit_groups_menuitem') send_file_menuitem = xml.get_object('send_file_menuitem') assign_openpgp_key_menuitem = xml.get_object('assign_openpgp_key_menuitem') add_special_notification_menuitem = xml.get_object( 'add_special_notification_menuitem') information_menuitem = xml.get_object('information_menuitem') history_menuitem = xml.get_object('history_menuitem') send_custom_status_menuitem = xml.get_object('send_custom_status_menuitem') send_single_message_menuitem = xml.get_object( 'send_single_message_menuitem') invite_menuitem = xml.get_object('invite_menuitem') block_menuitem = xml.get_object('block_menuitem') unblock_menuitem = xml.get_object('unblock_menuitem') ignore_menuitem = xml.get_object('ignore_menuitem') unignore_menuitem = xml.get_object('unignore_menuitem') set_custom_avatar_menuitem = xml.get_object('set_custom_avatar_menuitem') # Subscription submenu subscription_menuitem = xml.get_object('subscription_menuitem') send_auth_menuitem, ask_auth_menuitem, revoke_auth_menuitem = \ subscription_menuitem.get_submenu().get_children() add_to_roster_menuitem = xml.get_object('add_to_roster_menuitem') remove_from_roster_menuitem = xml.get_object('remove_from_roster_menuitem') manage_contact_menuitem = xml.get_object('manage_contact') convert_to_gc_menuitem = xml.get_object('convert_to_groupchat_menuitem') encryption_separator = xml.get_object('encryption_separator') toggle_gpg_menuitem = xml.get_object('toggle_gpg_menuitem') toggle_e2e_menuitem = xml.get_object('toggle_e2e_menuitem') last_separator = xml.get_object('last_separator') items_to_hide = [] contacts = gajim.contacts.get_contacts(account, jid) if len(contacts) > 1 and use_multiple_contacts: # several resources start_chat_menuitem.set_submenu( build_resources_submenu(contacts, account, gajim.interface.on_open_chat_window)) send_file_menuitem.set_submenu( build_resources_submenu(contacts, account, roster.on_send_file_menuitem_activate, cap=NS_FILE)) execute_command_menuitem.set_submenu( build_resources_submenu(contacts, account, roster.on_execute_command, cap=NS_COMMANDS)) else: start_chat_menuitem.connect('activate', gajim.interface.on_open_chat_window, contact, account) if contact.supports(NS_FILE) or contact.supports( NS_JINGLE_FILE_TRANSFER): send_file_menuitem.set_sensitive(True) send_file_menuitem.connect('activate', roster.on_send_file_menuitem_activate, contact, account) else: send_file_menuitem.set_sensitive(False) if contact.supports(NS_COMMANDS): execute_command_menuitem.set_sensitive(True) if gc_contact and gc_contact.jid and not is_anonymous: execute_command_menuitem.connect('activate', roster.on_execute_command, gc_contact, account, gc_contact.resource) else: execute_command_menuitem.connect('activate', roster.on_execute_command, contact, account, contact.resource) else: execute_command_menuitem.set_sensitive(False) rename_menuitem.connect('activate', roster.on_rename, 'contact', jid, account) history_menuitem.connect('activate', roster.on_history, contact, account) if control: convert_to_gc_menuitem.connect( 'activate', control._on_convert_to_gc_menuitem_activate) else: items_to_hide.append(convert_to_gc_menuitem) if _('Not in Roster') not in contact.get_shown_groups(): # contact is in normal group edit_groups_menuitem.connect('activate', roster.on_edit_groups, [(contact, account)]) if gajim.connections[account].gpg: assign_openpgp_key_menuitem.connect('activate', roster.on_assign_pgp_key, contact, account) else: assign_openpgp_key_menuitem.set_sensitive(False) else: # contact is in group 'Not in Roster' edit_groups_menuitem.set_sensitive(False) assign_openpgp_key_menuitem.set_sensitive(False) # Hide items when it's self contact row if our_jid: items_to_hide += [rename_menuitem, edit_groups_menuitem] # Unsensitive many items when account is offline if gajim.account_is_disconnected(account): for widget in (start_chat_menuitem, rename_menuitem, edit_groups_menuitem, send_file_menuitem, convert_to_gc_menuitem, information_menuitem): widget.set_sensitive(False) if not show_start_chat: items_to_hide.append(start_chat_menuitem) if not show_encryption or not control: items_to_hide += [ encryption_separator, toggle_gpg_menuitem, toggle_e2e_menuitem ] else: e2e_is_active = control.session is not None and \ control.session.enable_encryption # check if we support and use gpg if not gajim.config.get_per('accounts', account, 'keyid') or \ not gajim.connections[account].USE_GPG or gajim.jid_is_transport( contact.jid): toggle_gpg_menuitem.set_sensitive(False) else: toggle_gpg_menuitem.set_sensitive(control.gpg_is_active or \ not e2e_is_active) toggle_gpg_menuitem.set_active(control.gpg_is_active) toggle_gpg_menuitem.connect( 'activate', control._on_toggle_gpg_menuitem_activate) # disable esessions if we or the other client don't support them if not gajim.HAVE_PYCRYPTO or not contact.supports(NS_ESESSION) or \ not gajim.config.get_per('accounts', account, 'enable_esessions'): toggle_e2e_menuitem.set_sensitive(False) else: toggle_e2e_menuitem.set_active(e2e_is_active) toggle_e2e_menuitem.set_sensitive(e2e_is_active or \ not control.gpg_is_active) toggle_e2e_menuitem.connect( 'activate', control._on_toggle_e2e_menuitem_activate) if not show_buttonbar_items: items_to_hide += [ history_menuitem, send_file_menuitem, information_menuitem, convert_to_gc_menuitem, last_separator ] if not control: items_to_hide.append(convert_to_gc_menuitem) # Hide items when it's a pm if gc_contact: items_to_hide += [ rename_menuitem, edit_groups_menuitem, subscription_menuitem, remove_from_roster_menuitem ] for item in items_to_hide: item.set_no_show_all(True) item.hide() # Zeroconf Account if gajim.config.get_per('accounts', account, 'is_zeroconf'): for item in (send_custom_status_menuitem, send_single_message_menuitem, invite_menuitem, block_menuitem, unblock_menuitem, ignore_menuitem, unignore_menuitem, set_custom_avatar_menuitem, subscription_menuitem, manage_contact_menuitem, convert_to_gc_menuitem): item.set_no_show_all(True) item.hide() if contact.show in ('offline', 'error'): information_menuitem.set_sensitive(False) send_file_menuitem.set_sensitive(False) else: information_menuitem.connect('activate', roster.on_info_zeroconf, contact, account) contact_context_menu.connect('selection-done', gtkgui_helpers.destroy_widget) contact_context_menu.show_all() return contact_context_menu # normal account # send custom status icon blocked = False if helpers.jid_is_blocked(account, jid): blocked = True else: for group in contact.get_shown_groups(): if helpers.group_is_blocked(account, group): blocked = True break transport = gajim.get_transport_name_from_jid(jid, use_config_setting=False) if transport and transport != 'jabber': # Transport contact, send custom status unavailable send_custom_status_menuitem.set_sensitive(False) elif blocked: send_custom_status_menuitem.set_sensitive(False) if gc_contact: if not gc_contact.jid: # it's a pm and we don't know real JID invite_menuitem.set_sensitive(False) else: bookmarked = False c_ = gajim.contacts.get_contact(account, gc_contact.jid, gc_contact.resource) if c_ and c_.supports(NS_CONFERENCE): bookmarked = True build_invite_submenu(invite_menuitem, [(gc_contact, account)], show_bookmarked=bookmarked) else: force_resource = False if control and control.resource: force_resource = True build_invite_submenu(invite_menuitem, [(contact, account)], show_bookmarked=contact.supports(NS_CONFERENCE), force_resource=force_resource) if gajim.account_is_disconnected(account): invite_menuitem.set_sensitive(False) # One or several resource, we do the same for send_custom_status status_menuitems = Gtk.Menu() send_custom_status_menuitem.set_submenu(status_menuitems) for s in ('online', 'chat', 'away', 'xa', 'dnd', 'offline'): # icon MUST be different instance for every item status_menuitem = Gtk.MenuItem.new_with_label(helpers.get_uf_show(s)) status_menuitem.connect('activate', roster.on_send_custom_status, [(contact, account)], s) status_menuitems.append(status_menuitem) send_single_message_menuitem.connect( 'activate', roster.on_send_single_message_menuitem_activate, account, contact) remove_from_roster_menuitem.connect('activate', roster.on_req_usub, [(contact, account)]) information_menuitem.connect('activate', roster.on_info, contact, account) if _('Not in Roster') not in contact.get_shown_groups(): # contact is in normal group add_to_roster_menuitem.hide() add_to_roster_menuitem.set_no_show_all(True) if contact.sub in ('from', 'both'): send_auth_menuitem.set_sensitive(False) else: send_auth_menuitem.connect('activate', roster.authorize, jid, account) if contact.sub in ('to', 'both'): ask_auth_menuitem.set_sensitive(False) add_special_notification_menuitem.connect( 'activate', roster.on_add_special_notification_menuitem_activate, jid) else: ask_auth_menuitem.connect( 'activate', roster.req_sub, jid, _('I would like to add you to my roster'), account, contact.groups, contact.name) transport = gajim.get_transport_name_from_jid(jid, use_config_setting=False) if contact.sub in ('to', 'none') or transport not in ['jabber', None]: revoke_auth_menuitem.set_sensitive(False) else: revoke_auth_menuitem.connect('activate', roster.revoke_auth, jid, account) elif gajim.connections[account].roster_supported: # contact is in group 'Not in Roster' add_to_roster_menuitem.set_no_show_all(False) subscription_menuitem.set_sensitive(False) add_to_roster_menuitem.connect('activate', roster.on_add_to_roster, contact, account) else: add_to_roster_menuitem.hide() add_to_roster_menuitem.set_no_show_all(True) subscription_menuitem.set_sensitive(False) set_custom_avatar_menuitem.connect('activate', roster.on_set_custom_avatar_activate, contact, account) # Hide items when it's self contact row if our_jid: manage_contact_menuitem.set_sensitive(False) # Unsensitive items when account is offline if gajim.account_is_disconnected(account): for widget in (send_single_message_menuitem, subscription_menuitem, add_to_roster_menuitem, remove_from_roster_menuitem, execute_command_menuitem, send_custom_status_menuitem): widget.set_sensitive(False) if gajim.connections[account] and (gajim.connections[account].\ privacy_rules_supported or gajim.connections[account].blocking_supported): if helpers.jid_is_blocked(account, jid): block_menuitem.set_no_show_all(True) block_menuitem.hide() if gajim.get_transport_name_from_jid(jid, use_config_setting=False)\ and transport != 'jabber': unblock_menuitem.set_no_show_all(True) unblock_menuitem.hide() unignore_menuitem.set_no_show_all(False) unignore_menuitem.connect('activate', roster.on_unblock, [(contact, account)]) else: unblock_menuitem.connect('activate', roster.on_unblock, [(contact, account)]) else: unblock_menuitem.set_no_show_all(True) unblock_menuitem.hide() if gajim.get_transport_name_from_jid(jid, use_config_setting=False)\ and transport != 'jabber': block_menuitem.set_no_show_all(True) block_menuitem.hide() ignore_menuitem.set_no_show_all(False) ignore_menuitem.connect('activate', roster.on_block, [(contact, account)]) else: block_menuitem.connect('activate', roster.on_block, [(contact, account)]) else: unblock_menuitem.set_no_show_all(True) block_menuitem.set_sensitive(False) unblock_menuitem.hide() contact_context_menu.connect('selection-done', gtkgui_helpers.destroy_widget) contact_context_menu.show_all() return contact_context_menu
class ChatControlSession(stanza_session.EncryptedStanzaSession): def __init__(self, conn, jid, thread_id, type_='chat'): stanza_session.EncryptedStanzaSession.__init__(self, conn, jid, thread_id, type_='chat') self.control = None def acknowledge_termination(self): if self.control: self.control.set_session(None) stanza_session.EncryptedStanzaSession.acknowledge_termination(self) def terminate(self): stanza_session.EncryptedStanzaSession.terminate(self) if self.control: self.control.set_session(None) # extracts chatstate from a <message/> stanza def get_chatstate(self, msg, msgtxt): composing_xep = None chatstate = None # chatstates - look for chatstate tags in a message if not delayed delayed = msg.getTag('x', namespace=common.xmpp.NS_DELAY) is not None if not delayed: composing_xep = False children = msg.getChildren() for child in children: if child.getNamespace( ) == 'http://jabber.org/protocol/chatstates': chatstate = child.getName() composing_xep = 'XEP-0085' break # No XEP-0085 support, fallback to XEP-0022 if not chatstate: chatstate_child = msg.getTag('x', namespace=common.xmpp.NS_EVENT) if chatstate_child: chatstate = 'active' composing_xep = 'XEP-0022' if not msgtxt and chatstate_child.getTag('composing'): chatstate = 'composing' return (composing_xep, chatstate) # dispatch a received <message> stanza def received(self, full_jid_with_resource, msgtxt, tim, encrypted, msg): msg_type = msg.getType() subject = msg.getSubject() if not msg_type or msg_type not in ('chat', 'groupchat', 'error'): msg_type = 'normal' msg_id = None # XEP-0172 User Nickname user_nick = msg.getTagData('nick') if not user_nick: user_nick = '' form_node = None for xtag in msg.getTags('x'): if xtag.getNamespace() == common.xmpp.NS_DATA: form_node = xtag break composing_xep, chatstate = self.get_chatstate(msg, msgtxt) xhtml = msg.getXHTML() if msg_type == 'chat': if not msg.getTag('body') and chatstate is None: return log_type = 'chat_msg_recv' else: log_type = 'single_msg_recv' if self.is_loggable() and msgtxt: try: msg_id = gajim.logger.write(log_type, full_jid_with_resource, msgtxt, tim=tim, subject=subject) except exceptions.PysqliteOperationalError, e: self.conn.dispatch('ERROR', (_('Disk WriteError'), str(e))) treat_as = gajim.config.get('treat_incoming_messages') if treat_as: msg_type = treat_as jid = gajim.get_jid_without_resource(full_jid_with_resource) resource = gajim.get_resource_from_jid(full_jid_with_resource) if gajim.config.get('ignore_incoming_xhtml'): xhtml = None if gajim.jid_is_transport(jid): jid = jid.replace('@', '') groupchat_control = gajim.interface.msg_win_mgr.get_gc_control( jid, self.conn.name) if not groupchat_control and \ jid in gajim.interface.minimized_controls[self.conn.name]: groupchat_control = gajim.interface.minimized_controls[self.conn.name]\ [jid] pm = False if groupchat_control and groupchat_control.type_id == \ message_control.TYPE_GC: # It's a Private message pm = True msg_type = 'pm' highest_contact = gajim.contacts.get_contact_with_highest_priority( self.conn.name, jid) # does this resource have the highest priority of any available? is_highest = not highest_contact or not highest_contact.resource or \ resource == highest_contact.resource or highest_contact.show == \ 'offline' # Handle chat states contact = gajim.contacts.get_contact(self.conn.name, jid, resource) if contact: if contact.composing_xep != 'XEP-0085': # We cache xep85 support contact.composing_xep = composing_xep if self.control and self.control.type_id == message_control.TYPE_CHAT: if chatstate is not None: # other peer sent us reply, so he supports jep85 or jep22 contact.chatstate = chatstate if contact.our_chatstate == 'ask': # we were jep85 disco? contact.our_chatstate = 'active' # no more self.control.handle_incoming_chatstate() elif contact.chatstate != 'active': # got no valid jep85 answer, peer does not support it contact.chatstate = False elif chatstate == 'active': # Brand new message, incoming. contact.our_chatstate = chatstate contact.chatstate = chatstate if msg_id: # Do not overwrite an existing msg_id with None contact.msg_id = msg_id # THIS MUST BE AFTER chatstates handling # AND BEFORE playsound (else we ear sounding on chatstates!) if not msgtxt: # empty message text return if gajim.config.get('ignore_unknown_contacts') and \ not gajim.contacts.get_contacts(self.conn.name, jid) and not pm: return if not contact: # contact is not in the roster, create a fake one to display # notification contact = contacts.Contact(jid=jid, resource=resource) advanced_notif_num = notify.get_advanced_notification( 'message_received', self.conn.name, contact) if not pm and is_highest: jid_of_control = jid else: jid_of_control = full_jid_with_resource if not self.control: ctrl = gajim.interface.msg_win_mgr.get_control( jid_of_control, self.conn.name) if ctrl: self.control = ctrl self.control.set_session(self) # Is it a first or next message received ? first = False if not self.control and not gajim.events.get_events(self.conn.name, \ jid_of_control, [msg_type]): first = True if pm: nickname = resource if self.control: # print if a control is open self.control.print_conversation(msgtxt, tim=tim, xhtml=xhtml, encrypted=encrypted) else: # otherwise pass it off to the control to be queued groupchat_control.on_private_message(nickname, msgtxt, tim, xhtml, self, msg_id=msg_id, encrypted=encrypted) else: self.roster_message(jid, msgtxt, tim, encrypted, msg_type, subject, resource, msg_id, user_nick, advanced_notif_num, xhtml=xhtml, form_node=form_node) nickname = gajim.get_name_from_jid(self.conn.name, jid) # Check and do wanted notifications msg = msgtxt if subject: msg = _('Subject: %s') % subject + '\n' + msg focused = False if self.control: parent_win = self.control.parent_win if self.control == parent_win.get_active_control() and \ parent_win.window.has_focus: focused = True notify.notify('new_message', jid_of_control, self.conn.name, [msg_type, first, nickname, msg, focused], advanced_notif_num) if gajim.interface.remote_ctrl: gajim.interface.remote_ctrl.raise_signal( 'NewMessage', (self.conn.name, [ full_jid_with_resource, msgtxt, tim, encrypted, msg_type, subject, chatstate, msg_id, composing_xep, user_nick, xhtml, form_node ]))