Ejemplo n.º 1
0
    def onTermCommand(bot, command):
        command = BYTES2STR(command)
        if command.startswith('GET /'):
            http = True
            end = command.find('\r\n')
            if end == -1 or not command[:end - 3].endswith(' HTTP/'):
                argv = []
            else:
                url = command[5:end - 9].rstrip('/')
                if url == 'favicon.ico':
                    return b''
                argv = [Unquote(x) for x in url.split('/')]
        else:
            http = False
            argv = command.strip().split(None, 3)

        if argv and argv[0] in cmdFuncs:
            try:
                result, err = cmdFuncs[argv[0]](bot, argv[1:], http)
            except Exception as e:
                result, err = None, '运行命令过程中出错:' + str(type(e)) + str(e)
                ERROR(err, exc_info=True)
        else:
            result, err = None, 'QQBot 命令格式错误'

        if http:
            rep = {'result': result, 'err': err}
            rep = STR2BYTES(JsonDumps(rep, ensure_ascii=False, indent=4))
            rep = (b'HTTP/1.1 200 OK\r\n' + b'Connection: close\r\n' +
                   b'Content-Length: ' + STR2BYTES(str(len(rep))) + b'\r\n' +
                   b'Content-Type: text/plain;charset=utf-8\r\n\r\n' + rep)
        else:
            rep = STR2BYTES(str(err or result)) + b'\r\n'

        return rep
Ejemplo n.º 2
0
 def Reply(self, rep):
     rep = STR2BYTES(str(rep) + '\r\n')
     try:
         self.sock.sendall(rep)
     except socket.error:
         WARN('回复 %s 失败', self.name)
     finally:
         self.sock.close()
Ejemplo n.º 3
0
    def readConfFile(self):
        conf = ast.literal_eval(sampleConfStr)['默认配置']

        confPath = self.ConfPath()

        if os.path.exists(confPath):
            try:
                with open(confPath, 'rb') as f:
                    cusConf = ast.literal_eval(BYTES2STR(f.read()))

                if type(cusConf) is not dict:
                    raise ConfError('文件内容必须是一个dict')

                elif self.user is None:
                    pass

                elif self.user not in cusConf:
                    raise ConfError('用户 %s 不存在' % self.user)

                elif type(cusConf[self.user]) is not dict:
                    raise ConfError('用户 %s 的配置必须是一个 dict' % self.user)

                else:
                    for k, v in list(cusConf[self.user].items()):
                        if k not in conf:
                            raise ConfError('不存在的配置选项 %s.%s ' % (self.user, k))

                        elif type(v) is not type(conf[k]):
                            raise ConfError(
                                '%s.%s 必须是一个 %s' %
                                (self.user, k, type(conf[k]).__name__))

                        else:
                            conf[k] = v

            except (IOError, SyntaxError, ValueError, ConfError) as e:
                PRINT('配置文件 %s 错误: %s\n' % (confPath, e), end='')
                sys.exit(1)

        else:
            try:
                with open(confPath, 'wb') as f:
                    f.write(STR2BYTES(sampleConfStr))
            except IOError:
                pass

            if self.user is not None:
                PRINT('用户 %s 不存在\n' % self.user, end='')
                sys.exit(1)

        for k, v in list(conf.items()):
            if getattr(self, k, None) is None:
                setattr(self, k, v)

        if self.mailAccount and not self.mailAuthCode:
            msg = '请输入 %s 的 IMAP/SMTP 服务授权码: ' % self.mailAccount
            self.mailAuthCode = RAWINPUT(msg)
Ejemplo n.º 4
0
 def send(self, prefix, command, params, tail):
     words = [':' + prefix, command.upper()] + params + [':' + tail]
     msg = ' '.join(words)
     try:
         self.sock.sendall(STR2BYTES(msg) + b'\r\n')
     except socket.timeout:
         ERROR('在向 %s 发送数据时出现 %s', self.name, 'SOCKET-TIMEOUT')
     except socket.error:
         ERROR('在向 %s 发送数据时出现 %s', self.name, 'SOCKET-ERROR')
         self.close()
     else:
         DEBUG('%s ==> %s: %r', self.servername, self.name, msg)
Ejemplo n.º 5
0
    def onData(self, sock, addr, data):
        try:
            resp = self.response(data)
        except Exception as e:
            resp = '%s 在处理 %s:%s 的请求时发生错误,%s' % (self.name, addr[0], addr[1], e)
            ERROR(resp, exc_info = True)
            resp = STR2BYTES(resp)

        try:
            sock.sendall(resp)
        except socket.error as e:
            ERROR('%s 在向 %s:%s 发送数据时发送错误,%s', self.name, addr[0], addr[1], e)
            self.onSendError(sock, addr, data)
        finally:
            sock.close()
Ejemplo n.º 6
0
    def response(self, request):
        request = BYTES2STR(request)
        url = None
        if request.startswith('GET /'):
            end = request.find('\r\n')
            if end != -1 and request[:end - 3].endswith(' HTTP/'):
                url = request[5:end - 9].rstrip('/')

        resp = b''
        if (url is not None) and (url != 'favicon.ico'):
            try:
                with open(self.qrcodePath, 'rb') as f:
                    png = f.read()
            except Exception as e:
                ERROR('读取二维码文件 %s 出错:%s', SYSTEMSTR2STR(self.qrcodePath), e)
            else:
                resp = (b'HTTP/1.1 200 OK\r\n' + b'Connection: close\r\n' +
                        b'Content-Length: ' + STR2BYTES(str(len(png))) +
                        b'\r\n' + b'Content-Type: image/png\r\n\r\n' + png)

        return resp
Ejemplo n.º 7
0
    def readConfFile(self):
        confPath = self.ConfPath()
        strConfPath = SYSTEMSTR2STR(confPath)
        conf = rootConf.copy()

        if os.path.exists(confPath):
            try:
                with open(confPath, 'rb') as f:
                    cusConf = ast.literal_eval(BYTES2STR(f.read()))

                if type(cusConf) is not dict:
                    raise ConfError('文件内容必须是一个 dict')

                if type(cusConf.get('默认配置', {})) is not dict:
                    raise ConfError('默认配置必须是一个 dict')

                if self.user is not None:
                    if self.user not in cusConf:
                        raise ConfError('用户 %s 不存在' % self.user)
                    elif type(cusConf[self.user]) is not dict:
                        raise ConfError('用户 %s 的配置必须是一个 dict' % self.user)
                    else:
                        names = ['默认配置', self.user]
                else:
                    names = ['默认配置']

                for name in names:
                    for k, v in list(cusConf.get(name, {}).items()):
                        if k in deprecatedConfKeys:
                            PRINT('被废弃的配置选项 %s ,将忽略此选项' % k)
                        elif k not in conf:
                            raise ConfError('不存在的配置选项 %s.%s ' % (name, k))
                        elif type(v) is not type(conf[k]):
                            t = type(conf[k]).__name__
                            raise ConfError('%s.%s 必须是一个 %s' % (name, k, t))
                        else:
                            conf[k] = v

            except (IOError, SyntaxError, ValueError, ConfError) as e:
                PRINT('配置文件 %s 错误: %s\n' % (strConfPath, e), end='')
                sys.exit(1)

        else:
            PRINT('未找到配置文件“%s”,将使用默认配置' % strConfPath)
            try:
                with open(confPath, 'wb') as f:
                    f.write(STR2BYTES(sampleConfStr))
            except IOError:
                pass
            else:
                PRINT('已创建一个默认配置文件“%s”' % strConfPath)

            if self.user is not None:
                PRINT('用户 %s 不存在\n' % self.user, end='')
                sys.exit(1)

        for k, v in list(conf.items()):
            if getattr(self, k, None) is None:
                setattr(self, k, v)

        if self.pluginPath and not os.path.isdir(STR2SYSTEMSTR(
                self.pluginPath)):
            PRINT('配置文件 %s 错误: 插件目录 “%s” 不存在\n' % \
                  (strConfPath, self.pluginPath), end='')
            sys.exit(1)

        if self.mailAccount and not self.mailAuthCode:
            msg = '请输入 %s 的 IMAP/SMTP 服务授权码: ' % self.mailAccount
            self.mailAuthCode = RAWINPUT(msg)

        if self.cmdQrcode:
            try:
                import PIL
                import wcwidth
            except ImportError:
                PRINT('您已选择以文本模式显示二维码,请先安装 pillow, wcwidth 库')
                sys.exit(1)
Ejemplo n.º 8
0
def fetchGroupMemberTable(self, group):
    
    result = self.smartRequest(
        url = ('http://s.web2.qq.com/api/get_group_info_ext2?gcode=%s'
               '&vfwebqq=%s&t={rand}') % (group.gcode, self.vfwebqq),
        Referer = ('http://s.web2.qq.com/proxy.html?v=20130916001'
                   '&callback=1&id=1'),
        expectedKey = 'minfo',
        repeatOnDeny = 5
    )

    cardDict = collections.defaultdict(list)
    nickDict = collections.defaultdict(list)
    _qqDict = {}
    if group.qq != '#NULL':
        r = self.smartRequest(
            url='http://qinfo.clt.qq.com/cgi-bin/qun_info/get_group_members_new',
            Referer='http://qinfo.clt.qq.com/member.html',
            data={'gc': group.qq, 'u': self.uin , 'bkn': self.bkn}
        )        
        
        for m in r['mems']:
            qq = str(m['u'])
            nick = HTMLUnescape(m['n'])
            card = HTMLUnescape(r.get('cards', {}).get(qq, ''))
            mark = HTMLUnescape(r.get('remarks', {}).get(qq, ''))            
            name = card or nick
            
            join_time = r.get('join', {}).get(qq, 0)
            last_speak_time = r.get('times', {}).get(qq, 0)
            is_buddy = m['u'] in r.get('friends', [])
    
            if r['owner'] == m['u'] :
                role, role_id = '群主', 0
            elif m['u'] in r.get('adm', []):
                role, role_id = '管理员', 1
            else:
                role, role_id = '普通成员', 2
    
            level = r.get('lv', {}).get(qq, {}).get('l', 0)
            levelname = HTMLUnescape(r.get('levelname', {}).get('lvln' + str(level), ''))
            point = r.get('lv', {}).get(qq, {}).get('p', 0)
            
            memb = [qq, None, nick, mark, card, name, join_time, last_speak_time,
                    role, role_id, is_buddy, level, levelname, point]
            
            if card:
                cardDict[STR2BYTES(card)[:18]].append(memb)
    
            nickDict[nick].append(memb)
            _qqDict[qq] = memb
    
    membss, unresolved = [], []
    ucDict = dict((str(it['muin']), it['card']) for it in result.get('cards', {}))
    for m, inf in zip(result['ginfo']['members'], result['minfo']):
        uin, nick = str(m['muin']), str(inf['nick'])
        card = ucDict.get(uin, '')        
        if not PY3:
            card = card.replace('\xc2\xa0', ' ')
            nick = nick.replace('\xc2\xa0', ' ')
        else:
            card = card.replace('\xa0', ' ')
            nick = nick.replace('\xa0', ' ')
        name = card or nick
        
        membs = nickDict.get(nick, [])
        if len(membs) == 1:
            memb = membs[0]
        else:
            membs = cardDict.get(STR2BYTES(card)[:18], [])
            if len(membs) == 1:
                memb = membs[0]
            else:
                memb = None
        
        if memb is None:
            unresolved.append('成员“%s”(uin=%s)' % (name, uin))
            memb = ['#NULL', uin, nick, mark, card, name, -1, -1,
                    '#NULL', -1, -1, -1, '#NULL', -1]
        else:
            memb[1] = uin
            _qqDict.pop(memb[0], None)
        
        membss.append(memb)

    if unresolved:
        unresolved.sort()
        WARN('因存在重名或名称中含特殊字符,无法绑定 %s 中以下'
             '成员的真实QQ号:\n\t%s', group, '\n\t'.join(unresolved))
    
    for memb in _qqDict.values():
        memb[1] = '-' + memb[0]
        membss.append(memb)        
    
    return membss