Beispiel #1
0
 def update_portraits_t_run(self):
     if self.update_all_portraits_t and not self.update_all_portraits_t.isFinished(
     ):
         return
     self.update_all_portraits_t = IThread(i_update_all_portraits,
                                           user=self.user)
     self.update_all_portraits_t.start()
Beispiel #2
0
 def listen_main_sock_t_run(self):
     """ TODO: offline-handler
     socket.error: [Errno 32] Broken pipe
     """
     # listen the socket (main sock) used in SIPC auth
     self.listen_main_sock_t = IThread(self.listen_sock,
                                       sock=self.user.get_sock(),
                                       data_list=self.server_push_data_list,
                                       signal='recved_server_push_datas()',
                                       debug=True)
     self.listen_main_sock_t.start()
Beispiel #3
0
 def set_portrait(self, path=None):
     if not path:
         path = self.user.get_portrait_path() or DEFAULT_PORTRAIT_PATH
     elif path and not os.path.exists(path):
         self.download_portrait_t = IThread(i_download_portrait_by_uri,
                                            user=self.user,
                                            uri=self.user.uri,
                                            debug=True)
         self.connect(self.download_portrait_t,
                      QtCore.SIGNAL("thread_finished()"),
                      self.download_portrait_t_finished)
         self.download_portrait_t.start()
     pixmap = QtGui.QPixmap(path)
     width, height = 60, 60
     pixmap = pixmap.scaled(QtCore.QSize(width, height))
     self.portraitLabel.setPixmap(pixmap)
Beispiel #4
0
    def sipc_auth_t_run(self):
        kill_qthread(self.sipc_auth_t)
        kill_qthread(self.sipc_auth_t_killer)

        self.sipc_auth_t = IThread(i_sipc_auth,
                                   user=self.user,
                                   verification=self.verification,
                                   debug=True)
        self.sipc_auth_t_killer = IThreadKiller(self.sipc_auth_t, timeout=10)

        self.connect(self.sipc_auth_t, QtCore.SIGNAL("thread_finished()"),
                     self.sipc_auth_t_finished)
        self.connect(self.sipc_auth_t_killer, QtCore.SIGNAL('kill_qthread()'),
                     self.kill_sipc_auth_t)

        self.sipc_auth_t.start()
        self.sipc_auth_t_killer.start()
Beispiel #5
0
    def download_sys_config_t_run(self):
        kill_qthread(self.download_sys_config_t)
        kill_qthread(self.download_sys_config_t_killer)

        self.download_sys_config_t = IThread(i_download_sys_config,
                                             user=self.user,
                                             debug=True)
        self.download_sys_config_t_killer = IThreadKiller(
            self.download_sys_config_t, timeout=20)

        self.connect(self.download_sys_config_t,
                     QtCore.SIGNAL("thread_finished()"),
                     self.download_sys_config_t_finished)
        self.connect(self.download_sys_config_t_killer,
                     QtCore.SIGNAL("kill_qthread()"),
                     self.kill_download_sys_config_t)

        self.download_sys_config_t.start()
        self.download_sys_config_t_killer.start()
Beispiel #6
0
 def listen_main_sock_t_run(self):
     """ TODO: offline-handler
     socket.error: [Errno 32] Broken pipe
     """
     # listen the socket (main sock) used in SIPC auth
     self.listen_main_sock_t = IThread(self.listen_sock, sock = self.user.get_sock(),
             data_list = self.server_push_data_list,
             signal = 'recved_server_push_datas()',
             debug = True)
     self.listen_main_sock_t.start()
Beispiel #7
0
    def send_msg(self, msg):
        my_name = self.user.get_display_name()

        cur_idx = self.convTab.currentIndex()
        to_uri = str(self.convTab.tabBar().tabData(cur_idx).toString())
        assert to_uri not in (None, "")

        convs = self.user.get_conversations()
        if to_uri not in convs:
            conv = Conversation(to_uri)
            convs[to_uri] = conv
        else:
            conv = convs[to_uri]

        send_msg_thread = IThread(i_send_msg, user = self.user, to_uri = to_uri, msg = msg)
        conv.send_msg_thread = send_msg_thread
        self.connect(send_msg_thread, QtCore.SIGNAL("thread_finished()"), self.send_msg_t_finished)
        send_msg_thread.start()

        chat_history_model = self.blah.contact_list_win.chat_history[to_uri]
        self.append_to_chat_history(chat_history_model, my_name, msg, MYSELF_LOG_TPL)
Beispiel #8
0
    def sipc_auth_t_run(self):
        kill_qthread(self.sipc_auth_t)
        kill_qthread(self.sipc_auth_t_killer)

        self.sipc_auth_t = IThread(i_sipc_auth, user = self.user, verification = self.verification, debug = True)
        self.sipc_auth_t_killer = IThreadKiller(self.sipc_auth_t, timeout = 10)

        self.connect(self.sipc_auth_t, QtCore.SIGNAL("thread_finished()"), self.sipc_auth_t_finished)
        self.connect(self.sipc_auth_t_killer, QtCore.SIGNAL('kill_qthread()'), self.kill_sipc_auth_t)

        self.sipc_auth_t.start()
        self.sipc_auth_t_killer.start()
Beispiel #9
0
 def set_portrait(self, path = None):
     if not path:
         path = self.user.get_portrait_path() or DEFAULT_PORTRAIT_PATH
     elif path and not os.path.exists(path):
         self.download_portrait_t = IThread(i_download_portrait_by_uri,
                 user = self.user, uri = self.user.uri, debug = True)
         self.connect(self.download_portrait_t, QtCore.SIGNAL("thread_finished()"),
                 self.download_portrait_t_finished)
         self.download_portrait_t.start()
     pixmap = QtGui.QPixmap(path)
     width, height = 60, 60
     pixmap = pixmap.scaled(QtCore.QSize(width, height))
     self.portraitLabel.setPixmap(pixmap)
Beispiel #10
0
    def download_sys_config_t_run(self):
        kill_qthread(self.download_sys_config_t)
        kill_qthread(self.download_sys_config_t_killer)

        self.download_sys_config_t = IThread(i_download_sys_config, user = self.user, debug = True)
        self.download_sys_config_t_killer = IThreadKiller(self.download_sys_config_t, timeout = 20)

        self.connect(self.download_sys_config_t, QtCore.SIGNAL("thread_finished()"),
                     self.download_sys_config_t_finished)
        self.connect(self.download_sys_config_t_killer, QtCore.SIGNAL("kill_qthread()"),
                     self.kill_download_sys_config_t)

        self.download_sys_config_t.start()
        self.download_sys_config_t_killer.start()
Beispiel #11
0
    def add_listener_for_conversation_sock(self, conv):
        assert conv.sock != self.user.get_sock()
        conv.listen_thread = IThread(
            self.listen_sock,
            sock=conv.sock,
            data_list=self.conversation_server_push_data_list,
            signal='recved_conversation_server_push_datas()',
            debug=True)
        conv.listen_thread.start()

        conv.keep_conn_busy_thread = PeriodicExecutor(30,
                                                      i_keep_connection_busy,
                                                      user=self.user,
                                                      sock=conv.sock)
        conv.keep_conn_busy_thread.start()
Beispiel #12
0
    def _consume_invitation(self, res_obj, sock):
        assert (sock is not None)
        """ TODO: ignore invitation will prevent from hide detecting. """
        i_send_ack(res_obj, sock)

        attr = res_obj.headers.get_field_value
        from_uri = attr("F")

        conv = Conversation(from_uri)
        convs = self.user.get_conversations()
        convs[from_uri] = conv
        get_sock_for_recv_msg_thread = IThread(get_sock_for_recv_msg,
                                               user=self.user,
                                               res_obj=res_obj,
                                               debug=True)
        conv.get_sock_for_recv_msg_thread = get_sock_for_recv_msg_thread
        self.connect(conv.get_sock_for_recv_msg_thread,
                     QtCore.SIGNAL("thread_finished()"),
                     self.recv_msg_t_finished)
        conv.get_sock_for_recv_msg_thread.start()
Beispiel #13
0
class ContactListWidow(QtGui.QWidget, Ui_ContactListWindow):
    FIRST_COLUMN = 0
    def __init__(self, blah):
        QtGui.QWidget.__init__(self)
        self.setupUi(self)
        self.setWindowIcon(QtGui.QIcon(LOGO_PATH))

        self.chat_history = {}

        self.blah = blah
        self.user = blah.user
        self.chat_win = ChatWindow(blah)
        self.chat_win.move(200, 200)

        self.load_user_presence_list()

        self.update_all_portraits_t = None

        # listen the socket (main sock) used in SIPC auth
        self.listen_main_sock_t = None
        self.server_push_data_list = []
        self.connect(self, QtCore.SIGNAL("recved_server_push_datas()"),
                     self.consume_server_push_datas)

        self.conversation_server_push_data_list = []
        self.connect(self, QtCore.SIGNAL("recved_conversation_server_push_datas()"),
                     self.consume_conversation_server_push_datas)

        self.setup_keep_alive_timer()
        self.setup_check_user_presence_timer()

        self._init_addition_widgets()

        i_subscribe_contact_list(self.user, debug = True)

        self.listen_main_sock_t_run()
        self.keep_alive_timer.start()

    def on_contact_list_double_clicked(self):
        contact = self.get_current_selected_contact()
        DOUBLE_CLICK_ON_CONTACT_ITEM = contact is not None
        if DOUBLE_CLICK_ON_CONTACT_ITEM:
            self.goto_or_create_tab_before_send_msg(contact)

    def _init_addition_widgets(self):
        self.nicknameLabel.setText(self.blah.get_my_name())
        self.set_user_presence()
        self._init_portrait_widget()

        self.contact_list_tree_model = ContactListTreeModel(self.user.group_agent)
        self.contact_list_tree_view.setModel(self.contact_list_tree_model)

        self.selection_model = self.contact_list_tree_view.selectionModel()

        self.contact_list_tree_view.mouseDoubleClickEvent = contact_list_double_click_wrapper(
                self.contact_list_tree_view.mousePressEvent, self.contact_list_tree_view)
        self.connect(self.contact_list_tree_view, QtCore.SIGNAL('doubleClicked()'),
                     self.on_contact_list_double_clicked)

        self.contact_list_tree_view.mouseReleaseEvent = contact_list_view_left_click_wrapper(
                self.contact_list_tree_view.mouseReleaseEvent, self.contact_list_tree_view)
        self.connect(self.contact_list_tree_view, QtCore.SIGNAL("leftClicked()"),
                     self.on_contact_group_left_clicked)

#        self.connect(self.contact_list_tree_model,
#            QtCore.SIGNAL('update_contact_order()'),
#            self.update_contact_order_after_presence_changed)

        self.update_portraits_t_run()

        self.reportBugBtn.clicked.connect(self.on_report_bug_btn_click)
        self.add_buddy_btn.clicked.connect(self.on_add_buddy_btn_click)

#    def update_contact_order_after_presence_changed(self):
#        logger.info('data_change')

    def on_contact_group_left_clicked(self):
        idx = self.selection_model.currentIndex()
        obj = idx.internalPointer()
        if obj and obj.get_type() == GroupAgentItemType.GROUP:
            if self.contact_list_tree_view.isExpanded(idx):
                self.contact_list_tree_view.collapse(idx)
            else:
                self.contact_list_tree_view.expand(idx)


    def update_portraits_t_run(self):
        if self.update_all_portraits_t and not self.update_all_portraits_t.isFinished():
            return
        self.update_all_portraits_t = IThread(i_update_all_portraits, user = self.user)
        self.update_all_portraits_t.start()

    def get_current_selected_contact(self):
        idx = self.selection_model.currentIndex()
        obj = idx.internalPointer()
        if obj and obj.get_type() == GroupAgentItemType.CONTACT:
            return obj

    def on_avatar_left_clicked(self):
        read_only = True
        user = self.blah.user
        is_save_btn_clicked, new_user = ProfileDialog.get_data(self, user, read_only)
        assert new_user != None

    def _init_portrait_widget(self):
        self.set_portrait()
        self.portraitLabel.mousePressEvent = portrait_left_click_wrapper(self.portraitLabel.mousePressEvent,
                                                                         self.portraitLabel)
        self.connect(self.portraitLabel, QtCore.SIGNAL('leftClicked()'), self.on_avatar_left_clicked)

        self.set_portrait()

    def set_portrait(self, path = None):
        if not path:
            path = self.user.get_portrait_path() or DEFAULT_PORTRAIT_PATH
        elif path and not os.path.exists(path):
            self.download_portrait_t = IThread(i_download_portrait_by_uri,
                    user = self.user, uri = self.user.uri, debug = True)
            self.connect(self.download_portrait_t, QtCore.SIGNAL("thread_finished()"),
                    self.download_portrait_t_finished)
            self.download_portrait_t.start()
        pixmap = QtGui.QPixmap(path)
        width, height = 60, 60
        pixmap = pixmap.scaled(QtCore.QSize(width, height))
        self.portraitLabel.setPixmap(pixmap)

    def download_portrait_t_finished(self):
        res_obj = self.download_portrait_t.get_return()
        assert res_obj != None

    def on_add_buddy_btn_click(self):
        myname = "" # self.user.nickname[:10]
        send_btn_clicked, data = AddBuddyDialog.get_data(parent = self, name = myname)
        if send_btn_clicked:
            i_add_buddy(self.user, data["account"], data["name"], debug = True)


    def on_report_bug_btn_click(self):
        popup_about(self)

    def switch_presence_to_online(self):
        pass

    def switch_presence_to_away(self):
        pass

    def switch_presence_to_invisible(self):
        pass

    def switch_presence_to_offline(self):
        logger.error("in switch_presence_to_offline()")
        # there are bug in timer ?
        # QObject::startTimer: QTimer can only be used with threads started with QThread
        self.check_user_presence_timer.stop()
        self.keep_alive_timer.stop()

        convs = self.user.get_conversations()
        uri_list = convs.keys()
        for uri in uri_list:
            conv = convs[uri]
            conv.over()
            convs.pop(uri)

        sock = self.user.get_sock()
        sock.close()

        while not self.listen_main_sock_t.isFinished():
            time.sleep(0.1)

        while not self.update_all_portraits_t.isFinished():
            time.sleep(0.1)

        self.hide()
        self.blah.show()
        self.blah.show_or_hide_login_widgets(show = True)

    def load_user_presence_list(self):
        for const, presence in UserPresence.__dict__["CONST_TO_STR_ZH"].iteritems():
            self.presenceComboBox.addItem(presence, QtCore.QVariant(const))

        self.connect(self.presenceComboBox, QtCore.SIGNAL('currentIndexChanged ( int )'),
                        self.on_presence_changed)

    def on_presence_changed(self, idx):
        presence_const = self.presenceComboBox.itemData(idx).toInt()[0]
        i_set_presence(self.user, presence_const)

        self.set_presence_icon(presence_const)

    def set_presence_icon(self, presence_const):
        #icon_path = os.path.join(ICON_PATH, "status-%s.png" % str(UserPresence(presence_const)))
        icon_path = ":/status-%s.png" % str(UserPresence(presence_const))
        self.presenceLabel.setPixmap(QtGui.QPixmap(icon_path))

    def set_user_presence(self):
        idx = self.presenceComboBox.findData(QtCore.QVariant(self.user.get_presence()))
        self.presenceComboBox.setCurrentIndex(idx)

        self.set_presence_icon(self.user.get_presence())

    def check_user_presence(self):
        if self.user.get_presence() == UserPresence.OFFLINE:
            logger.error('user.get_presence() == UserPresence.OFFLINE is True')
            self.switch_presence_to_offline()

    def consume_server_push_datas(self):
        while len(self.server_push_data_list):
            res_obj, sock = self.server_push_data_list.pop()
            self._consume_datas(res_obj, sock)

    def consume_conversation_server_push_datas(self):
        while len(self.conversation_server_push_data_list):
            res_obj, sock = self.conversation_server_push_data_list.pop()
            self._consume_datas(res_obj, sock)

    def _consume_notification(self, res_obj, sock):
        assert (sock is not None)
        sip_event_str = res_obj.headers.get_field_value("N")
        sip_event = SIPEvent.get_const_by_str(SIPEvent, sip_event_str)
        events = get_conversation_events(res_obj)

        body_dom = minidom.parseString(res_obj.body)
        CONTACT_PRESENCE_CHANGED = sip_event == SIPEvent.PRESENCE_V4 and \
                                   NotificationEvent.PRESENCE_CHANGED in events

        CONTACT_LEFT = sip_event == SIPEvent.CONVERSATION and \
                       NotificationEvent.USER_LEFT in events

        SYNC_USER_INFO_V4 = sip_event == SIPEvent.SYNC_USER_INFO_V4 and \
                        NotificationEvent.SYNC_USER_INFO in events

        BEEN_DISCONNECTED = sip_event == SIPEvent.REGISTRATION and \
                                NotificationEvent.DEREGISTRATION in events

        ADD_BUDDY_REFUSED = sip_event == SIPEvent.SYSTEM_NOTIFY_V4 and \
                            NotificationEvent.ADD_BUDDY_REFUSED in events

        USER_DYNAMICS_CHANGED = sip_event == SIPEvent.SYSTEM_NOTIFY_V4 and \
                                NotificationEvent.USER_DYNAMICS_CHANGED

        ADD_BUDDY_APPLICATION = sip_event == SIPEvent.CONTACT and \
                                NotificationEvent.ADD_BUDDY_APPLICATION in events

        convs = self.user.get_conversations()
        if CONTACT_PRESENCE_CHANGED:
            offline_uri_list = update_contacts_presence_from_response(self.user, body_dom)
            for uri in offline_uri_list:
                if uri in convs:
                    conv = convs[uri]
                    assert conv.sock != self.user.get_sock()
                    conv.over()
                    #convs.pop(uri)
            self.update_portraits_t_run()

            self.emit(QtCore.SIGNAL('dataChanged ( const QModelIndex & , const QModelIndex &  )'))

        elif CONTACT_LEFT:
            member_nodes = body_dom.getElementsByTagName("member")
            for member_node in member_nodes:
                uri = member_node.getAttribute("uri")
                conv = convs[uri]
                assert conv.sock != self.user.get_sock()
                conv.over()
                #convs.pop(uri)

        elif SYNC_USER_INFO_V4:
            self._consume_noti_sync_user_info_v4(res_obj)

        elif BEEN_DISCONNECTED:
            OFFLINE_ALERTS = "You have been disconnected" \
                "as someone has signed in with your ID on another computer." \
                "<br /><br />" \
                "Please note that if this was not intentional, some may have stolen your passwrod. "\
                "Please change your password."
            popup_error(self, OFFLINE_ALERTS)
            self.switch_presence_to_offline()
            #"Sign in again", "OK"

        elif ADD_BUDDY_REFUSED:
            uri, reason = i_parse_add_buddy_refused(body_dom)
            assert uri != reason
            logger.error("User (URI: %s) refused your add buddy application, reason: %s" % (uri, reason))

        elif ADD_BUDDY_APPLICATION:
            self._consume_add_buddy_application(res_obj)

        elif USER_DYNAMICS_CHANGED:
            pass

    def update_portraits(self):
        for contact in self.user.group_agent.get_all_contacts():
            if contact.image_changed == YES:
                i_download_portrait_by_uri(self.user, contact.uri)
                contact.image_changed = NO

    def _consume_add_buddy_application(self, res_obj):
        body_dom = minidom.parseString(res_obj.body)
        app_data = i_parse_add_buddy_application(body_dom)

        sid = get_sid_from_uri(app_data["uri"])
        SHOW_MSG_TPL = u"我是 %s (飞信号: %s ),想添加您为好友"
        show_msg = SHOW_MSG_TPL % (app_data["who"], sid)

        send_btn_clicked, data = ReplyAddBuddyDialog.get_data(parent = self,
                                        show_msg = show_msg)

        if send_btn_clicked:
            if data["accept"]:
                result = ReplyAddBuddyApplication.ACCEPT
            else:
                result = ReplyAddBuddyApplication.REFUSE
        else:
            result = ReplyAddBuddyApplication.IGNORE

        i_reply_add_buddy(self.user, res_obj, result,
                          data["refuse_reason"], data["decline_add_req_forever"],
                          debug = True)

    def _consume_noti_sync_user_info_v4(self, res_obj):
        body_dom = minidom.parseString(res_obj.body)

        contact_list_nodes = body_dom.getElementsByTagName("contact-list")
        if not contact_list_nodes:
            return
        assert len(contact_list_nodes) == 1
        contact_list_node = contact_list_nodes[0]
        contact_list_version = contact_list_node.getAttribute("version")
        if self.user.contact_list_version != contact_list_version:
            self.user.contact_list_version = contact_list_version

        buddy_nodes = body_dom.getElementsByTagName("buddy")
        for buddy_node in buddy_nodes:
            attr = buddy_node.getAttribute
            user_id = attr("user-id")
            contact = self.user.group_agent.get_contact_by_user_id(user_id)

            # someone send add buddy application to you,
            # and you send buddy application before any reply,
            # contact will be not found in self.user.contact_list.
            if not contact:
                continue

            if attr("action") == "remove":
                logger.error("!!! Your buddy (uri: %s) %s you" % (contact.uri, attr("action")))

                convs = self.user.conversations()
                conv = convs.get(contact.uri, None)
                if conv:
                    assert conv.sock != self.user.get_sock()
                    conv.over()
                    del conv
                self.user.group_agent.remove_user_by_user_id(user_id)

            elif attr("action") == "add":
                logger.info("!!! Your buddy (uri: %s) %s you" % (contact.uri, attr("action")))

                cat = Contact(user = self.blah.user)
                map_node_attr_to_obj(buddy_node, cat)
                self.user.contact_list.append(cat)
                cat.buddy_lists = attr("buddy-lists")
                cat.online_notify = attr("online-notify")
                cat.permission_values = attr("permission-values")

    def _consume_invitation(self, res_obj, sock):
        assert (sock is not None)

        """ TODO: ignore invitation will prevent from hide detecting. """
        i_send_ack(res_obj, sock)

        attr = res_obj.headers.get_field_value
        from_uri = attr("F")

        conv = Conversation(from_uri)
        convs = self.user.get_conversations()
        convs[from_uri] = conv
        get_sock_for_recv_msg_thread = IThread(get_sock_for_recv_msg, user = self.user, res_obj = res_obj,
                                      debug = True)
        conv.get_sock_for_recv_msg_thread = get_sock_for_recv_msg_thread
        self.connect(conv.get_sock_for_recv_msg_thread, QtCore.SIGNAL("thread_finished()"),
                     self.recv_msg_t_finished)
        conv.get_sock_for_recv_msg_thread.start()

    def recv_msg_t_finished(self):
        convs_d = dict()
        convs = self.user.get_conversations()
        for to_uri, conv in convs.iteritems():
            if conv.get_sock_for_recv_msg_thread and conv.get_sock_for_recv_msg_thread.isFinished():
                res_obj = conv.get_sock_for_recv_msg_thread.get_return()
                conv.get_sock_for_recv_msg_thread = None

                if res_obj.code == SIPResponse.OK:
                    assert conv.sock != self.user.get_sock()
                    assert conv.listen_thread == None
                    self.add_listener_for_conversation_sock(conv)
                    convs_d[to_uri] = conv
            else:
                convs_d[to_uri] = conv

        self.user.set_conversations(convs_d)

    def add_listener_for_conversation_sock(self, conv):
        assert conv.sock != self.user.get_sock()
        conv.listen_thread = IThread(self.listen_sock,
                sock = conv.sock,
                data_list = self.conversation_server_push_data_list,
                signal = 'recved_conversation_server_push_datas()',
                debug = True)
        conv.listen_thread.start()

        conv.keep_conn_busy_thread = PeriodicExecutor(30, i_keep_connection_busy,
                                                      user = self.user,
                                                      sock = conv.sock)
        conv.keep_conn_busy_thread.start()

    def _consume_message(self, res_obj, sock):
        assert (sock is not None)

        attr = res_obj.headers.get_field_value
        from_uri = attr("F")

        logger.info("Get message from: %s" % from_uri)

        msg = rm_markups(to_unicode_obj(res_obj.body))

        if from_uri != SERVICE_PROVIDER_URI:
            i_send_ack(res_obj, sock)
            contact = self.user.group_agent.get_contact_by_uri(from_uri)
            if not contact:
                """ This message send you before him delete you from his buddy list. """
                name = u"陌生人 (飞信号: %s) " % get_sid_from_uri(from_uri)
            else:
                name = contact.get_display_name()
        else:
            name = to_unicode_obj("系统信息")

        self.goto_or_create_tab_after_received_msg(from_uri)

        chat_history_model = self.chat_history[from_uri]
        self.chat_win.append_to_chat_history(chat_history_model, name, msg, OTHER_LOG_TPL)

    def goto_or_create_tab_after_received_msg(self, from_uri):
        IS_SYSTEM_MSG = from_uri.find('sip:') == STR_NOT_FOUND

        if not IS_SYSTEM_MSG:
            TAB_ALREADY_EXISTS = self.chat_win.go_to_tab_by_uri(from_uri)
            if not TAB_ALREADY_EXISTS:
                self.chat_win.create_tab(from_uri)

    def _consume_datas(self, res_obj, sock):
        sip_type = res_obj.get_sip_method()
        
        if sip_type == SIP.NOTIFICATION:
            self._consume_notification(res_obj, sock)
        elif sip_type == SIP.SIPC_4_0:
            i_process_sipc_request_response(self.user, res_obj)
        elif sip_type == SIP.INVITATION:
            self._consume_invitation(res_obj, sock)
        elif sip_type == SIP.MESSAGE:
            self._consume_message(res_obj, sock)

#        elif sip_type == SIP.INCOMING:
#            process_incoming(user, res_obj)

    def send_keep_connection_busy(self, sock, debug = False):
        i_keep_connection_busy(self.user, sock, debug)
#        try:
#            i_keep_connection_busy(self.user, sock, debug)
#        except socket.error as (err_no, err_msg):
#            assert err_msg != None
#            # `socket.error: [Errno 22] Invalid argument` exception means disconnect
#            if err_no == errno.EINVAL:
#                self.user.get_presence() = OFFLINE
#                time.sleep(1)

    def send_keep_alive(self, debug = False):
        i_send_keep_alive(self.user, debug)
#        try:
#            i_send_keep_alive(self.user, debug)
#        except socket.error as (err_no, err_msg):
#            assert err_msg != None
#            # `socket.error: [Errno 22] Invalid argument` exception means disconnect
#            if err_no == errno.EINVAL:
#                self.user.get_presence() = OFFLINE
#                time.sleep(1)

    def setup_keep_alive_timer(self):
        self.keep_alive_timer = QtCore.QTimer()
        self.connect(self.keep_alive_timer, QtCore.SIGNAL('timeout()'), self.send_keep_alive)
        msec = 1000 * 70
        self.keep_alive_timer.setInterval(msec)

    def setup_check_user_presence_timer(self):
        print " in setup_check_user_presence_timer() "
        self.check_user_presence_timer = QtCore.QTimer()
        self.connect(self.check_user_presence_timer, QtCore.SIGNAL('timeout()'), self.check_user_presence)
        msec = 1000 * 5
        self.check_user_presence_timer.setInterval(msec)

    def listen_main_sock_t_run(self):
        """ TODO: offline-handler
        socket.error: [Errno 32] Broken pipe
        """
        # listen the socket (main sock) used in SIPC auth
        self.listen_main_sock_t = IThread(self.listen_sock, sock = self.user.get_sock(),
                data_list = self.server_push_data_list,
                signal = 'recved_server_push_datas()',
                debug = True)
        self.listen_main_sock_t.start()

        # self.connect(self.listen_main_sock_t, QtCore.SIGNAL('thread_finished()'), self.switch_presence_to_offline)

    def listen_sock(self, sock, data_list, signal, debug = False):
        IS_MAIN_SOCK = sock is self.user.get_sock()
        if IS_MAIN_SOCK:
            is_main_sock = 'yes'
        else:
            is_main_sock = 'no'
        recv_buf = ""

        while True:
            try:
                readys = select.select([sock], [], [sock])
            except select.error as (err_no, err_msg):
                # sock passive close but listen thread still running
                logger.error("!!! %s while select, is main sock: %s" % (err_msg, is_main_sock))
                SOCK_CLOSED_T_RUNNING = (not IS_MAIN_SOCK) and (err_no == errno.EBADF)
                if SOCK_CLOSED_T_RUNNING:
                    return SOCK_CLOSED_T_RUNNING
            except socket.error as (err_no, err_msg):
                logger.error("!!! %s while select, is main sock: %s" % (err_msg, is_main_sock))
                DEREGISTERED = IS_MAIN_SOCK and (err_no == errno.EBADF)
                return DEREGISTERED

            input_ready = readys[0]
            except_ready = readys[2]

            if except_ready:
                logger.error("!!! Get exception while read socket")
                raise Exception("get exception while read socket")

            if input_ready:
                buf = ""
                try:
                    """ NOTICE: don't set size_once less than 1024, or you will get errno.EAGAIN and
                      this sock will couldn't read data again. """
                    buf = SIPConnection.recv(sock, size_once = 1024, flags = socket.MSG_DONTWAIT, debug = debug)
                except socket.error as (err_no, err_msg):
                    if err_no == errno.EAGAIN:
                        logger.error("!!! %s while sock.recv, is main sock: %s" % (err_msg, is_main_sock))
                        
                        res = is_a_complete_response(recv_buf)
                        CONTINUE_RECV = len(recv_buf) != 0 and res == SIPResponseValidity.NOT_COMPLETE
                        if CONTINUE_RECV:
                            print "CONTINUE_RECV:", CONTINUE_RECV
                            continue

                recv_buf += buf
                """Contact left conversation with a `UserLeft` push msg will be active close sock(i),
                this sock will receives nothing after `UserLeft`, so length of buf will be zero.

                This sock will be active close if get deregistered event type of registration notification,
                so length of buf will be zero too.
                """
                if len(recv_buf) == 0:
                    if not IS_MAIN_SOCK:
                        logger.error("!!! len(recv_buf) == 0, is main sock: %s", is_main_sock)
                        return
                else:
                    pkgs, remain = split_package(recv_buf)

                    while len(pkgs):
                        res_obj = pkgs.pop(0)
                        data_list.append((res_obj, sock))
                        self.emit(QtCore.SIGNAL(signal))
                    recv_buf = remain
Beispiel #14
0
class IBlah(QtGui.QMainWindow, Ui_LoginWindow):
    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        self.setupUi(self)
        self.setWindowIcon(QtGui.QIcon(LOGO_PATH))
        self.setWindowTitle(consts.NAME)
        
        self._debug_mode = None

        self.load_user_presence_list()
        self.load_account_list()

        self.user = None

        # SSI login thread
        self.ssi_auth_t = None
        self.ssi_auth_t_killer = None
        self.verification = None

        # SIPC auth thread
        self.sipc_auth_t = None
        self.sipc_auth_t_killer = None

        # download system configuration
        self.download_sys_config_t = None
        self.download_sys_config_t_killer = None

        # contact list widget
        self.contact_list_win = None

#        self.setup_tray_icon()
        self._init_misc_widgets()

        self._retry_times = 0

        self.show()

    def _init_misc_widgets(self):
        self.loginBtn.clicked.connect(self.on_login_btn_click)
        self.reportBugBtn.clicked.connect(self.on_report_bug_btn_click)

        self.progress_bar.setMaximum(0)
        self.progress_bar.setMinimum(0)
        self.progress_bar.hide()

        self.debug_mode_cb.hide()

    def get_my_name(self):
        return self.user.nickname or self.user.sid
        

    def load_account_list(self):
        self.accounts_basic_info_list = get_accounts_basic_info_list()

        for acc in self.accounts_basic_info_list:
            if acc["mobile_no"]:
                self.accountComboBox.addItem(acc["mobile_no"], QtCore.QVariant(acc["sid"]))
            else:
                self.accountComboBox.addItem(acc["sid"], QtCore.QVariant(acc["sid"]))

        self.connect(self.accountComboBox,
                     QtCore.SIGNAL('currentIndexChanged ( int )'),
                     self.on_account_combobox_index_changed)
        self.connect(self.accountComboBox,
                     QtCore.SIGNAL('editTextChanged ( const QString & )'),
                     self.on_account_combobox_text_changed)

        self.on_account_combobox_index_changed(self.accountComboBox.currentIndex())

        last_login_sid = get_last_login_sid()
        if last_login_sid:
            idx = self.accountComboBox.findData(QtCore.QVariant(last_login_sid))
            self.accountComboBox.setCurrentIndex(idx)

    def load_user_presence_list(self):
        for const, presence in UserPresence.__dict__["CONST_TO_STR_ZH"].iteritems():
            self.presenceComboBox.addItem(presence, QtCore.QVariant(const))
            self.set_debault_presence()

    def set_debault_presence(self):
        idx = self.presenceComboBox.findData(QtCore.QVariant(UserPresence.ONLINE))
        self.presenceComboBox.setCurrentIndex(idx)
        
    def on_account_combobox_index_changed(self, idx):
        account_no = str(self.accountComboBox.itemText(idx))
        self._fill_correspond_by_account_no(account_no)

    def _fill_correspond_by_account_no(self, account_no):
        for acc_basic_info in self.accounts_basic_info_list:
            if account_no == acc_basic_info["mobile_no"] or \
                account_no == acc_basic_info["sid"]:
                if not acc_basic_info["hashed_passwd"]:
                    self.rememberPasswdCheckBox.setCheckState(QtCore.Qt.Unchecked)
                    return
                
                passwd = acc_basic_info["hashed_passwd"]
                
                if passwd == "hash!":
                    passwd = ""
                self.passwdLineEdit.setText(passwd)
                self.rememberPasswdCheckBox.setCheckState(QtCore.Qt.Checked)

                presence = acc_basic_info["last_presence"]
                idx = self.presenceComboBox.findData(QtCore.QVariant(presence))
                self.presenceComboBox.setCurrentIndex(idx)
                return
            else:
                self.passwdLineEdit.setText("")
                self.rememberPasswdCheckBox.setCheckState(QtCore.Qt.Unchecked)
                self.set_debault_presence()

    def on_account_combobox_text_changed(self, account_no):
        self._fill_correspond_by_account_no(account_no)

    def on_report_bug_btn_click(self):
        popup_about(self)

    def download_sys_config_t_finished(self):
        kill_qthread(self.download_sys_config_t_killer)

        res_obj = self.download_sys_config_t.get_return()
        code = res_obj.code

        if code == httplib.OK:
            self.download_sys_config_t = None
            self.download_sys_config_t_killer = None
            self._retry_times = 0
            i_update_user_after_get_sys_config_success(self.user, res_obj.body)
            self.sipc_auth_t_run()
            return

        self.download_sys_config_t = None
        self.download_sys_config_t_killer = None
        self.show_or_hide_login_widgets(show = True)
        popup_error(self, "Download configuration response code: %d" % code)

    def kill_download_sys_config_t(self):
        kill_qthread(self.download_sys_config_t)

        if self._retry_times < MAX_RETRY_TIMES:
            self._retry_times += 1
            logger.error("Download configuration failed, auto re-try ...")
            self.download_sys_config_t_run()
            return

        self.verification = None
        self.user = None
        self.show_or_hide_login_widgets(show = True)

        popup_error(self, "Download configuration failed, try again later")

    def download_sys_config_t_run(self):
        kill_qthread(self.download_sys_config_t)
        kill_qthread(self.download_sys_config_t_killer)

        self.download_sys_config_t = IThread(i_download_sys_config, user = self.user, debug = True)
        self.download_sys_config_t_killer = IThreadKiller(self.download_sys_config_t, timeout = 20)

        self.connect(self.download_sys_config_t, QtCore.SIGNAL("thread_finished()"),
                     self.download_sys_config_t_finished)
        self.connect(self.download_sys_config_t_killer, QtCore.SIGNAL("kill_qthread()"),
                     self.kill_download_sys_config_t)

        self.download_sys_config_t.start()
        self.download_sys_config_t_killer.start()

    def ssi_auth_t_finished(self):
        # why not necessary to call disconnect(SIGNAL) here
        # http://doc.qt.nokia.com/4.7/qobject.html#disconnect-3
        kill_qthread(self.ssi_auth_t_killer)

        res_obj = self.ssi_auth_t.get_return()
        code = res_obj.code

        if code == httplib.OK:
            i_update_user_after_ssi_auth_success(self.user, res_obj, self.get_if_remember_passwd())

            self._retry_times = 0
            
            self.download_sys_config_t_run()

        elif code == HTTPResponse.PASSWD_ERROR:
            self.user = None
            self.show_or_hide_login_widgets(show = True)
            popup_error(self, u"密码错误")
            
        elif code in (HTTPResponse.CCPS_CHECK_ERROR, HTTPResponse.NEED_VERIFY):
            self.verification = i_generate_verification_pic(self.user, res_obj)
            body = "%s<br />%s" % (self.verification.text, self.verification.tips)
            (btn_val, chars) = GetVerificationDialog.get_input(body = body,
                        path = self.verification.picture_path)

            if btn_val:
                logger.info("(SSI auth)Input recognise chars: %s" % chars)
                self.verification.chars = chars
                self.ssi_auth_t_run()
            else:
                self.verification = None
                self.user = None
                self.show_or_hide_login_widgets(show = True)
        else:
            raise Exception("SSI authentication response code: %d" % code)

    def show_contact_list_win(self):
        self.contact_list_win = ContactListWidow(self)
        self.hide()
        self.contact_list_win.move(800, 150)
        self.contact_list_win.show()

    def kill_ssi_auth_t(self):
        if self._retry_times < MAX_RETRY_TIMES:
            self._retry_times += 1
            logger.error("SSI authentication failed, auto re-try ...")
            self.ssi_auth_t_run()
            return 

        self.verification = None
        self.user = None
        self.show_or_hide_login_widgets(show = True)

        popup_error(self, u"连接超时(SSI),请稍候再尝试")


    def sipc_auth_t_finished(self):
        kill_qthread(self.sipc_auth_t_killer)

        res_obj = self.sipc_auth_t.get_return()
        code = res_obj.code

        if code == SIPResponse.OK:
            self._retry_times = 0
            i_update_user_after_sipc_auth_success(self.user, res_obj)
            self.show_contact_list_win()
            return

        elif code == SIPResponse.EXTENSION_REQUIRED: # login location changed
            self.verification = i_generate_verification_pic(self.user, res_obj)
            body = "%s<br />%s" % (self.verification.text, self.verification.tips)
            (btn_val, chars) = GetVerificationDialog.get_input(body = body,
                        path = self.verification.picture_path)
            
            if btn_val:
                logger.info("(SIPC auth) Input recognise chars: %s" % chars)
                self.verification.chars = chars
                self.sipc_auth_t_run()
            else:
                self.verification = None
                self.user = None
                self.show_or_hide_login_widgets(show = True)

            return

        self.show_or_hide_login_widgets(show = True)
        popup_error(self, "SIPC authentication response code: %d" % code)

    def kill_sipc_auth_t(self):
        kill_qthread(self.sipc_auth_t)

        if self._retry_times < MAX_RETRY_TIMES:
            self._retry_times += 1
            logger.error("SIPC authentication failed, auto re-try ...")
            self.sipc_auth_t_run()
            return

        self.verification = None
        self.user = None
        self.show_or_hide_login_widgets(show = True)
        
        popup_error(self, u"连接超时(SIPC),请稍候再尝试")

    def on_login_btn_click(self):
        self._retry_times = 0
        account = self.get_account()
        passwd = self.get_passwd()

#        self._debug_mode = self.debug_mode_cb.checkState() == QtCore.Qt.Checked

        if not len(account) or not len(passwd):
            popup_error(self, u"帐号和密码都不能为空!")
            return
        else:
            last_char = account[-1]
            if last_char < '0' or last_char > '9':
                popup_error(self, u"您输入的不是一个有效的飞信号或者移动手机号,飞信邮箱协议暂时不兼容本软件")
                return

        hashed_passwd = i_hash_passwd(passwd)
        presence = self.get_presence()
        self.user = i_create_user(account, hashed_passwd, presence)
        self.ssi_auth_t_run()
        self.show_or_hide_login_widgets(show = False)

    def ssi_auth_t_run(self):
        kill_qthread(self.ssi_auth_t)
        kill_qthread(self.ssi_auth_t_killer)

        self.ssi_auth_t = IThread(i_ssi_auth, user = self.user, verification = self.verification, debug = True)
        self.ssi_auth_t_killer = IThreadKiller(self.ssi_auth_t, timeout = 10)

        self.connect(self.ssi_auth_t, QtCore.SIGNAL("thread_finished()"), self.ssi_auth_t_finished)
        self.connect(self.ssi_auth_t_killer, QtCore.SIGNAL('kill_qthread()'), self.kill_ssi_auth_t)

        self.ssi_auth_t.start()
        self.ssi_auth_t_killer.start()

    def sipc_auth_t_run(self):
        kill_qthread(self.sipc_auth_t)
        kill_qthread(self.sipc_auth_t_killer)

        self.sipc_auth_t = IThread(i_sipc_auth, user = self.user, verification = self.verification, debug = True)
        self.sipc_auth_t_killer = IThreadKiller(self.sipc_auth_t, timeout = 10)

        self.connect(self.sipc_auth_t, QtCore.SIGNAL("thread_finished()"), self.sipc_auth_t_finished)
        self.connect(self.sipc_auth_t_killer, QtCore.SIGNAL('kill_qthread()'), self.kill_sipc_auth_t)

        self.sipc_auth_t.start()
        self.sipc_auth_t_killer.start()

    def get_passwd(self):
        passwd = self.passwdLineEdit.text()
        return str(passwd)

    def get_account(self):
        account = self.accountComboBox.currentText()
        return str(account)

    def get_presence(self):
        idx = self.presenceComboBox.currentIndex()
        presence_const = self.presenceComboBox.itemData(idx).toInt()[0]
        return presence_const

    def get_if_remember_passwd(self):
        if_remember_passwd = self.rememberPasswdCheckBox.checkState() == QtCore.Qt.Checked
        return if_remember_passwd
    
    def get_if_debug_mode(self):
         return self._debug_mode 

    def thread_running(self):
        logger.info('thread running ... ')

    def show_or_hide_login_widgets(self, show = True):
        if show:
            self.accountLabel.show()
            self.accountComboBox.show()

            self.passwdLabel.show()
            self.passwdLineEdit.show()

            self.presenceComboBox.show()
            self.rememberPasswdCheckBox.show()

            self.loginBtn.show()
#            self.debug_mode_cb.show()
            self.reportBugBtn.show()

            self.progress_bar.hide()
        else:
            self.accountLabel.hide()
            self.accountComboBox.hide()

            self.passwdLabel.hide()
            self.passwdLineEdit.hide()

            self.presenceComboBox.hide()
            self.rememberPasswdCheckBox.hide()

            self.loginBtn.hide()
#            self.debug_mode_cb.hide()
            self.reportBugBtn.hide()

            self.progress_bar.show()
Beispiel #15
0
class IBlah(QtGui.QMainWindow, Ui_LoginWindow):
    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        self.setupUi(self)
        self.setWindowIcon(QtGui.QIcon(LOGO_PATH))
        self.setWindowTitle(consts.NAME)

        self._debug_mode = None

        self.load_user_presence_list()
        self.load_account_list()

        self.user = None

        # SSI login thread
        self.ssi_auth_t = None
        self.ssi_auth_t_killer = None
        self.verification = None

        # SIPC auth thread
        self.sipc_auth_t = None
        self.sipc_auth_t_killer = None

        # download system configuration
        self.download_sys_config_t = None
        self.download_sys_config_t_killer = None

        # contact list widget
        self.contact_list_win = None

        #        self.setup_tray_icon()
        self._init_misc_widgets()

        self._retry_times = 0

        self.show()

    def _init_misc_widgets(self):
        self.loginBtn.clicked.connect(self.on_login_btn_click)
        self.reportBugBtn.clicked.connect(self.on_report_bug_btn_click)

        self.progress_bar.setMaximum(0)
        self.progress_bar.setMinimum(0)
        self.progress_bar.hide()

        self.debug_mode_cb.hide()

    def get_my_name(self):
        return self.user.nickname or self.user.sid

    def load_account_list(self):
        self.accounts_basic_info_list = get_accounts_basic_info_list()

        for acc in self.accounts_basic_info_list:
            if acc["mobile_no"]:
                self.accountComboBox.addItem(acc["mobile_no"],
                                             QtCore.QVariant(acc["sid"]))
            else:
                self.accountComboBox.addItem(acc["sid"],
                                             QtCore.QVariant(acc["sid"]))

        self.connect(self.accountComboBox,
                     QtCore.SIGNAL('currentIndexChanged ( int )'),
                     self.on_account_combobox_index_changed)
        self.connect(self.accountComboBox,
                     QtCore.SIGNAL('editTextChanged ( const QString & )'),
                     self.on_account_combobox_text_changed)

        self.on_account_combobox_index_changed(
            self.accountComboBox.currentIndex())

        last_login_sid = get_last_login_sid()
        if last_login_sid:
            idx = self.accountComboBox.findData(
                QtCore.QVariant(last_login_sid))
            self.accountComboBox.setCurrentIndex(idx)

    def load_user_presence_list(self):
        for const, presence in UserPresence.__dict__[
                "CONST_TO_STR_ZH"].iteritems():
            self.presenceComboBox.addItem(presence, QtCore.QVariant(const))
            self.set_debault_presence()

    def set_debault_presence(self):
        idx = self.presenceComboBox.findData(
            QtCore.QVariant(UserPresence.ONLINE))
        self.presenceComboBox.setCurrentIndex(idx)

    def on_account_combobox_index_changed(self, idx):
        account_no = str(self.accountComboBox.itemText(idx))
        self._fill_correspond_by_account_no(account_no)

    def _fill_correspond_by_account_no(self, account_no):
        for acc_basic_info in self.accounts_basic_info_list:
            if account_no == acc_basic_info["mobile_no"] or \
                account_no == acc_basic_info["sid"]:
                if not acc_basic_info["hashed_passwd"]:
                    self.rememberPasswdCheckBox.setCheckState(
                        QtCore.Qt.Unchecked)
                    return

                passwd = acc_basic_info["hashed_passwd"]

                if passwd == "hash!":
                    passwd = ""
                self.passwdLineEdit.setText(passwd)
                self.rememberPasswdCheckBox.setCheckState(QtCore.Qt.Checked)

                presence = acc_basic_info["last_presence"]
                idx = self.presenceComboBox.findData(QtCore.QVariant(presence))
                self.presenceComboBox.setCurrentIndex(idx)
                return
            else:
                self.passwdLineEdit.setText("")
                self.rememberPasswdCheckBox.setCheckState(QtCore.Qt.Unchecked)
                self.set_debault_presence()

    def on_account_combobox_text_changed(self, account_no):
        self._fill_correspond_by_account_no(account_no)

    def on_report_bug_btn_click(self):
        popup_about(self)

    def download_sys_config_t_finished(self):
        kill_qthread(self.download_sys_config_t_killer)

        res_obj = self.download_sys_config_t.get_return()
        code = res_obj.code

        if code == httplib.OK:
            self.download_sys_config_t = None
            self.download_sys_config_t_killer = None
            self._retry_times = 0
            i_update_user_after_get_sys_config_success(self.user, res_obj.body)
            self.sipc_auth_t_run()
            return

        self.download_sys_config_t = None
        self.download_sys_config_t_killer = None
        self.show_or_hide_login_widgets(show=True)
        popup_error(self, "Download configuration response code: %d" % code)

    def kill_download_sys_config_t(self):
        kill_qthread(self.download_sys_config_t)

        if self._retry_times < MAX_RETRY_TIMES:
            self._retry_times += 1
            logger.error("Download configuration failed, auto re-try ...")
            self.download_sys_config_t_run()
            return

        self.verification = None
        self.user = None
        self.show_or_hide_login_widgets(show=True)

        popup_error(self, "Download configuration failed, try again later")

    def download_sys_config_t_run(self):
        kill_qthread(self.download_sys_config_t)
        kill_qthread(self.download_sys_config_t_killer)

        self.download_sys_config_t = IThread(i_download_sys_config,
                                             user=self.user,
                                             debug=True)
        self.download_sys_config_t_killer = IThreadKiller(
            self.download_sys_config_t, timeout=20)

        self.connect(self.download_sys_config_t,
                     QtCore.SIGNAL("thread_finished()"),
                     self.download_sys_config_t_finished)
        self.connect(self.download_sys_config_t_killer,
                     QtCore.SIGNAL("kill_qthread()"),
                     self.kill_download_sys_config_t)

        self.download_sys_config_t.start()
        self.download_sys_config_t_killer.start()

    def ssi_auth_t_finished(self):
        # why not necessary to call disconnect(SIGNAL) here
        # http://doc.qt.nokia.com/4.7/qobject.html#disconnect-3
        kill_qthread(self.ssi_auth_t_killer)

        res_obj = self.ssi_auth_t.get_return()
        code = res_obj.code

        if code == httplib.OK:
            i_update_user_after_ssi_auth_success(self.user, res_obj,
                                                 self.get_if_remember_passwd())

            self._retry_times = 0

            self.download_sys_config_t_run()

        elif code == HTTPResponse.PASSWD_ERROR:
            self.user = None
            self.show_or_hide_login_widgets(show=True)
            popup_error(self, u"密码错误")

        elif code in (HTTPResponse.CCPS_CHECK_ERROR, HTTPResponse.NEED_VERIFY):
            self.verification = i_generate_verification_pic(self.user, res_obj)
            body = "%s<br />%s" % (self.verification.text,
                                   self.verification.tips)
            (btn_val, chars) = GetVerificationDialog.get_input(
                body=body, path=self.verification.picture_path)

            if btn_val:
                logger.info("(SSI auth)Input recognise chars: %s" % chars)
                self.verification.chars = chars
                self.ssi_auth_t_run()
            else:
                self.verification = None
                self.user = None
                self.show_or_hide_login_widgets(show=True)
        else:
            raise Exception("SSI authentication response code: %d" % code)

    def show_contact_list_win(self):
        self.contact_list_win = ContactListWidow(self)
        self.hide()
        self.contact_list_win.move(800, 150)
        self.contact_list_win.show()

    def kill_ssi_auth_t(self):
        if self._retry_times < MAX_RETRY_TIMES:
            self._retry_times += 1
            logger.error("SSI authentication failed, auto re-try ...")
            self.ssi_auth_t_run()
            return

        self.verification = None
        self.user = None
        self.show_or_hide_login_widgets(show=True)

        popup_error(self, u"连接超时(SSI),请稍候再尝试")

    def sipc_auth_t_finished(self):
        kill_qthread(self.sipc_auth_t_killer)

        res_obj = self.sipc_auth_t.get_return()
        code = res_obj.code

        if code == SIPResponse.OK:
            self._retry_times = 0
            i_update_user_after_sipc_auth_success(self.user, res_obj)
            self.show_contact_list_win()
            return

        elif code == SIPResponse.EXTENSION_REQUIRED:  # login location changed
            self.verification = i_generate_verification_pic(self.user, res_obj)
            body = "%s<br />%s" % (self.verification.text,
                                   self.verification.tips)
            (btn_val, chars) = GetVerificationDialog.get_input(
                body=body, path=self.verification.picture_path)

            if btn_val:
                logger.info("(SIPC auth) Input recognise chars: %s" % chars)
                self.verification.chars = chars
                self.sipc_auth_t_run()
            else:
                self.verification = None
                self.user = None
                self.show_or_hide_login_widgets(show=True)

            return

        self.show_or_hide_login_widgets(show=True)
        popup_error(self, "SIPC authentication response code: %d" % code)

    def kill_sipc_auth_t(self):
        kill_qthread(self.sipc_auth_t)

        if self._retry_times < MAX_RETRY_TIMES:
            self._retry_times += 1
            logger.error("SIPC authentication failed, auto re-try ...")
            self.sipc_auth_t_run()
            return

        self.verification = None
        self.user = None
        self.show_or_hide_login_widgets(show=True)

        popup_error(self, u"连接超时(SIPC),请稍候再尝试")

    def on_login_btn_click(self):
        self._retry_times = 0
        account = self.get_account()
        passwd = self.get_passwd()

        #        self._debug_mode = self.debug_mode_cb.checkState() == QtCore.Qt.Checked

        if not len(account) or not len(passwd):
            popup_error(self, u"帐号和密码都不能为空!")
            return
        else:
            last_char = account[-1]
            if last_char < '0' or last_char > '9':
                popup_error(self, u"您输入的不是一个有效的飞信号或者移动手机号,飞信邮箱协议暂时不兼容本软件")
                return

        hashed_passwd = i_hash_passwd(passwd)
        presence = self.get_presence()
        self.user = i_create_user(account, hashed_passwd, presence)
        self.ssi_auth_t_run()
        self.show_or_hide_login_widgets(show=False)

    def ssi_auth_t_run(self):
        kill_qthread(self.ssi_auth_t)
        kill_qthread(self.ssi_auth_t_killer)

        self.ssi_auth_t = IThread(i_ssi_auth,
                                  user=self.user,
                                  verification=self.verification,
                                  debug=True)
        self.ssi_auth_t_killer = IThreadKiller(self.ssi_auth_t, timeout=10)

        self.connect(self.ssi_auth_t, QtCore.SIGNAL("thread_finished()"),
                     self.ssi_auth_t_finished)
        self.connect(self.ssi_auth_t_killer, QtCore.SIGNAL('kill_qthread()'),
                     self.kill_ssi_auth_t)

        self.ssi_auth_t.start()
        self.ssi_auth_t_killer.start()

    def sipc_auth_t_run(self):
        kill_qthread(self.sipc_auth_t)
        kill_qthread(self.sipc_auth_t_killer)

        self.sipc_auth_t = IThread(i_sipc_auth,
                                   user=self.user,
                                   verification=self.verification,
                                   debug=True)
        self.sipc_auth_t_killer = IThreadKiller(self.sipc_auth_t, timeout=10)

        self.connect(self.sipc_auth_t, QtCore.SIGNAL("thread_finished()"),
                     self.sipc_auth_t_finished)
        self.connect(self.sipc_auth_t_killer, QtCore.SIGNAL('kill_qthread()'),
                     self.kill_sipc_auth_t)

        self.sipc_auth_t.start()
        self.sipc_auth_t_killer.start()

    def get_passwd(self):
        passwd = self.passwdLineEdit.text()
        return str(passwd)

    def get_account(self):
        account = self.accountComboBox.currentText()
        return str(account)

    def get_presence(self):
        idx = self.presenceComboBox.currentIndex()
        presence_const = self.presenceComboBox.itemData(idx).toInt()[0]
        return presence_const

    def get_if_remember_passwd(self):
        if_remember_passwd = self.rememberPasswdCheckBox.checkState(
        ) == QtCore.Qt.Checked
        return if_remember_passwd

    def get_if_debug_mode(self):
        return self._debug_mode

    def thread_running(self):
        logger.info('thread running ... ')

    def show_or_hide_login_widgets(self, show=True):
        if show:
            self.accountLabel.show()
            self.accountComboBox.show()

            self.passwdLabel.show()
            self.passwdLineEdit.show()

            self.presenceComboBox.show()
            self.rememberPasswdCheckBox.show()

            self.loginBtn.show()
            #            self.debug_mode_cb.show()
            self.reportBugBtn.show()

            self.progress_bar.hide()
        else:
            self.accountLabel.hide()
            self.accountComboBox.hide()

            self.passwdLabel.hide()
            self.passwdLineEdit.hide()

            self.presenceComboBox.hide()
            self.rememberPasswdCheckBox.hide()

            self.loginBtn.hide()
            #            self.debug_mode_cb.hide()
            self.reportBugBtn.hide()

            self.progress_bar.show()
Beispiel #16
0
 def update_portraits_t_run(self):
     if self.update_all_portraits_t and not self.update_all_portraits_t.isFinished():
         return
     self.update_all_portraits_t = IThread(i_update_all_portraits, user = self.user)
     self.update_all_portraits_t.start()
Beispiel #17
0
class ContactListWidow(QtGui.QWidget, Ui_ContactListWindow):
    FIRST_COLUMN = 0

    def __init__(self, blah):
        QtGui.QWidget.__init__(self)
        self.setupUi(self)
        self.setWindowIcon(QtGui.QIcon(LOGO_PATH))

        self.chat_history = {}

        self.blah = blah
        self.user = blah.user
        self.chat_win = ChatWindow(blah)
        self.chat_win.move(200, 200)

        self.load_user_presence_list()

        self.update_all_portraits_t = None

        # listen the socket (main sock) used in SIPC auth
        self.listen_main_sock_t = None
        self.server_push_data_list = []
        self.connect(self, QtCore.SIGNAL("recved_server_push_datas()"),
                     self.consume_server_push_datas)

        self.conversation_server_push_data_list = []
        self.connect(self,
                     QtCore.SIGNAL("recved_conversation_server_push_datas()"),
                     self.consume_conversation_server_push_datas)

        self.setup_keep_alive_timer()
        self.setup_check_user_presence_timer()

        self._init_addition_widgets()

        i_subscribe_contact_list(self.user, debug=True)

        self.listen_main_sock_t_run()
        self.keep_alive_timer.start()

    def on_contact_list_double_clicked(self):
        contact = self.get_current_selected_contact()
        DOUBLE_CLICK_ON_CONTACT_ITEM = contact is not None
        if DOUBLE_CLICK_ON_CONTACT_ITEM:
            self.goto_or_create_tab_before_send_msg(contact)

    def _init_addition_widgets(self):
        self.nicknameLabel.setText(self.blah.get_my_name())
        self.set_user_presence()
        self._init_portrait_widget()

        self.contact_list_tree_model = ContactListTreeModel(
            self.user.group_agent)
        self.contact_list_tree_view.setModel(self.contact_list_tree_model)

        self.selection_model = self.contact_list_tree_view.selectionModel()

        self.contact_list_tree_view.mouseDoubleClickEvent = contact_list_double_click_wrapper(
            self.contact_list_tree_view.mousePressEvent,
            self.contact_list_tree_view)
        self.connect(self.contact_list_tree_view,
                     QtCore.SIGNAL('doubleClicked()'),
                     self.on_contact_list_double_clicked)

        self.contact_list_tree_view.mouseReleaseEvent = contact_list_view_left_click_wrapper(
            self.contact_list_tree_view.mouseReleaseEvent,
            self.contact_list_tree_view)
        self.connect(self.contact_list_tree_view,
                     QtCore.SIGNAL("leftClicked()"),
                     self.on_contact_group_left_clicked)

        #        self.connect(self.contact_list_tree_model,
        #            QtCore.SIGNAL('update_contact_order()'),
        #            self.update_contact_order_after_presence_changed)

        self.update_portraits_t_run()

        self.reportBugBtn.clicked.connect(self.on_report_bug_btn_click)
        self.add_buddy_btn.clicked.connect(self.on_add_buddy_btn_click)

#    def update_contact_order_after_presence_changed(self):
#        logger.info('data_change')

    def on_contact_group_left_clicked(self):
        idx = self.selection_model.currentIndex()
        obj = idx.internalPointer()
        if obj and obj.get_type() == GroupAgentItemType.GROUP:
            if self.contact_list_tree_view.isExpanded(idx):
                self.contact_list_tree_view.collapse(idx)
            else:
                self.contact_list_tree_view.expand(idx)

    def update_portraits_t_run(self):
        if self.update_all_portraits_t and not self.update_all_portraits_t.isFinished(
        ):
            return
        self.update_all_portraits_t = IThread(i_update_all_portraits,
                                              user=self.user)
        self.update_all_portraits_t.start()

    def get_current_selected_contact(self):
        idx = self.selection_model.currentIndex()
        obj = idx.internalPointer()
        if obj and obj.get_type() == GroupAgentItemType.CONTACT:
            return obj

    def on_avatar_left_clicked(self):
        read_only = True
        user = self.blah.user
        is_save_btn_clicked, new_user = ProfileDialog.get_data(
            self, user, read_only)
        assert new_user != None

    def _init_portrait_widget(self):
        self.set_portrait()
        self.portraitLabel.mousePressEvent = portrait_left_click_wrapper(
            self.portraitLabel.mousePressEvent, self.portraitLabel)
        self.connect(self.portraitLabel, QtCore.SIGNAL('leftClicked()'),
                     self.on_avatar_left_clicked)

        self.set_portrait()

    def set_portrait(self, path=None):
        if not path:
            path = self.user.get_portrait_path() or DEFAULT_PORTRAIT_PATH
        elif path and not os.path.exists(path):
            self.download_portrait_t = IThread(i_download_portrait_by_uri,
                                               user=self.user,
                                               uri=self.user.uri,
                                               debug=True)
            self.connect(self.download_portrait_t,
                         QtCore.SIGNAL("thread_finished()"),
                         self.download_portrait_t_finished)
            self.download_portrait_t.start()
        pixmap = QtGui.QPixmap(path)
        width, height = 60, 60
        pixmap = pixmap.scaled(QtCore.QSize(width, height))
        self.portraitLabel.setPixmap(pixmap)

    def download_portrait_t_finished(self):
        res_obj = self.download_portrait_t.get_return()
        assert res_obj != None

    def on_add_buddy_btn_click(self):
        myname = ""  # self.user.nickname[:10]
        send_btn_clicked, data = AddBuddyDialog.get_data(parent=self,
                                                         name=myname)
        if send_btn_clicked:
            i_add_buddy(self.user, data["account"], data["name"], debug=True)

    def on_report_bug_btn_click(self):
        popup_about(self)

    def switch_presence_to_online(self):
        pass

    def switch_presence_to_away(self):
        pass

    def switch_presence_to_invisible(self):
        pass

    def switch_presence_to_offline(self):
        logger.error("in switch_presence_to_offline()")
        # there are bug in timer ?
        # QObject::startTimer: QTimer can only be used with threads started with QThread
        self.check_user_presence_timer.stop()
        self.keep_alive_timer.stop()

        convs = self.user.get_conversations()
        uri_list = convs.keys()
        for uri in uri_list:
            conv = convs[uri]
            conv.over()
            convs.pop(uri)

        sock = self.user.get_sock()
        sock.close()

        while not self.listen_main_sock_t.isFinished():
            time.sleep(0.1)

        while not self.update_all_portraits_t.isFinished():
            time.sleep(0.1)

        self.hide()
        self.blah.show()
        self.blah.show_or_hide_login_widgets(show=True)

    def load_user_presence_list(self):
        for const, presence in UserPresence.__dict__[
                "CONST_TO_STR_ZH"].iteritems():
            self.presenceComboBox.addItem(presence, QtCore.QVariant(const))

        self.connect(self.presenceComboBox,
                     QtCore.SIGNAL('currentIndexChanged ( int )'),
                     self.on_presence_changed)

    def on_presence_changed(self, idx):
        presence_const = self.presenceComboBox.itemData(idx).toInt()[0]
        i_set_presence(self.user, presence_const)

        self.set_presence_icon(presence_const)

    def set_presence_icon(self, presence_const):
        #icon_path = os.path.join(ICON_PATH, "status-%s.png" % str(UserPresence(presence_const)))
        icon_path = ":/status-%s.png" % str(UserPresence(presence_const))
        self.presenceLabel.setPixmap(QtGui.QPixmap(icon_path))

    def set_user_presence(self):
        idx = self.presenceComboBox.findData(
            QtCore.QVariant(self.user.get_presence()))
        self.presenceComboBox.setCurrentIndex(idx)

        self.set_presence_icon(self.user.get_presence())

    def check_user_presence(self):
        if self.user.get_presence() == UserPresence.OFFLINE:
            logger.error('user.get_presence() == UserPresence.OFFLINE is True')
            self.switch_presence_to_offline()

    def consume_server_push_datas(self):
        while len(self.server_push_data_list):
            res_obj, sock = self.server_push_data_list.pop()
            self._consume_datas(res_obj, sock)

    def consume_conversation_server_push_datas(self):
        while len(self.conversation_server_push_data_list):
            res_obj, sock = self.conversation_server_push_data_list.pop()
            self._consume_datas(res_obj, sock)

    def _consume_notification(self, res_obj, sock):
        assert (sock is not None)
        sip_event_str = res_obj.headers.get_field_value("N")
        sip_event = SIPEvent.get_const_by_str(SIPEvent, sip_event_str)
        events = get_conversation_events(res_obj)

        body_dom = minidom.parseString(res_obj.body)
        CONTACT_PRESENCE_CHANGED = sip_event == SIPEvent.PRESENCE_V4 and \
                                   NotificationEvent.PRESENCE_CHANGED in events

        CONTACT_LEFT = sip_event == SIPEvent.CONVERSATION and \
                       NotificationEvent.USER_LEFT in events

        SYNC_USER_INFO_V4 = sip_event == SIPEvent.SYNC_USER_INFO_V4 and \
                        NotificationEvent.SYNC_USER_INFO in events

        BEEN_DISCONNECTED = sip_event == SIPEvent.REGISTRATION and \
                                NotificationEvent.DEREGISTRATION in events

        ADD_BUDDY_REFUSED = sip_event == SIPEvent.SYSTEM_NOTIFY_V4 and \
                            NotificationEvent.ADD_BUDDY_REFUSED in events

        USER_DYNAMICS_CHANGED = sip_event == SIPEvent.SYSTEM_NOTIFY_V4 and \
                                NotificationEvent.USER_DYNAMICS_CHANGED

        ADD_BUDDY_APPLICATION = sip_event == SIPEvent.CONTACT and \
                                NotificationEvent.ADD_BUDDY_APPLICATION in events

        convs = self.user.get_conversations()
        if CONTACT_PRESENCE_CHANGED:
            offline_uri_list = update_contacts_presence_from_response(
                self.user, body_dom)
            for uri in offline_uri_list:
                if uri in convs:
                    conv = convs[uri]
                    assert conv.sock != self.user.get_sock()
                    conv.over()
                    #convs.pop(uri)
            self.update_portraits_t_run()

            self.emit(
                QtCore.SIGNAL(
                    'dataChanged ( const QModelIndex & , const QModelIndex &  )'
                ))

        elif CONTACT_LEFT:
            member_nodes = body_dom.getElementsByTagName("member")
            for member_node in member_nodes:
                uri = member_node.getAttribute("uri")
                conv = convs[uri]
                assert conv.sock != self.user.get_sock()
                conv.over()
                #convs.pop(uri)

        elif SYNC_USER_INFO_V4:
            self._consume_noti_sync_user_info_v4(res_obj)

        elif BEEN_DISCONNECTED:
            OFFLINE_ALERTS = "You have been disconnected" \
                "as someone has signed in with your ID on another computer." \
                "<br /><br />" \
                "Please note that if this was not intentional, some may have stolen your passwrod. "\
                "Please change your password."
            popup_error(self, OFFLINE_ALERTS)
            self.switch_presence_to_offline()
            #"Sign in again", "OK"

        elif ADD_BUDDY_REFUSED:
            uri, reason = i_parse_add_buddy_refused(body_dom)
            assert uri != reason
            logger.error(
                "User (URI: %s) refused your add buddy application, reason: %s"
                % (uri, reason))

        elif ADD_BUDDY_APPLICATION:
            self._consume_add_buddy_application(res_obj)

        elif USER_DYNAMICS_CHANGED:
            pass

    def update_portraits(self):
        for contact in self.user.group_agent.get_all_contacts():
            if contact.image_changed == YES:
                i_download_portrait_by_uri(self.user, contact.uri)
                contact.image_changed = NO

    def _consume_add_buddy_application(self, res_obj):
        body_dom = minidom.parseString(res_obj.body)
        app_data = i_parse_add_buddy_application(body_dom)

        sid = get_sid_from_uri(app_data["uri"])
        SHOW_MSG_TPL = u"我是 %s (飞信号: %s ),想添加您为好友"
        show_msg = SHOW_MSG_TPL % (app_data["who"], sid)

        send_btn_clicked, data = ReplyAddBuddyDialog.get_data(
            parent=self, show_msg=show_msg)

        if send_btn_clicked:
            if data["accept"]:
                result = ReplyAddBuddyApplication.ACCEPT
            else:
                result = ReplyAddBuddyApplication.REFUSE
        else:
            result = ReplyAddBuddyApplication.IGNORE

        i_reply_add_buddy(self.user,
                          res_obj,
                          result,
                          data["refuse_reason"],
                          data["decline_add_req_forever"],
                          debug=True)

    def _consume_noti_sync_user_info_v4(self, res_obj):
        body_dom = minidom.parseString(res_obj.body)

        contact_list_nodes = body_dom.getElementsByTagName("contact-list")
        if not contact_list_nodes:
            return
        assert len(contact_list_nodes) == 1
        contact_list_node = contact_list_nodes[0]
        contact_list_version = contact_list_node.getAttribute("version")
        if self.user.contact_list_version != contact_list_version:
            self.user.contact_list_version = contact_list_version

        buddy_nodes = body_dom.getElementsByTagName("buddy")
        for buddy_node in buddy_nodes:
            attr = buddy_node.getAttribute
            user_id = attr("user-id")
            contact = self.user.group_agent.get_contact_by_user_id(user_id)

            # someone send add buddy application to you,
            # and you send buddy application before any reply,
            # contact will be not found in self.user.contact_list.
            if not contact:
                continue

            if attr("action") == "remove":
                logger.error("!!! Your buddy (uri: %s) %s you" %
                             (contact.uri, attr("action")))

                convs = self.user.conversations()
                conv = convs.get(contact.uri, None)
                if conv:
                    assert conv.sock != self.user.get_sock()
                    conv.over()
                    del conv
                self.user.group_agent.remove_user_by_user_id(user_id)

            elif attr("action") == "add":
                logger.info("!!! Your buddy (uri: %s) %s you" %
                            (contact.uri, attr("action")))

                cat = Contact(user=self.blah.user)
                map_node_attr_to_obj(buddy_node, cat)
                self.user.contact_list.append(cat)
                cat.buddy_lists = attr("buddy-lists")
                cat.online_notify = attr("online-notify")
                cat.permission_values = attr("permission-values")

    def _consume_invitation(self, res_obj, sock):
        assert (sock is not None)
        """ TODO: ignore invitation will prevent from hide detecting. """
        i_send_ack(res_obj, sock)

        attr = res_obj.headers.get_field_value
        from_uri = attr("F")

        conv = Conversation(from_uri)
        convs = self.user.get_conversations()
        convs[from_uri] = conv
        get_sock_for_recv_msg_thread = IThread(get_sock_for_recv_msg,
                                               user=self.user,
                                               res_obj=res_obj,
                                               debug=True)
        conv.get_sock_for_recv_msg_thread = get_sock_for_recv_msg_thread
        self.connect(conv.get_sock_for_recv_msg_thread,
                     QtCore.SIGNAL("thread_finished()"),
                     self.recv_msg_t_finished)
        conv.get_sock_for_recv_msg_thread.start()

    def recv_msg_t_finished(self):
        convs_d = dict()
        convs = self.user.get_conversations()
        for to_uri, conv in convs.iteritems():
            if conv.get_sock_for_recv_msg_thread and conv.get_sock_for_recv_msg_thread.isFinished(
            ):
                res_obj = conv.get_sock_for_recv_msg_thread.get_return()
                conv.get_sock_for_recv_msg_thread = None

                if res_obj.code == SIPResponse.OK:
                    assert conv.sock != self.user.get_sock()
                    assert conv.listen_thread == None
                    self.add_listener_for_conversation_sock(conv)
                    convs_d[to_uri] = conv
            else:
                convs_d[to_uri] = conv

        self.user.set_conversations(convs_d)

    def add_listener_for_conversation_sock(self, conv):
        assert conv.sock != self.user.get_sock()
        conv.listen_thread = IThread(
            self.listen_sock,
            sock=conv.sock,
            data_list=self.conversation_server_push_data_list,
            signal='recved_conversation_server_push_datas()',
            debug=True)
        conv.listen_thread.start()

        conv.keep_conn_busy_thread = PeriodicExecutor(30,
                                                      i_keep_connection_busy,
                                                      user=self.user,
                                                      sock=conv.sock)
        conv.keep_conn_busy_thread.start()

    def _consume_message(self, res_obj, sock):
        assert (sock is not None)

        attr = res_obj.headers.get_field_value
        from_uri = attr("F")

        logger.info("Get message from: %s" % from_uri)

        msg = rm_markups(to_unicode_obj(res_obj.body))

        if from_uri != SERVICE_PROVIDER_URI:
            i_send_ack(res_obj, sock)
            contact = self.user.group_agent.get_contact_by_uri(from_uri)
            if not contact:
                """ This message send you before him delete you from his buddy list. """
                name = u"陌生人 (飞信号: %s) " % get_sid_from_uri(from_uri)
            else:
                name = contact.get_display_name()
        else:
            name = to_unicode_obj("系统信息")

        self.goto_or_create_tab_after_received_msg(from_uri)

        chat_history_model = self.chat_history[from_uri]
        self.chat_win.append_to_chat_history(chat_history_model, name, msg,
                                             OTHER_LOG_TPL)

    def goto_or_create_tab_after_received_msg(self, from_uri):
        IS_SYSTEM_MSG = from_uri.find('sip:') == STR_NOT_FOUND

        if not IS_SYSTEM_MSG:
            TAB_ALREADY_EXISTS = self.chat_win.go_to_tab_by_uri(from_uri)
            if not TAB_ALREADY_EXISTS:
                self.chat_win.create_tab(from_uri)

    def _consume_datas(self, res_obj, sock):
        sip_type = res_obj.get_sip_method()

        if sip_type == SIP.NOTIFICATION:
            self._consume_notification(res_obj, sock)
        elif sip_type == SIP.SIPC_4_0:
            i_process_sipc_request_response(self.user, res_obj)
        elif sip_type == SIP.INVITATION:
            self._consume_invitation(res_obj, sock)
        elif sip_type == SIP.MESSAGE:
            self._consume_message(res_obj, sock)

#        elif sip_type == SIP.INCOMING:
#            process_incoming(user, res_obj)

    def send_keep_connection_busy(self, sock, debug=False):
        i_keep_connection_busy(self.user, sock, debug)
#        try:
#            i_keep_connection_busy(self.user, sock, debug)
#        except socket.error as (err_no, err_msg):
#            assert err_msg != None
#            # `socket.error: [Errno 22] Invalid argument` exception means disconnect
#            if err_no == errno.EINVAL:
#                self.user.get_presence() = OFFLINE
#                time.sleep(1)

    def send_keep_alive(self, debug=False):
        i_send_keep_alive(self.user, debug)


#        try:
#            i_send_keep_alive(self.user, debug)
#        except socket.error as (err_no, err_msg):
#            assert err_msg != None
#            # `socket.error: [Errno 22] Invalid argument` exception means disconnect
#            if err_no == errno.EINVAL:
#                self.user.get_presence() = OFFLINE
#                time.sleep(1)

    def setup_keep_alive_timer(self):
        self.keep_alive_timer = QtCore.QTimer()
        self.connect(self.keep_alive_timer, QtCore.SIGNAL('timeout()'),
                     self.send_keep_alive)
        msec = 1000 * 70
        self.keep_alive_timer.setInterval(msec)

    def setup_check_user_presence_timer(self):
        print " in setup_check_user_presence_timer() "
        self.check_user_presence_timer = QtCore.QTimer()
        self.connect(self.check_user_presence_timer,
                     QtCore.SIGNAL('timeout()'), self.check_user_presence)
        msec = 1000 * 5
        self.check_user_presence_timer.setInterval(msec)

    def listen_main_sock_t_run(self):
        """ TODO: offline-handler
        socket.error: [Errno 32] Broken pipe
        """
        # listen the socket (main sock) used in SIPC auth
        self.listen_main_sock_t = IThread(self.listen_sock,
                                          sock=self.user.get_sock(),
                                          data_list=self.server_push_data_list,
                                          signal='recved_server_push_datas()',
                                          debug=True)
        self.listen_main_sock_t.start()

        # self.connect(self.listen_main_sock_t, QtCore.SIGNAL('thread_finished()'), self.switch_presence_to_offline)

    def listen_sock(self, sock, data_list, signal, debug=False):
        IS_MAIN_SOCK = sock is self.user.get_sock()
        if IS_MAIN_SOCK:
            is_main_sock = 'yes'
        else:
            is_main_sock = 'no'
        recv_buf = ""

        while True:
            try:
                readys = select.select([sock], [], [sock])
            except select.error as (err_no, err_msg):
                # sock passive close but listen thread still running
                logger.error("!!! %s while select, is main sock: %s" %
                             (err_msg, is_main_sock))
                SOCK_CLOSED_T_RUNNING = (not IS_MAIN_SOCK) and (err_no
                                                                == errno.EBADF)
                if SOCK_CLOSED_T_RUNNING:
                    return SOCK_CLOSED_T_RUNNING
            except socket.error as (err_no, err_msg):
                logger.error("!!! %s while select, is main sock: %s" %
                             (err_msg, is_main_sock))
                DEREGISTERED = IS_MAIN_SOCK and (err_no == errno.EBADF)
                return DEREGISTERED

            input_ready = readys[0]
            except_ready = readys[2]

            if except_ready:
                logger.error("!!! Get exception while read socket")
                raise Exception("get exception while read socket")

            if input_ready:
                buf = ""
                try:
                    """ NOTICE: don't set size_once less than 1024, or you will get errno.EAGAIN and
                      this sock will couldn't read data again. """
                    buf = SIPConnection.recv(sock,
                                             size_once=1024,
                                             flags=socket.MSG_DONTWAIT,
                                             debug=debug)
                except socket.error as (err_no, err_msg):
                    if err_no == errno.EAGAIN:
                        logger.error(
                            "!!! %s while sock.recv, is main sock: %s" %
                            (err_msg, is_main_sock))

                        res = is_a_complete_response(recv_buf)
                        CONTINUE_RECV = len(
                            recv_buf
                        ) != 0 and res == SIPResponseValidity.NOT_COMPLETE
                        if CONTINUE_RECV:
                            print "CONTINUE_RECV:", CONTINUE_RECV
                            continue

                recv_buf += buf
                """Contact left conversation with a `UserLeft` push msg will be active close sock(i),
                this sock will receives nothing after `UserLeft`, so length of buf will be zero.

                This sock will be active close if get deregistered event type of registration notification,
                so length of buf will be zero too.
                """
                if len(recv_buf) == 0:
                    if not IS_MAIN_SOCK:
                        logger.error(
                            "!!! len(recv_buf) == 0, is main sock: %s",
                            is_main_sock)
                        return
                else:
                    pkgs, remain = split_package(recv_buf)

                    while len(pkgs):
                        res_obj = pkgs.pop(0)
                        data_list.append((res_obj, sock))
                        self.emit(QtCore.SIGNAL(signal))
                    recv_buf = remain