def Run(self, onCommand=None): try: self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.sock.bind((HOST, self.port)) self.sock.listen(5) except socket.error as e: WARN('无法开启 QQBot term 服务器。%s', e) WARN(' qq 命令无法使用') else: time.sleep(0.1) INFO('已在 %s 端口开启 QQBot-Term 服务器,', self.port) INFO('QQBot 已启动,请在其他控制台窗口使用 qq 命令来控制 QQBot ,' '示例: qq send buddy jack hello') while True: try: sock, addr = self.sock.accept() except socket.error: WARN('QQBot-Term 服务器出现 accept 错误') else: name = 'QTerm客户端"%s:%s"' % addr sock.settimeout(5.0) try: data = sock.recv(8192) except socket.error: sock.close() else: command = BYTES2STR(data) # INFO('QTerm 命令:%s', repr(command)) Put(onCommand, Client(name, sock), command)
def QTerm(): try: # python qterm.py -s # python qterm.py [PORT] [COMMAND] if len(sys.argv) == 2 and sys.argv[1] == '-s': QTermServer(DEFPORT).Test() else: if len(sys.argv) >= 2 and sys.argv[1].isdigit(): port = int(sys.argv[1]) command = ' '.join(sys.argv[2:]).strip() else: port = DEFPORT command = ' '.join(sys.argv[1:]).strip() if command: if not PY3: command = command.decode(sys.getfilesystemencoding()) command = command.encode('utf8') resp = BYTES2STR(query(port, command)) if not resp: PRINT('无法连接 QQBot-term 服务器') elif not resp.strip(): PRINT('QQBot 命令格式错误') else: PRINT(resp.strip()) except KeyboardInterrupt: pass
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
def Run(self): try: self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.sock.bind((HOST, self.port)) self.sock.listen(5) except socket.error as e: WARN('无法开启 QQBot term 服务器。%s', e) WARN(' qq 命令无法使用') else: time.sleep(0.1) INFO('已在 %s 端口开启 QQBot-Term 服务器,', self.port) INFO('请在其他控制台窗口使用 qq 命令来控制 QQBot ,' '示例: qq send buddy jack hello') while True: try: sock, addr = self.sock.accept() except socket.error: WARN('QQBot-Term 服务器出现 accept 错误') else: name = 'QTerm客户端"%s:%s"' % addr sock.settimeout(5.0) try: data = sock.recv(1024) except socket.error: sock.close() else: content = BYTES2STR(data) INFO('QTerm 命令:%s', content) yield TermMessage(name, sock, content)
def getManaulGroupQQDict(): mgQQDict = collections.defaultdict(list) from qqbot import QQBot fn = QQBot._bot.conf.absPath('groupqq') if not os.path.exists(fn): return mgQQDict try: with open(fn, 'rb') as f: s = f.read() except Exception as e: ERROR('无法读取群 QQ 文件 %s , %s', fn, e) return mgQQDict try: s = BYTES2STR(s) except Exception as e: ERROR('群 QQ 文件 %s 编码错误, %s', fn, e) return mgQQDict try: for line in s.split('\n'): if not line.startswith('#') and (',' in line): qq, nick = line.rstrip('\r').split(',', 1) mgQQDict[nick].append(qq) except Exception as e: ERROR('群 QQ 文件 %s 格式错误, %s', fn, e) return mgQQDict INFO('成功从文件 %s 中读取群的实际 QQ 号码', fn) return mgQQDict
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)
def QTerm(): # python qterm.py [PORT] [COMMAND] if len(sys.argv) >= 2 and sys.argv[1].isdigit(): port = sys.argv[1] command = ' '.join(sys.argv[2:]).strip() else: port = DEFPORT command = ' '.join(sys.argv[1:]).strip() if command: resp = BYTES2STR(Query(HOST, port, SYSTEMSTR2BYTES(command))) if not resp: PRINT('无法连接 QQBot-Term 服务器') elif not resp.strip(): PRINT('QQBot 命令格式错误') else: PRINT(resp.strip())
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
def parseLines(self, lines): if self.handler is None: return for line in lines: line = line.rstrip(b'\r').lstrip() if not line: continue try: line = BYTES2STR(line) except Exception as e: DEBUG('%r\n%r', e, line) continue head, sep, tail = line.partition(' :') params = head.rstrip().split() command, params = params[0].upper(), params[1:] DEBUG('%s <== %s: %r', self.servername, self.name, line) DEBUG('%r, %r, %r', command, params, tail) self.handler(command, params, tail)
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)