示例#1
0
def get_sock_for_send_msg(user, to_uri, debug = False):
    """ Parse (ip, port) get by start_chat request,
        create a new socket object to register and invite buddy to start a online conversation. """

    conversations = user.get_conversations()
    conv = conversations[to_uri]
    while not conv.start_chat_response:
        time.sleep(0.1)
    res_obj = conv.start_chat_response

    auth_val = res_obj.headers.get_field_value("A")
    ip, port, credential = _get_ip_port_credential_from_auth_field(auth_val)

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    conv.sock = sock
    sock.connect((ip, port))

    call_id = conv.call_id
    sip_type = SIP(SIP.REGISTER)
    sid = user.sid

    headers = {
        "F" : sid,
        "I" : call_id,
        "Q" : "%d %s" % (DEFAULT_SIP_SEQUENCE, str(sip_type)),

        "K" : ["text/html-fragment", "multiparty", "nudge"],
        "A" : 'TICKS auth="%s"' % credential,
    }

    conn = SIPConnection(sock, sip_type = sip_type, headers = headers)
    conn.send(debug = debug)

    # invite_buddy_to_start_chat(user, call_id, to_uri, debug)
    sip_type = SIP(SIP.SERVICE)
    sip_event = SIPEvent(SIPEvent.INVITE_BUDDY)

    headers = {
        "F" : sid,
        "I" : call_id,
        "Q" : "%d %s" % (DEFAULT_SIP_SEQUENCE, str(sip_type)),
        "N" : str(sip_event),
    }

    body = '<args><contacts><contact uri="%s" /></contacts></args>' % to_uri

    conn = SIPConnection(sock, sip_type = sip_type, headers = headers, body = body)
    res_obj = conn.send(debug = debug)

    if res_obj.code != SIPResponse.OK:
        sock.close()
        logger.error("get sock for cat failed")
        return None

    # recevie option response, we can do detect user if is offline or hide from response
    buf = SIPConnection.recv(sock, debug = debug)
    res_obj = SIPResponse(buf)
    
    logger.info("user is offline: %s" % str(detect_user_if_is_offline_from_invite_response(res_obj)))
    if detect_user_if_is_offline_from_invite_response(res_obj):
        sock.close()
        return None

    assert res_obj != None

    # recevie conversation response
    buf = SIPConnection.recv(sock, debug = debug)
    res_obj = SIPResponse(buf)
    assert res_obj != None

    return res_obj
示例#2
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