Example #1
0
def QLogin(qq=None, user=None):
    conf = QConf(qq, user)
    conf.Display()

    if conf.qq:
        INFO('开始自动登录...')
        picklePath = conf.PicklePath()
        session = QSession()
        contactdb = QContactDB(session)
        try:
            contactdb.Restore(picklePath)
        except Exception as e:
            WARN('自动登录失败,原因:%s', e)
        else:
            INFO('成功从文件 "%s" 中恢复登录信息' % picklePath)

            try:
                contactdb.session.TestLogin()
            except RequestError:
                WARN('自动登录失败,原因:上次保存的登录信息已过期')
            except Exception as e:
                WARN('自动登录失败,原因:%s', e)
                DEBUG('', exc_info=True)
            else:
                return contactdb.session.Copy(), contactdb, conf

    INFO('开始手动登录...')
    session = QSession()
    session.Login(conf)
    contactdb = QContactDB(session, conf.PicklePath())
    contactdb.Dump()
    return session.Copy(), contactdb, conf
Example #2
0
def runBot(argv):
    # argv -1, sub program call
    if sys.argv[-1] == '--subprocessCall':
        # Remove the last item
        sys.argv.pop()
        try:
            # Bot login, run
            # QQBot is defined below.
            bot = QQBot._bot
            bot.Login(argv)
            bot.Run()
        finally:
            # Finally, always run, no matter what
            # If bot has conf, bot conf storeQQ
            if hasattr(bot, 'conf'):
                bot.conf.StoreQQ()
    else:
        # Not sub program called
        conf = QConf()

        # QQ run in background
        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

        args = args + ['--mailAuthCode', conf.mailAuthCode]
        args = args + ['--qq', 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:
                args[-2] = conf.LoadQQ()
                INFO('5 秒后重新启动 QQBot (自动登陆,qq=%s)', args[-2])
                time.sleep(5)
            elif code == FRESH_RESTART:
                args[-2] = ''
                INFO('5 秒后重新启动 QQBot (手工登陆)')
                time.sleep(5)
            else:
                CRITICAL('QQBOT 异常停止(code=%s)', code)
                if conf.restartOnOffline:
                    args[-2] = conf.LoadQQ()
                    INFO('15秒后重新启动 QQBot (自动登陆,qq=%s)', args[-2])
                    time.sleep(15)
                else:
                    sys.exit(code)
Example #3
0
    def init(self, argv):
        for name, slots in self.slotsTable.items():
            setattr(self, name, self.wrap(slots))

        self.conf = QConf(argv)
        self.conf.Display()

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

        self.onInit()
Example #4
0
def runBot(botCls, qq, user):
    if sys.argv[-1] == '--subprocessCall':
        isSubprocessCall = True
        sys.argv.pop()
    else:
        isSubprocessCall = False

    if isSubprocessCall:
        bot = botCls()
        try:
            bot.Login(qq, user)
            bot.Run()
        finally:
            if hasattr(bot, 'conf'):
                bot.conf.StoreQQ()
    else:
        conf = QConf(qq, user)

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

        args = args + ['--mailAuthCode', conf.mailAuthCode]
        args = args + ['--qq', conf.qq]
        args = args + ['--subprocessCall']

        while True:
            p = subprocess.Popen(args)
            pid = p.pid
            code = p.wait()
            qq = conf.LoadQQ(pid)
            if code == 0:
                INFO('QQBot 正常停止')
                sys.exit(code)
            elif code == RESTART:
                args[-2] = qq
                INFO('5 秒后重新启动 QQBot (自动登陆,qq=%s)', args[-2])
                time.sleep(5)
            elif code == FRESH_RESTART:
                args[-2] = ''
                INFO('5 秒后重新启动 QQBot (手工登陆)')
                time.sleep(5)
            else:
                CRITICAL('QQBOT 异常停止(code=%s)', code)
                if conf.restartOnOffline:
                    args[-2] = qq
                    INFO('15秒后重新启动 QQBot (自动登陆,qq=%s)', args[-2])
                    time.sleep(15)
                else:
                    sys.exit(code)
Example #5
0
    def Login(self, qq=None, user=None):
        self.conf = QConf(qq, user)
        session, contactdb, self.conf = QLogin(conf=self.conf)

        # main thread
        self.SendTo = session.SendTo
        self.groupKick = session.GroupKick
        self.groupSetAdmin = session.GroupSetAdmin
        self.groupShut = session.GroupShut
        self.groupSetCard = session.GroupSetCard

        # main thread
        self.List = contactdb.List
        self.Update = contactdb.Update
        self.StrOfList = contactdb.StrOfList
        self.ObjOfList = contactdb.ObjOfList
        self.findSender = contactdb.FindSender
        self.firstFetch = contactdb.FirstFetch
        self.Delete = contactdb.db.Delete
        self.Modify = contactdb.db.Modify

        # child thread 1
        self.poll = session.Copy().Poll

        # child thread 2
        self.termForver = QTermServer(self.conf.termServerPort).Run
Example #6
0
def QLogin(qq=None, user=None):
    conf = QConf(qq, user)
    conf.Display()

    if conf.qq:
        INFO('开始自动登录...')
        picklePath = conf.PicklePath()
        session = QSession()
        try:
            with open(picklePath, 'rb') as f:
                session.__dict__ = pickle.load(f)
        except Exception as e:
            WARN('自动登录失败,原因:%s', e)
        else:
            INFO('成功从文件 "%s" 中恢复登录信息' % SYSTEMSTR2STR(picklePath))

            try:
                session.TestLogin()
            except RequestError:
                WARN('自动登录失败,原因:上次保存的登录信息已过期')
            except Exception as e:
                WARN('自动登录失败,原因:%s', e)
                DEBUG('', exc_info=True)                
            else:
                return session, QContactDB(session), conf
            
            if os.path.exists(session.dbname):
                try:
                    os.remove(session.dbname)
                except OSError:
                    pass
                except:
                    WARN('', exc_info=True)

    INFO('开始手动登录...')
    session = QSession()
    session.Login(conf)
    picklePath = conf.PicklePath()
    try:
        with open(picklePath, 'wb') as f:
            pickle.dump((session.__dict__), f)
    except Exception as e:
        WARN('保存登录信息及联系人失败:%s %s', (e, SYSTEMSTR2STR(picklePath)))
    else:
        INFO('登录信息已保存至文件:file://%s' % SYSTEMSTR2STR(picklePath))

    return session, QContactDB(session), conf
Example #7
0
def runBot(botCls, qq, user):
    if sys.argv[-1] == '--subprocessCall':
        isSubprocessCall = True
        sys.argv.pop()
    else:
        isSubprocessCall = False

    if isSubprocessCall:
        bot = botCls()
        bot.Login(qq, user)
        bot.Run()
    else:
        conf = QConf(qq, user)

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

        args = args + ['--mailAuthCode', conf.mailAuthCode]
        args = args + ['--qq', conf.qq]
        args = args + ['--subprocessCall']

        while True:
            code = subprocess.call(args)
            if code == 0:
                INFO('QQBot 正常停止')
                sys.exit(code)
            elif code == RESTART:
                args[-2] = conf.LoadQQ()
                INFO('5 秒后重新启动 QQBot (自动登陆)')
                time.sleep(5)
            elif code == FRESH_RESTART:
                args[-2] = ''
                INFO('5 秒后重新启动 QQBot (手工登陆)')
                time.sleep(5)
            else:
                CRITICAL('QQBOT 异常停止(code=%s)', code)
                if conf.restartOnOffline:
                    args[-2] = conf.LoadQQ()
                    INFO('30秒后重新启动 QQBot (自动登陆)')
                    time.sleep(30)
                else:
                    sys.exit(code)
Example #8
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
Example #9
0
class QQBot(GroupManager, TermBot):

    # this class, arg
    def Login(self, argv=None):
        # init bot
        self.init(argv)

        session, contactdb = QLogin(self.conf)
        self.session, self.contactdb = session, contactdb

        # main thread
        self.SendTo = session.Copy().SendTo
        self.groupKick = session.GroupKick
        self.groupSetAdmin = session.GroupSetAdmin
        self.groupShut = session.GroupShut
        self.groupSetCard = session.GroupSetCard

        # main thread
        self.List = contactdb.List
        self.Update = contactdb.Update
        self.StrOfList = contactdb.StrOfList
        self.ObjOfList = contactdb.ObjOfList
        self.findSender = contactdb.FindSender
        self.firstFetch = contactdb.FirstFetch
        self.Delete = contactdb.db.Delete
        self.Modify = contactdb.db.Modify

        # child thread 1
        self.poll = session.Copy().Poll

    def Run(self):
        if self.conf.startAfterFetch:
            self.firstFetch()

        self.onPlug()
        self.onStartupComplete()

        # child thread 1~4
        StartDaemonThread(self.pollForever)
        StartDaemonThread(self.intervalForever)
        StartDaemonThread(
            QTermServer(self.conf.termServerPort, self.onTermCommand).Run)
        self.scheduler.start()

        self.started = True

        try:
            MainLoop()
        except SystemExit as e:
            self.onExit(e.code, getReason(e.code), None)
            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)

    def FreshRestart(self):
        sys.exit(FRESH_RESTART)

    # child thread 1
    def pollForever(self):
        while True:
            try:
                result = self.poll()
            except RequestError:
                Put(sys.exit, LOGIN_EXPIRE)
                break
            except:
                ERROR('qsession.Poll 方法出错', exc_info=True)
            else:
                Put(self.onPollComplete, *result)

    def onPollComplete(self, ctype, fromUin, membUin, content):
        if ctype == 'timeout':
            return

        contact, member, nameInGroup = \
            self.findSender(ctype, fromUin, membUin, self.conf.qq, content)

        if contact.ctype == 'group' and member == 'SYSTEM-MESSAGE':
            INFO('来自 %s 的系统消息: "%s"', contact, content)
            return

        if self.detectAtMe(nameInGroup, content):
            INFO('有人 @ 我:%s[%s]' % (contact, member))
            content = '[@ME] ' + content.replace('@' + nameInGroup, '')
        else:
            content = content.replace('@ME', '@Me')

        if ctype == 'buddy':
            INFO('来自 %s 的消息: "%s"' % (contact, content))
        else:
            INFO('来自 %s[%s] 的消息: "%s"' % (contact, member, content))

        self.onQQMessage(contact, member, content)

    def detectAtMe(self, nameInGroup, content):
        return nameInGroup and ('@' + nameInGroup) in content

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

    def __init__(self):
        self.scheduler = BackgroundScheduler(daemon=True)
        self.schedTable = defaultdict(list)
        self.slotsTable = {
            'onInit': [],
            'onQrcode': [],
            'onStartupComplete': [],
            'onQQMessage': [],
            'onInterval': [],
            'onUpdate': [],
            'onPlug': [],
            'onUnplug': [],
            'onExit': [],
        }
        self.started = False
        self.plugins = {}

    def init(self, argv):
        for name, slots in self.slotsTable.items():
            setattr(self, name, self.wrap(slots))

        self.conf = QConf(argv)
        self.conf.Display()

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

        self.onInit()

    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 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
                WARN(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.started and hasattr(module, 'onPlug'):
                    _call(module.onPlug, self)

        return result

    def Unplug(self, moduleName):
        if moduleName not in self.plugins:
            result = '警告:试图卸载未安装的插件 %s' % moduleName
            WARN(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())
Example #10
0
    INFO('正在获取 %s ...', rname)
    try:
        if ttype == 'buddy':
            table = fetchBuddyTable(self)
        elif ttype == 'group':
            table = fetchGroupTable(self)
        elif ttype == 'discuss':
            table = fetchDiscussTable(self)
        elif ttype == 'group-member':
            table = fetchGroupMemberTable(self, tinfo)
        else:
            table = fetchDiscussMemberTable(self, tinfo)
    except RequestError:
        table = None
    except:
        ERROR('', exc_info=True)
        table = None

    if table is None:
        ERROR('获取 %s 失败', rname)

    return table


if __name__ == '__main__':
    from qqbot.qconf import QConf
    from qqbot.basicqsession import BasicQSession

    self = BasicQSession()
    self.Login(QConf())
Example #11
0
                    pass
                except:
                    WARN('', exc_info=True)

    INFO('开始手动登录...')
    session = QSession()
    session.Login(conf)
    picklePath = conf.PicklePath()
    try:
        with open(picklePath, 'wb') as f:
            pickle.dump((session.__dict__), f)
    except Exception as e:
        WARN('保存登录信息及联系人失败:%s %s', (e, SYSTEMSTR2STR(picklePath)))
    else:
        INFO('登录信息已保存至:%s' % SYSTEMSTR2STR(picklePath))

    return session, QContactDB(session)


class QSession(BasicQSession, GroupManagerSession):
    pass


if __name__ == '__main__':
    from qqbot.qconf import QConf
    conf = QConf(['-q', '1261422618'])
    conf.Display()
    session, contactdb = QLogin(conf)
    self = session
    c = contactdb.List('buddy', 'Eva')[0]
Example #12
0
            email_id = id_list[i]
        except IndexError:
            return None
        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__':
    from qqbot.qconf import QConf

    conf = QConf(['-u', 'xxx'])
    conf.Display()

    ma = MailAgent(conf.mailAccount, conf.mailAuthCode)

    with ma.SMTP() as s:
        s.send(conf.mailAccount, 'hello', 'faf房间多啦')
    print('send ok')

    with ma.IMAP() as i:
        subject = i.getSubject(-1)
        print('latest email: ' + str(subject))
    print('recv ok')
Example #13
0
        if ttype == 'buddy':
            table = fetchBuddyTable(self)
        elif ttype == 'group':
            table = fetchGroupTable(self)
        elif ttype == 'discuss':
            table = fetchDiscussTable(self)
        elif ttype == 'group-member':
            table = fetchGroupMemberTable(self, tinfo)
        else:
            table = fetchDiscussMemberTable(self, tinfo)
    except RequestError:
        table = None
    except:
        ERROR('', exc_info=True)
        table = None

    if table is None:
        ERROR('获取 %s 失败', rname)

    return table


if __name__ == '__main__':
    from qqbot.qconf import QConf
    from qqbot.basicqsession import BasicQSession

    self = BasicQSession()
    conf = QConf(['-q', '158297369'])
    conf.Display()
    self.Login(conf)