예제 #1
0
    def __init__(self, qq=None, user=None, conf=None, ai=None):
        MessageFactory.__init__(self)
        self.conf = conf if conf else QConf(qq, user)
        ai = ai if ai else BasicAI()
        termServer = QTermServer(self.conf.termServerPort)

        self.On('qqmessage', ai.OnQQMessage)  # main thread
        self.On('polltimeout', ai.OnPollTimeout)  # main thread
        self.On('termmessage', ai.OnTermMessage)  # main thread
        self.On('pollcomplete', QQBot.onPollComplete)  # main thread

        self.AddGenerator(self.pollForever)  # child thread 1
        self.AddGenerator(termServer.Run)  # child thread 2
예제 #2
0
def runBot(argv=None):
    if sys.argv[-1] == '--subprocessCall':
        sys.argv.pop()
        bot = QQBot._bot
        bot.init(argv)
        bot.Run()
    else:
        conf = QConf()

        if conf.daemon:
            conf.Daemonize()

        if sys.argv[0].endswith('py') or sys.argv[0].endswith('pyc'):
            args = [sys.executable] + sys.argv
        else:
            args = sys.argv

        if '--bench' not in args:
            args = args + ['--bench', os.getcwd()]
        args = args + ['--qq', str(conf.qq)]
        args = args + ['--subprocessCall']

        while True:
            p = subprocess.Popen(args)
            code = p.wait()
            if code == 0:
                INFO('QQBot 正常停止')
                sys.exit(code)
            elif code == RESTART:
                INFO('1 秒后重新启动 QQBot (自动登陆,qq=%s)', args[-2])
                time.sleep(1)
            else:
                CRITICAL('QQBOT 异常停止(code=%s)', code)
                if conf.restartOnOffline:
                    args[-2] = '0'
                    INFO('5秒后重新启动 QQBot (手动登录)')
                    time.sleep(5)
                else:
                    sys.exit(code)
예제 #3
0
def QLogin(qq=None, user=None, conf=None):
    if conf is None:
        conf = QConf(qq, user)

    if conf.qq:
        INFO('开始自动登录...')
        picklePath = conf.PicklePath()
        try:
            with open(picklePath, 'rb') as f:
                session, contacts = pickle.load(f)
        except Exception as e:
            WARN('自动登录失败,原因:%s', e)
        else:
            INFO('成功从文件 "%s" 中恢复登录信息和联系人' % picklePath)
            try:
                session.TestLogin()
            except QSession.Error:
                WARN('自动登录失败,原因:上次保存的登录信息已过期')
            else:
                INFO('登录成功。登录账号:%s(%s)', session.nick, session.qq)
                return session, contacts

    INFO('开始手动登录...')
    session = QSession()
    contacts = session.Login(conf)
    INFO('登录成功。登录账号:%s(%s)', session.nick, session.qq)

    conf.qq = session.qq
    picklePath = conf.PicklePath()
    try:
        with open(picklePath, 'wb') as f:
            pickle.dump((session, contacts), f)
    except IOError:
        WARN('保存登录信息及联系人失败:IOError %s', picklePath)
    else:
        INFO('登录信息及联系人已保存至文件:file://%s' % picklePath)

    return session, contacts
예제 #4
0
    def init(self, argv=None):
        for name, slots in self.slotsTable.items():
            setattr(self, name, self.wrap(slots))
        self.slotsTable['onQQRequestEvent'] = []
        self.conf = QConf(argv)
        self.conf.Display()

        self.Mirai = MiraiApi(self.conf.qq, self.conf.verifyKey,
                              self.conf.host, self.conf.port)
        while not self.Mirai.started:
            pass

        self.MessageFromId = self.Mirai.MessageFromId
        self.SendMessage = self.Mirai.SendMessage
        self.Nudge = self.Mirai.Nudge
        self.Recall = self.Mirai.Recall
        self.List = self.Mirai.List
        self.Profile = self.Mirai.Profile
        self.DeleteFriend = self.Mirai.DeleteFriend
        self.Mute = self.Mirai.Mute
        self.kick = self.Mirai.kick
        self.quit = self.Mirai.quit
        self.MuteAll = self.Mirai.MuteAll
        self.SetEssence = self.Mirai.SetEssence
        self.GroupConfig = self.Mirai.GroupConfig
        self.MemberInfo = self.Mirai.MemberInfo
        self.FileList = self.Mirai.FileList
        self.FileInfo = self.Mirai.FileInfo
        self.FileMkdir = self.Mirai.FileMkdir
        self.FileDelete = self.Mirai.FileDelete
        self.FileMove = self.Mirai.FileMove
        self.FilereName = self.Mirai.FilereName
        self.FileUpload = self.Mirai.FileUpload
        self.Upload = self.Mirai.Upload

        for pluginName in self.conf.plugins:
            self.Plug(pluginName)
예제 #5
0
def Main():
    try:
        if sys.argv[-1] == '--subprocessCall':
            isSubprocessCall = True
            sys.argv.pop()
        else:
            isSubprocessCall = False

        conf = QConf()
        if not conf.restartOnOffline or isSubprocessCall:
            bot = QQBot(conf=conf)
            bot.Login()
            sys.exit(bot.Run())
        else:
            args = ['python', __file__] + sys.argv[1:] + \
                   ['--mailAuthCode', conf.mailAuthCode, '--subprocessCall']
            while subprocess.call(args) != 0:
                INFO('重新启动 QQBot ')
    except KeyboardInterrupt:
        sys.exit(0)
예제 #6
0
class LockedValue(object):
    def __init__(self, initialVal=None):
        self.val = initialVal
        self.lock = threading.Lock()

    def setVal(self, val):
        with self.lock:
            self.val = val

    def getVal(self):
        with self.lock:
            val = self.val
        return val


if __name__ == '__main__':
    from qconf import QConf

    # 需要先在 ~/.qqbot-tmp/v2.x.conf 文件中设置好邮箱帐号和授权码
    conf = QConf()
    conf.Display()

    qrm = QrcodeManager(conf)
    with open('tmp.png', 'rb') as f:
        qrcode = f.read()
    qrm.Show(qrcode)
    time.sleep(5)
    qrm.Show(qrcode)
    qrm.Destroy()
예제 #7
0
        N[T % 4] ^= ord(K[T])

    U, V = 'ECOK', [0] * 4
    V[0] = ((x >> 24) & 255) ^ ord(U[0])
    V[1] = ((x >> 16) & 255) ^ ord(U[1])
    V[2] = ((x >> 8) & 255) ^ ord(U[2])
    V[3] = ((x >> 0) & 255) ^ ord(U[3])

    U1 = [0] * 8
    for T in range(8):
        U1[T] = N[T >> 1] if T % 2 == 0 else V[T >> 1]

    N1, V1 = '0123456789ABCDEF', ''
    for aU1 in U1:
        V1 += N1[((aU1 >> 4) & 15)]
        V1 += N1[((aU1 >> 0) & 15)]

    return V1


def bknHash(skey, init_str=5381):
    hash_str = init_str
    for i in skey:
        hash_str += (hash_str << 5) + ord(i)
    hash_str = int(hash_str & 2147483647)
    return hash_str


if __name__ == '__main__':
    session, contacts = QLogin(conf=QConf())
예제 #8
0
    osName = platform.system()
    if osName == 'Windows':
        filename = filename.decode('utf8').encode('cp936')
        retcode = subprocess.call([filename], shell=True)
    elif osName == 'Linux':
        retcode = subprocess.call(['gvfs-open', filename])
    elif osName == 'Darwin':
        retcode = subprocess.call(['open', filename])
    else:
        retcode = 1
    if retcode:
        raise


if __name__ == '__main__':
    from qconf import QConf

    # 需要先在 ~/.qqbot-tmp/v2.x.conf 文件中设置好邮箱帐号和授权码
    conf = QConf(user='******')
    conf.Display()

    qrm = QrcodeManager(conf)
    with open('tmp.png', 'rb') as f:
        qrcode = f.read()
    qrm.Show(qrcode)
    time.sleep(60)
    qrm.Show(qrcode)
    qrm.Destroy()

    time.sleep(60)
예제 #9
0
            return None, -1
        data = conn.fetch(email_id, 'BODY.PEEK[HEADER.FIELDS (SUBJECT)]')[1]
        if not PY3:
            msg = message_from_string(data[0][1])
            s, encoding = decode_header(msg['Subject'])[0]
            subject = s.decode(encoding or 'utf-8').encode('utf-8')
        else:
            msg = message_from_bytes(data[0][1])
            s, encoding = decode_header(msg['Subject'])[0]
            subject = s if type(s) is str else s.decode(encoding or 'utf-8')
        return subject

if __name__ == '__main__':
    import time
    from qconf import QConf
    conf = QConf(user='******')
    ma = MailAgent(conf.mailAccount, conf.mailAuthCode)

    with ma.SMTP() as s:
        s.send(conf.mailAccount, 'hello', 'faf房间多啦')
    print('send ok')
    
    time.sleep(5)
        
    with ma.IMAP() as i:
        subject = i.getSubject(-1)
        print('latest email: '+subject)
    print('recv ok')
        
#    with ma.IMAP() as i:
#        subject = i.getUnSeenSubject(-1)[0]
예제 #10
0
파일: miraiapi.py 프로젝트: MDeath/qqbot
    def FileUpload(self, path: str, filepath: str):  # 上传群文件
        r'target is the groupID'
        payload = {'sessionKey': self.session}
        payload['type'] = 'group'
        payload['path'] = path
        files = filepath
        return self._file('upload', payload, files=files)


### 多媒体内容上传 ###

    def Upload(self, mode: str, form: str, filepath):  # 上传图片或语言
        if mode not in ['Image', 'Voice']:
            raise RequestError
        if form not in ['friend', 'group', 'temp']:
            raise RequestError
        if mode == 'Voice':
            form = 'group'
        payload = {'sessionKey': self.session}
        payload['type'] = form
        files = {'file': open(filepath, 'rb')}
        return self.basicsession(Post,
                                 'upload{mode}',
                                 data=json.dumps(payload),
                                 files=files)

if __name__ == '__main__':
    from qconf import QConf
    qconf = QConf()
    q = MiraiApi(qconf.qq, qconf.verifyKey)
    print(q.started)
예제 #11
0
class QQBot():
    def __init__(self) -> None:
        self.scheduler = BackgroundScheduler(daemon=True)
        self.schedTable = defaultdict(list)
        self.slotsTable = {
            'onStartupComplete': [],
            'onInterval': [],
            'onQQMessage': [],
            'onQQEvent': [],
            'onPlug': [],
            'onUnplug': [],
            'onExit': []
        }
        self.plugins = {}

    def init(self, argv=None):
        for name, slots in self.slotsTable.items():
            setattr(self, name, self.wrap(slots))
        self.slotsTable['onQQRequestEvent'] = []
        self.conf = QConf(argv)
        self.conf.Display()

        self.Mirai = MiraiApi(self.conf.qq, self.conf.verifyKey,
                              self.conf.host, self.conf.port)
        while not self.Mirai.started:
            pass

        self.MessageFromId = self.Mirai.MessageFromId
        self.SendMessage = self.Mirai.SendMessage
        self.Nudge = self.Mirai.Nudge
        self.Recall = self.Mirai.Recall
        self.List = self.Mirai.List
        self.Profile = self.Mirai.Profile
        self.DeleteFriend = self.Mirai.DeleteFriend
        self.Mute = self.Mirai.Mute
        self.kick = self.Mirai.kick
        self.quit = self.Mirai.quit
        self.MuteAll = self.Mirai.MuteAll
        self.SetEssence = self.Mirai.SetEssence
        self.GroupConfig = self.Mirai.GroupConfig
        self.MemberInfo = self.Mirai.MemberInfo
        self.FileList = self.Mirai.FileList
        self.FileInfo = self.Mirai.FileInfo
        self.FileMkdir = self.Mirai.FileMkdir
        self.FileDelete = self.Mirai.FileDelete
        self.FileMove = self.Mirai.FileMove
        self.FilereName = self.Mirai.FilereName
        self.FileUpload = self.Mirai.FileUpload
        self.Upload = self.Mirai.Upload

        for pluginName in self.conf.plugins:
            self.Plug(pluginName)

    def Run(self):
        self.onStartupComplete()
        self.onPlug()

        StartDaemonThread(self.pollForever)
        StartDaemonThread(self.intervalForever)
        self.scheduler.start()
        Put(self.Update)

        try:
            MainLoop()
        except SystemExit as e:
            raise
        except Exception as e:
            ERROR('', exc_info=True)
            ERROR('Mainloop 发生未知错误:%r', e)
            self.onExit(1, 'unknown-error', e)
            raise SystemExit(1)

    def Stop(self):
        sys.exit(0)

    def Restart(self):
        sys.exit(RESTART)

    # child thread 1
    def pollForever(self):
        while self.Mirai.started:
            try:
                result = self.Mirai.GetMessage()
            except RequestError:
                Put(sys.exit)
                break
            except:
                ERROR('qsession.Poll 方法出错', exc_info=True)
            else:
                if not result: continue
                for r in result:
                    Put(self.MessageAnalyst, r)

    def MessageAnalyst(self, Message):
        if 'Message' in Message.type:
            Type = Message.type.replace('Message', '')
            Sender = Message.sender
            Message = Message.messageChain
            Source = Message.pop(0)
            if hasattr(Sender, 'group'):
                INFO(
                    f'来自 {Type} {Sender.group.name} {Sender.memberName} 的消息({Source.id}):'
                )
            else:
                INFO(f'来自 {Type} {Sender.nickname} 的消息({Source.id}):')
            INFO(str(Message))
            self.onQQMessage(Type, Sender, Source, Message)
        elif 'RequestEvent' in Message.type:
            if hasattr(self, 'onQQRequestEvent'):
                operate, msg = self.onQQRequestEvent(Message)
                self.Mirai.Event_response(Message, operate, msg)
        elif 'Event' in Message.type:
            self.onQQEvent(Message)

    def onQQRequestEvent(self, Message):
        for f in self.slotsTable['onQQRequestEvent']:
            operate, msg = f(self, Message)
            if not operate:
                return operate, msg
        else:
            return operate, msg

    # child thread 2
    def intervalForever(self):
        while True:
            time.sleep(300)
            Put(self.onInterval)

    def Command(self):
        while True:
            pass

    def wrap(self, slots):
        def func(*args, **kwargs):
            for f in slots:
                _call(f, self, *args, **kwargs)

        return func

    def AddSlot(self, func):
        self.slotsTable[func.__name__].append(func)
        return func

    def AddSched(self, **triggerArgs):
        def wrapper(func):
            job = lambda: Put(_call, func, self)
            job.__name__ = func.__name__
            j = self.scheduler.add_job(job, CronTrigger(**triggerArgs))
            self.schedTable[func.__module__].append(j)
            return func

        return wrapper

    def Update(self):
        self.Friend = self.List('Friend')
        self.Group = self.List('Group')
        self.Member = {}
        for g in self.Group:
            self.Member[g.id] = self.List('Member', g.id)
            for m in self.Member[g.id]:
                delattr(m, 'group')

    def unplug(self, moduleName, removeJob=True):
        for slots in self.slotsTable.values():
            i = 0
            while i < len(slots):
                if slots[i].__module__ == moduleName:
                    slots[i] = slots[-1]
                    slots.pop()
                else:
                    i += 1

        if removeJob:
            for job in self.schedTable.pop(moduleName, []):
                job.remove()
            self.plugins.pop(moduleName, None)

    def Plug(self, moduleName):
        self.unplug(moduleName)
        try:
            module = Import(moduleName)
        except Exception as e:
            result = '错误:无法加载插件 %s ,%s: %s' % (moduleName, type(e), e)
            ERROR('', exc_info=True)
            ERROR(result)
            self.unplug(moduleName)
        else:
            self.unplug(moduleName, removeJob=False)

            names = []
            for slotName in self.slotsTable.keys():
                if hasattr(module, slotName):
                    self.slotsTable[slotName].append(getattr(module, slotName))
                    names.append(slotName)

            if not names and moduleName not in self.schedTable:
                result = '警告:插件 %s 中没有定义回调函数或定时任务' % moduleName
                WARNING(result)
            else:
                self.plugins[moduleName] = module

                jobs = self.schedTable.get(moduleName, [])
                jobNames = [f.func.__name__ for f in jobs]
                result = '成功:加载插件 %s(回调函数%s、定时任务%s)' % \
                         (moduleName, names, jobNames)
                INFO(result)

                if self.Mirai.started and hasattr(module, 'onPlug'):
                    _call(module.onPlug, self)

        return result

    def Unplug(self, moduleName):
        if moduleName not in self.plugins:
            result = '警告:试图卸载未安装的插件 %s' % moduleName
            WARNING(result)
            return result
        else:
            module = self.plugins[moduleName]
            self.unplug(moduleName)
            if hasattr(module, 'onUnplug'):
                _call(module.onUnplug, self)
            result = '成功:卸载插件 %s' % moduleName
            INFO(result)
            return result

    def Plugins(self):
        return list(self.plugins.keys())
예제 #12
0
        conn = self.conn
        id_list = conn.search(None, '(UNSEEN)')[1][0].split()
        try:
            email_id = id_list[i]
        except IndexError:
            return None, -1
        data = conn.fetch(email_id, 'BODY.PEEK[HEADER.FIELDS (SUBJECT)]')[1]
        msg = message_from_string(data[0][1])
        s, encoding = decode_header(msg['Subject'])[0]
        subject = s.decode(encoding or 'utf-8').encode('utf-8')
        return subject

if __name__ == '__main__':
    import time
    from qconf import QConf
    conf = QConf(user='******')
    ma = MailAgent(conf.mailAccount, conf.mailAuthCode)

    with ma.SMTP() as s:
        s.send(conf.mailAccount, 'hello')
    print 'send ok'

#    with ma.IMAP() as i:
#        subject = i.getUnSeenSubject(-1)[0]
#        print 'latest email:', subject
#    print 'recv ok'
#
#    time.sleep(5)
#
#    with ma.IMAP() as i:
#        i.delMail(subject)
예제 #13
0
파일: mailagent.py 프로젝트: yejr/qqbot
            return None, -1
        data = conn.fetch(email_id, 'BODY.PEEK[HEADER.FIELDS (SUBJECT)]')[1]
        if not PY3:
            msg = message_from_string(data[0][1])
            s, encoding = decode_header(msg['Subject'])[0]
            subject = s.decode(encoding or 'utf-8').encode('utf-8')
        else:
            msg = message_from_bytes(data[0][1])
            s, encoding = decode_header(msg['Subject'])[0]
            subject = s if type(s) is str else s.decode(encoding or 'utf-8')
        return subject

if __name__ == '__main__':
    import time
    from qconf import QConf
    conf = QConf(['-u', 'hcj'])
    ma = MailAgent(conf.mailAccount, conf.mailAuthCode)

    with ma.SMTP() as s:
        s.send(conf.mailAccount, 'hello', 'faf房间多啦')
    print('send ok')
    
    time.sleep(5)
        
    with ma.IMAP() as i:
        subject = i.getSubject(-1)
        print('latest email: '+subject)
    print('recv ok')
        
#    with ma.IMAP() as i:
#        subject = i.getUnSeenSubject(-1)[0]