def __init__( self, server, proxies={}, transport_class=DirectConnection, version=15, client_type=msnp.ClientTypes.COMPUTER ): """Initializer @param server: the Notification server to connect to. @type server: tuple(host, port) @param proxies: proxies that we can use to connect @type proxies: {type: string => L{gnet.proxy.ProxyInfos}} @note the key should be 'http', 'https' or 'direct' @param transport_class: the transport class to use for the network connection @type transport_class: L{papyon.transport.BaseTransport} @param version: protocol version to use (MSNP15, MSNP18...) @type version: int @param client_type: type of client (computer, mobile, web...) @type client_type: L{ClientTypes<papyon.msnp.constants.ClientTypes>}""" EventsDispatcher.__init__(self) self.__state = ClientState.CLOSED self._proxies = proxies self._transport_class = transport_class self._client_type = client_type self._transport = transport_class(server, ServerType.NOTIFICATION, self._proxies) self._protocol = msnp.NotificationProtocol(self, self._transport, self._proxies, version) self._switchboard_manager = SwitchboardManager(self) self._switchboard_manager.register_handler_class(SwitchboardConversation) self._p2p_session_manager = P2PSessionManager(self) self._webcam_handler = WebcamHandler(self) self._p2p_session_manager.register_handler(self._webcam_handler) self._call_manager = SIPCallManager(self) self._rtc_activity_manager = RTCActivityManager(self, self._protocol) self._msn_object_store = MSNObjectStore(self) self._p2p_session_manager.register_handler(self._msn_object_store) self._ft_manager = FileTransferManager(self) self._p2p_session_manager.register_handler(self._ft_manager) self._external_conversations = {} self._sso = None self._profile = None self._address_book = None self._oim_box = None self._mailbox = None self._roaming = None self._turn_client = None self.__die = False self.__connect_transport_signals() self.__connect_protocol_signals() self.__connect_switchboard_manager_signals() self.__connect_webcam_handler_signals() self.__connect_call_manager_signals() self.__connect_ft_manager_signals()
def __init__(self, server, proxies={}, transport_class=DirectConnection, version=15, client_type=msnp.ClientTypes.COMPUTER): """Initializer @param server: the Notification server to connect to. @type server: tuple(host, port) @param proxies: proxies that we can use to connect @type proxies: {type: string => L{gnet.proxy.ProxyInfos}} @note the key should be 'http', 'https' or 'direct' @param transport_class: the transport class to use for the network connection @type transport_class: L{papyon.transport.BaseTransport} @param version: protocol version to use (MSNP15, MSNP18...) @type version: int @param client_type: type of client (computer, mobile, web...) @type client_type: L{ClientTypes<papyon.msnp.constants.ClientTypes>}""" EventsDispatcher.__init__(self) self.__state = ClientState.CLOSED self._proxies = proxies self._transport_class = transport_class self._client_type = client_type self._transport = transport_class(server, ServerType.NOTIFICATION, self._proxies) self._protocol = msnp.NotificationProtocol(self, self._transport, self._proxies, version) self._switchboard_manager = SwitchboardManager(self) self._switchboard_manager.register_handler_class( SwitchboardConversation) self._p2p_session_manager = P2PSessionManager(self) self._webcam_handler = WebcamHandler(self) self._p2p_session_manager.register_handler(self._webcam_handler) self._call_manager = SIPCallManager(self) self._rtc_activity_manager = RTCActivityManager(self, self._protocol) self._msn_object_store = MSNObjectStore(self) self._p2p_session_manager.register_handler(self._msn_object_store) self._ft_manager = FileTransferManager(self) self._p2p_session_manager.register_handler(self._ft_manager) self._external_conversations = {} self._sso = None self._profile = None self._address_book = None self._oim_box = None self._mailbox = None self._roaming = None self._turn_client = None self.__keepalive_conversations = False self.__die = False self.__connect_transport_signals() self.__connect_protocol_signals() self.__connect_switchboard_manager_signals() self.__connect_webcam_handler_signals() self.__connect_call_manager_signals() self.__connect_ft_manager_signals()
class Client(EventsDispatcher): """This class provides way to connect to the notification server as well as methods to manage the contact list, and the personnal settings. @sort: __init__, login, logout, state, profile, address_book, msn_object_store, oim_box, spaces""" def __init__( self, server, proxies={}, transport_class=DirectConnection, version=15, client_type=msnp.ClientTypes.COMPUTER ): """Initializer @param server: the Notification server to connect to. @type server: tuple(host, port) @param proxies: proxies that we can use to connect @type proxies: {type: string => L{gnet.proxy.ProxyInfos}} @note the key should be 'http', 'https' or 'direct' @param transport_class: the transport class to use for the network connection @type transport_class: L{papyon.transport.BaseTransport} @param version: protocol version to use (MSNP15, MSNP18...) @type version: int @param client_type: type of client (computer, mobile, web...) @type client_type: L{ClientTypes<papyon.msnp.constants.ClientTypes>}""" EventsDispatcher.__init__(self) self.__state = ClientState.CLOSED self._proxies = proxies self._transport_class = transport_class self._client_type = client_type self._transport = transport_class(server, ServerType.NOTIFICATION, self._proxies) self._protocol = msnp.NotificationProtocol(self, self._transport, self._proxies, version) self._switchboard_manager = SwitchboardManager(self) self._switchboard_manager.register_handler_class(SwitchboardConversation) self._p2p_session_manager = P2PSessionManager(self) self._webcam_handler = WebcamHandler(self) self._p2p_session_manager.register_handler(self._webcam_handler) self._call_manager = SIPCallManager(self) self._rtc_activity_manager = RTCActivityManager(self, self._protocol) self._msn_object_store = MSNObjectStore(self) self._p2p_session_manager.register_handler(self._msn_object_store) self._ft_manager = FileTransferManager(self) self._p2p_session_manager.register_handler(self._ft_manager) self._external_conversations = {} self._sso = None self._profile = None self._address_book = None self._oim_box = None self._mailbox = None self._roaming = None self._turn_client = None self.__die = False self.__connect_transport_signals() self.__connect_protocol_signals() self.__connect_switchboard_manager_signals() self.__connect_webcam_handler_signals() self.__connect_call_manager_signals() self.__connect_ft_manager_signals() ### Public API ----------------------------------------------------------- @property def msn_object_store(self): """The MSNObjectStore instance associated with this client. @rtype: L{MSNObjectStore<papyon.p2p.MSNObjectStore>}""" return self._msn_object_store @property def webcam_handler(self): """The webcam handler to create new sessions. @rtype: L{WebcamHandler<papyon.p2p.WebcamHandler>}""" return self._webcam_handler @property def profile(self): """The profile of the current user @rtype: L{User<papyon.profile.Profile>}""" return self._profile @property def address_book(self): """The address book of the current user @rtype: L{AddressBook<papyon.service.AddressBook>}""" return self._address_book @property def call_manager(self): """The SIP call manager @type: L{SIPCallManager<papyon.sip.SIPCallManager>}""" return self._call_manager @property def content_roaming(self): """The content roaming service @type: L{ContentRoaming<papyon.service.ContentRoaming>}""" return self._roaming @property def ft_manager(self): """The files transfer manager @type: L{FileTransferManager<papyon.p2p.FileTransferManager>}""" return self._ft_manager @property def rtc_activity_manager(self): """The RTC activity manager @type: L{RTCActivityManager<papyon.media.RTCActivityManager>}""" return self._rtc_activity_manager @property def oim_box(self): """The offline IM for the current user @rtype: L{OfflineIM<papyon.service.OfflineIM>}""" return self._oim_box @property def mailbox(self): """The mailbox of the current user @rtype: L{<papyon.msnp.mailbox.Mailbox>}""" return self._mailbox @property def spaces(self): """The MSN Spaces of the current user @rtype: L{Spaces<papyon.service.Spaces>}""" return self._spaces @property def state(self): """The state of this Client @rtype: L{papyon.event.ClientState}""" return self.__state @property def client_type(self): """Type of client (computer, mobile, web...) @rtype: L{ClientTypes<papyon.msnp.constants.ClientTypes>}""" return self._client_type def login(self, account, password): """Login to the server. @param account: the account to use for authentication. @type account: utf-8 encoded string @param password: the password needed to authenticate to the account @type password: utf-8 encoded string """ if self._state != ClientState.CLOSED: logger.warning("login already in progress") self.__die = False self._state = ClientState.CONNECTING self._profile = profile.Profile((account, password), self._protocol) self.__connect_profile_signals() self._transport.establish_connection() def logout(self): """Logout from the server.""" if self._state == ClientState.CLOSED: logger.warning("already logged out") return self.__die = True self._call_manager.close() self._p2p_session_manager.close() self._switchboard_manager.close() self._protocol.signoff() self.__state = ClientState.CLOSED ### Protected API -------------------------------------------------------- @property def local_ip(self): return self._transport.sockname[0] @property def protocol_version(self): return self._protocol._protocol_version @property def machine_guid(self): if not hasattr(self, "_guid"): self._guid = uuid.uuid4() return self._guid @rw_property def _state(): def fget(self): return self.__state def fset(self, state): self.__state = state self._dispatch("on_client_state_changed", state) return locals() def _register_external_conversation(self, conversation): for contact in conversation.participants: break if contact in self._external_conversations: logger.warning("trying to register an external conversation twice") return self._external_conversations[contact] = conversation def _unregister_external_conversation(self, conversation): for contact in conversation.participants: break del self._external_conversations[contact] ### Private API ---------------------------------------------------------- def __connect_profile_signals(self): """Connect profile signals""" def event(contact, *args): event_name = args[-1] event_args = args[:-1] method_name = "on_profile_%s" % event_name.replace("-", "_") self._dispatch(method_name, *event_args) def property_changed(profile, pspec): method_name = "on_profile_%s_changed" % pspec.name.replace("-", "_") self._dispatch(method_name) self.profile.connect("notify::presence", property_changed) self.profile.connect("notify::display-name", property_changed) self.profile.connect("notify::personal-message", property_changed) self.profile.connect("notify::current-media", property_changed) self.profile.connect("notify::msn-object", property_changed) self.profile.connect("notify::end-points", property_changed) def connect_signal(name): self.profile.connect(name, event, name) connect_signal("end-point-added") connect_signal("end-point-removed") def __connect_mailbox_signals(self): """Connect mailbox signals""" def new_mail_received(mailbox, mail): self._dispatch("on_mailbox_new_mail_received", mail) def unread_changed(mailbox, unread_count, initial): method_name = "on_mailbox_unread_mail_count_changed" self._dispatch(method_name, unread_count, initial) self.mailbox.connect("unread-mail-count-changed", unread_changed) self.mailbox.connect("new-mail-received", new_mail_received) def __connect_contact_signals(self, contact): """Connect contact signals""" def event(contact, *args): event_name = args[-1] event_args = args[:-1] method_name = "on_contact_%s" % event_name.replace("-", "_") self._dispatch(method_name, contact, *event_args) def property_changed(contact, pspec): method_name = "on_contact_%s_changed" % pspec.name.replace("-", "_") self._dispatch(method_name, contact) contact.connect("notify::memberships", property_changed) contact.connect("notify::presence", property_changed) contact.connect("notify::display-name", property_changed) contact.connect("notify::personal-message", property_changed) contact.connect("notify::current-media", property_changed) contact.connect("notify::msn-object", property_changed) contact.connect("notify::client-capabilities", property_changed) contact.connect("notify::end-points", property_changed) def connect_signal(name): contact.connect(name, event, name) connect_signal("infos-changed") def __connect_transport_signals(self): """Connect transport signals""" def connect_success(transp): self._sso = SSO.SingleSignOn(self.profile.account, self.profile.password, self._proxies) self._address_book = AB.AddressBook(self._sso, self, self._proxies) self.__connect_addressbook_signals() self._mailbox = msnp.Mailbox(self._protocol) self.__connect_mailbox_signals() self._oim_box = OIM.OfflineMessagesBox(self._sso, self, self._proxies) self.__connect_oim_box_signals() self._spaces = Spaces.Spaces(self._sso, self._proxies) self._roaming = CR.ContentRoaming(self._sso, self._address_book, self._proxies) self._turn_client = TURNClient(self._sso, self.profile.account) self._state = ClientState.CONNECTED def connect_failure(transp, reason): self._dispatch("on_client_error", ClientErrorType.NETWORK, reason) self._state = ClientState.CLOSED def disconnected(transp, reason): if not self.__die: self._dispatch("on_client_error", ClientErrorType.NETWORK, reason) self.__die = False self._state = ClientState.CLOSED self._transport.connect("connection-success", connect_success) self._transport.connect("connection-failure", connect_failure) self._transport.connect("connection-lost", disconnected) def __connect_protocol_signals(self): """Connect protocol signals""" def state_changed(proto, param): state = proto.state if state == msnp.ProtocolState.AUTHENTICATING: self._state = ClientState.AUTHENTICATING elif state == msnp.ProtocolState.AUTHENTICATED: self._state = ClientState.AUTHENTICATED elif state == msnp.ProtocolState.SYNCHRONIZING: self._state = ClientState.SYNCHRONIZING elif state == msnp.ProtocolState.SYNCHRONIZED: self._state = ClientState.SYNCHRONIZED elif state == msnp.ProtocolState.OPEN: self._state = ClientState.OPEN im_contacts = self.address_book.contacts for contact in im_contacts: self.__connect_contact_signals(contact) def error(proto, error): self._dispatch("on_client_error", ClientErrorType.PROTOCOL, error) self.__die = True self._transport.lose_connection() def unmanaged_message_received(proto, sender, message): if sender in self._external_conversations: conversation = self._external_conversations[sender] conversation._on_message_received(message) else: conversation = ExternalNetworkConversation(self, [sender]) if self._dispatch("on_invite_conversation", conversation) == 0: logger.warning("No event handler attached for conversations") conversation._on_message_received(message) self._protocol.connect("error", error) self._protocol.connect("notify::state", state_changed) self._protocol.connect("unmanaged-message-received", unmanaged_message_received) def __connect_switchboard_manager_signals(self): """Connect Switchboard Manager signals""" def handler_created(switchboard_manager, handler_class, handler): if handler_class is SwitchboardConversation: if self._dispatch("on_invite_conversation", handler) == 0: logger.warning("No event handler attached for conversations") elif handler_class in [SwitchboardP2PTransport]: pass else: logger.warning("Unknown Switchboard Handler class %s" % handler_class) self._switchboard_manager.connect("handler-created", handler_created) def __connect_addressbook_signals(self): """Connect AddressBook signals""" def event(address_book, *args): event_name = args[-1] event_args = args[:-1] if event_name == "contact-added": self.__connect_contact_signals(event_args[0]) # Call the old event name to be backward compatible self._dispatch("on_addressbook_messenger_contact_added", *event_args) method_name = "on_addressbook_%s" % event_name.replace("-", "_") self._dispatch(method_name, *event_args) def error(address_book, error_code): self._dispatch("on_client_error", ClientErrorType.ADDRESSBOOK, error_code) self.__die = True self._transport.lose_connection() self.address_book.connect("error", error) def connect_signal(name): self.address_book.connect(name, event, name) connect_signal("contact-added") connect_signal("contact-pending") connect_signal("contact-deleted") connect_signal("contact-blocked") connect_signal("contact-unblocked") connect_signal("group-added") connect_signal("group-deleted") connect_signal("group-renamed") connect_signal("group-contact-added") connect_signal("group-contact-deleted") def __connect_oim_box_signals(self): """Connect Offline IM signals""" def event(oim_box, *args): method_name = "on_oim_%s" % args[-1].replace("-", "_") self._dispatch(method_name, *args[:-1]) def state_changed(oim_box, pspec): self._dispatch("on_oim_state_changed", oim_box.state) def error(oim_box, error_code): self._dispatch("on_client_error", ClientErrorType.OFFLINE_MESSAGES, error_code) self.oim_box.connect("notify::state", state_changed) self.oim_box.connect("error", error) def connect_signal(name): self.oim_box.connect(name, event, name) connect_signal("messages-received") connect_signal("messages-fetched") connect_signal("message-sent") connect_signal("messages-deleted") def __connect_webcam_handler_signals(self): """Connect Webcam Handler signals""" def session_created(webcam_handler, session, producer): self._dispatch("on_invite_webcam", session, producer) self._webcam_handler.connect("session-created", session_created) def __connect_call_manager_signals(self): """Connect SIP Call Manager signals""" def invite_received(call_manager, call): self._dispatch("on_invite_conference", call) self._call_manager.connect("incoming-call", invite_received) def __connect_ft_manager_signals(self): """Connect File Transfer Manager signals""" def invite_received(ft_manager, session): self._dispatch("on_invite_file_transfer", session) self._ft_manager.connect("transfer-requested", invite_received)
class Client(EventsDispatcher): """This class provides way to connect to the notification server as well as methods to manage the contact list, and the personnal settings. @sort: __init__, login, logout, state, profile, address_book, msn_object_store, oim_box, spaces""" def __init__(self, server, proxies={}, transport_class=DirectConnection, version=15, client_type=msnp.ClientTypes.COMPUTER): """Initializer @param server: the Notification server to connect to. @type server: tuple(host, port) @param proxies: proxies that we can use to connect @type proxies: {type: string => L{gnet.proxy.ProxyInfos}} @note the key should be 'http', 'https' or 'direct' @param transport_class: the transport class to use for the network connection @type transport_class: L{papyon.transport.BaseTransport} @param version: protocol version to use (MSNP15, MSNP18...) @type version: int @param client_type: type of client (computer, mobile, web...) @type client_type: L{ClientTypes<papyon.msnp.constants.ClientTypes>}""" EventsDispatcher.__init__(self) self.__state = ClientState.CLOSED self._proxies = proxies self._transport_class = transport_class self._client_type = client_type self._transport = transport_class(server, ServerType.NOTIFICATION, self._proxies) self._protocol = msnp.NotificationProtocol(self, self._transport, self._proxies, version) self._switchboard_manager = SwitchboardManager(self) self._switchboard_manager.register_handler_class( SwitchboardConversation) self._p2p_session_manager = P2PSessionManager(self) self._webcam_handler = WebcamHandler(self) self._p2p_session_manager.register_handler(self._webcam_handler) self._call_manager = SIPCallManager(self) self._rtc_activity_manager = RTCActivityManager(self, self._protocol) self._msn_object_store = MSNObjectStore(self) self._p2p_session_manager.register_handler(self._msn_object_store) self._ft_manager = FileTransferManager(self) self._p2p_session_manager.register_handler(self._ft_manager) self._external_conversations = {} self._sso = None self._profile = None self._address_book = None self._oim_box = None self._mailbox = None self._roaming = None self._turn_client = None self.__keepalive_conversations = False self.__die = False self.__connect_transport_signals() self.__connect_protocol_signals() self.__connect_switchboard_manager_signals() self.__connect_webcam_handler_signals() self.__connect_call_manager_signals() self.__connect_ft_manager_signals() ### Public API ----------------------------------------------------------- @property def msn_object_store(self): """The MSNObjectStore instance associated with this client. @rtype: L{MSNObjectStore<papyon.p2p.MSNObjectStore>}""" return self._msn_object_store @property def webcam_handler(self): """The webcam handler to create new sessions. @rtype: L{WebcamHandler<papyon.p2p.WebcamHandler>}""" return self._webcam_handler @property def profile(self): """The profile of the current user @rtype: L{User<papyon.profile.Profile>}""" return self._profile @property def address_book(self): """The address book of the current user @rtype: L{AddressBook<papyon.service.AddressBook>}""" return self._address_book @property def call_manager(self): """The SIP call manager @type: L{SIPCallManager<papyon.sip.SIPCallManager>}""" return self._call_manager @property def content_roaming(self): """The content roaming service @type: L{ContentRoaming<papyon.service.ContentRoaming>}""" return self._roaming @property def ft_manager(self): """The files transfer manager @type: L{FileTransferManager<papyon.p2p.FileTransferManager>}""" return self._ft_manager @property def rtc_activity_manager(self): """The RTC activity manager @type: L{RTCActivityManager<papyon.media.RTCActivityManager>}""" return self._rtc_activity_manager @property def oim_box(self): """The offline IM for the current user @rtype: L{OfflineIM<papyon.service.OfflineIM>}""" return self._oim_box @property def mailbox(self): """The mailbox of the current user @rtype: L{<papyon.msnp.mailbox.Mailbox>}""" return self._mailbox @property def spaces(self): """The MSN Spaces of the current user @rtype: L{Spaces<papyon.service.Spaces>}""" return self._spaces @property def state(self): """The state of this Client @rtype: L{papyon.event.ClientState}""" return self.__state @property def client_type(self): """Type of client (computer, mobile, web...) @rtype: L{ClientTypes<papyon.msnp.constants.ClientTypes>}""" return self._client_type @rw_property def keepalive_conversations(): def fget(self): return self.__keepalive_conversations def fset(self, k_): self.__keepalive_conversations = k_ return locals() def login(self, account, password): """Login to the server. @param account: the account to use for authentication. @type account: utf-8 encoded string @param password: the password needed to authenticate to the account @type password: utf-8 encoded string """ if self._state != ClientState.CLOSED: logger.warning('login already in progress') return self.__die = False self._state = ClientState.CONNECTING self._profile = profile.Profile((account, password), self._protocol) self.__connect_profile_signals() self._transport.establish_connection() def logout(self): """Logout from the server.""" if self._state == ClientState.CLOSED: logger.warning('already logged out') return self.__die = True self._call_manager.close() self._p2p_session_manager.close() self._switchboard_manager.close() self._protocol.signoff() self.__state = ClientState.CLOSED def disconnect_other_endpoints(self): """ Disconnects other endpoints """ if self._state == ClientState.CLOSED: return self._protocol.send_user_notification("goawyplzthxbye-nomorempop", self.profile.account, "", 4) def disconnect_endpoint(self, ep_id): """ Disconnects single endpoint """ if self._state == ClientState.CLOSED: return self._protocol.send_user_notification("goawyplzthxbye", self.profile.account, ep_id, 4) ### Protected API -------------------------------------------------------- @property def client_ip(self): if not self._profile: return "" return self._profile.profile.get("ClientIP") @property def client_port(self): if not self._profile: return 0 return self._profile.profile.get("ClientPort") @property def local_ip(self): return self._transport.sockname[0] @property def local_port(self): return self._transport.sockname[1] @property def conn_type(self): if not self.local_ip or not self.client_ip: return "Unkown-Connect" if self.local_ip == self.client_ip: if self.local_port == self.client_port: return "Direct-Connect" else: return "Port-Restrict-NAT" else: if self.local_port == self.client_port: return "IP-Restrict-NAT" else: return "Symmetric-NAT" @property def protocol_version(self): return self._protocol._protocol_version @property def machine_guid(self): if not hasattr(self, '_guid'): self._guid = uuid.uuid4() return self._guid @rw_property def _state(): def fget(self): return self.__state def fset(self, state): self.__state = state self._dispatch("on_client_state_changed", state) return locals() def _register_external_conversation(self, conversation): for contact in conversation.participants: break if contact in self._external_conversations: logger.warning("trying to register an external conversation twice") return self._external_conversations[contact] = conversation def _unregister_external_conversation(self, conversation): for contact in conversation.participants: break del self._external_conversations[contact] ### Private API ---------------------------------------------------------- def __connect_profile_signals(self): """Connect profile signals""" def event(contact, *args): event_name = args[-1] event_args = args[:-1] method_name = "on_profile_%s" % event_name.replace("-", "_") self._dispatch(method_name, *event_args) def property_changed(profile, pspec): method_name = "on_profile_%s_changed" % pspec.name.replace( "-", "_") self._dispatch(method_name) self.profile.connect("notify::presence", property_changed) self.profile.connect("notify::display-name", property_changed) self.profile.connect("notify::personal-message", property_changed) self.profile.connect("notify::current-media", property_changed) self.profile.connect("notify::msn-object", property_changed) self.profile.connect("notify::end-points", property_changed) def connect_signal(name): self.profile.connect(name, event, name) connect_signal("end-point-added") connect_signal("end-point-removed") connect_signal("end-point-updated") def __connect_mailbox_signals(self): """Connect mailbox signals""" def new_mail_received(mailbox, mail): self._dispatch("on_mailbox_new_mail_received", mail) def unread_changed(mailbox, unread_count, initial): method_name = "on_mailbox_unread_mail_count_changed" self._dispatch(method_name, unread_count, initial) self.mailbox.connect("unread-mail-count-changed", unread_changed) self.mailbox.connect("new-mail-received", new_mail_received) def __connect_contact_signals(self, contact): """Connect contact signals""" def event(contact, *args): event_name = args[-1] event_args = args[:-1] method_name = "on_contact_%s" % event_name.replace("-", "_") self._dispatch(method_name, contact, *event_args) def property_changed(contact, pspec): method_name = "on_contact_%s_changed" % pspec.name.replace( "-", "_") self._dispatch(method_name, contact) contact.connect("notify::memberships", property_changed) contact.connect("notify::presence", property_changed) contact.connect("notify::display-name", property_changed) contact.connect("notify::personal-message", property_changed) contact.connect("notify::current-media", property_changed) contact.connect("notify::msn-object", property_changed) contact.connect("notify::client-capabilities", property_changed) contact.connect("notify::end-points", property_changed) def connect_signal(name): contact.connect(name, event, name) connect_signal("infos-changed") def __connect_transport_signals(self): """Connect transport signals""" def connect_success(transp): self._sso = SSO.SingleSignOn(self.profile.account, self.profile.password, self._proxies) self._address_book = AB.AddressBook(self._sso, self, self._proxies) self._mailbox = msnp.Mailbox(self._protocol) self._oim_box = OIM.OfflineMessagesBox(self._sso, self, self._proxies) self._spaces = Spaces.Spaces(self._sso, self._proxies) self._roaming = CR.ContentRoaming(self._sso, self._address_book, self._proxies) self._turn_client = TURNClient(self._sso, self.profile.account) self.__connect_addressbook_signals() self.__connect_mailbox_signals() self.__connect_oim_box_signals() self.__connect_roaming_signals() self._state = ClientState.CONNECTED def connect_failure(transp, reason): self._dispatch("on_client_error", ClientErrorType.NETWORK, reason) self._state = ClientState.CLOSED def disconnected(transp, reason): if not self.__die: self._dispatch("on_client_error", ClientErrorType.NETWORK, reason) self.__die = False self._state = ClientState.CLOSED self._transport.connect("connection-success", connect_success) self._transport.connect("connection-failure", connect_failure) self._transport.connect("connection-lost", disconnected) def __connect_protocol_signals(self): """Connect protocol signals""" def state_changed(proto, param): state = proto.state if state == msnp.ProtocolState.AUTHENTICATING: self._state = ClientState.AUTHENTICATING elif state == msnp.ProtocolState.AUTHENTICATED: self._state = ClientState.AUTHENTICATED elif state == msnp.ProtocolState.SYNCHRONIZING: self._state = ClientState.SYNCHRONIZING elif state == msnp.ProtocolState.SYNCHRONIZED: self._state = ClientState.SYNCHRONIZED elif state == msnp.ProtocolState.OPEN: self._state = ClientState.OPEN im_contacts = self.address_book.contacts for contact in im_contacts: self.__connect_contact_signals(contact) def error(proto, error): self._dispatch("on_client_error", ClientErrorType.PROTOCOL, error) self.__die = True self._transport.lose_connection() def unmanaged_message_received(proto, sender, message): if sender in self._external_conversations: conversation = self._external_conversations[sender] conversation._on_message_received(message) else: conversation = ExternalNetworkConversation(self, [sender]) if self._dispatch("on_invite_conversation", conversation) == 0: logger.warning( "No event handler attached for conversations") conversation._on_message_received(message) self._protocol.connect("error", error) self._protocol.connect("notify::state", state_changed) self._protocol.connect("unmanaged-message-received", unmanaged_message_received) def __connect_switchboard_manager_signals(self): """Connect Switchboard Manager signals""" def handler_created(switchboard_manager, handler_class, handler): if handler_class is SwitchboardConversation: if self._dispatch("on_invite_conversation", handler) == 0: logger.warning( "No event handler attached for conversations") elif handler_class in [SwitchboardP2PTransport]: pass else: logger.warning("Unknown Switchboard Handler class %s" % handler_class) self._switchboard_manager.connect("handler-created", handler_created) def __connect_addressbook_signals(self): """Connect AddressBook signals""" def event(address_book, *args): event_name = args[-1] event_args = args[:-1] if event_name == "contact-added": self.__connect_contact_signals(event_args[0]) # Call the old event name to be backward compatible self._dispatch("on_addressbook_messenger_contact_added", *event_args) method_name = "on_addressbook_%s" % event_name.replace("-", "_") self._dispatch(method_name, *event_args) def error(address_book, error_code): self._dispatch("on_client_error", ClientErrorType.ADDRESSBOOK, error_code) self.__die = True self._transport.lose_connection() self.address_book.connect('error', error) def connect_signal(name): self.address_book.connect(name, event, name) connect_signal("sync") connect_signal("contact-added") connect_signal("contact-pending") connect_signal("contact-deleted") connect_signal("contact-blocked") connect_signal("contact-unblocked") connect_signal("group-added") connect_signal("group-deleted") connect_signal("group-renamed") connect_signal("group-contact-added") connect_signal("group-contact-deleted") def __connect_oim_box_signals(self): """Connect Offline IM signals""" def event(oim_box, *args): method_name = "on_oim_%s" % args[-1].replace("-", "_") self._dispatch(method_name, *args[:-1]) def state_changed(oim_box, pspec): self._dispatch("on_oim_state_changed", oim_box.state) def error(oim_box, error_code): self._dispatch("on_client_error", ClientErrorType.OFFLINE_MESSAGES, error_code) self.oim_box.connect("notify::state", state_changed) self.oim_box.connect('error', error) def connect_signal(name): self.oim_box.connect(name, event, name) connect_signal("messages-received") connect_signal("messages-fetched") connect_signal("message-sent") connect_signal("messages-deleted") def __connect_roaming_signals(self): """Connect Content Roaming signals""" def state_changed(roaming, pspec): self._dispatch("on_roaming_state_changed", roaming.state) def error(roaming, error_code): self._dispatch("on_client_error", ClientErrorType.CONTENT_ROAMING, error_code) self._roaming.connect("notify::state", state_changed) self._roaming.connect("error", error) def __connect_webcam_handler_signals(self): """Connect Webcam Handler signals""" def session_created(webcam_handler, session, producer): self._dispatch("on_invite_webcam", session, producer) self._webcam_handler.connect("session-created", session_created) def __connect_call_manager_signals(self): """Connect SIP Call Manager signals""" def invite_received(call_manager, call): self._dispatch("on_invite_conference", call) self._call_manager.connect("incoming-call", invite_received) def __connect_ft_manager_signals(self): """Connect File Transfer Manager signals""" def invite_received(ft_manager, session): self._dispatch("on_invite_file_transfer", session) self._ft_manager.connect("transfer-requested", invite_received)