def __init__(self): my_jid = JID(USER + '/Bot') self.my_jid = my_jid settings = XMPPSettings({ "software_name": "qxbot", "software_version": __version__, "software_os": "Linux", "tls_verify_peer": False, "starttls": True, "ipv6": False, "poll_interval": 10, }) settings["password"] = PASSWORD version_provider = VersionProvider(settings) event_queue = settings["event_queue"] self.webqq = WebQQ(QQ, event_queue) self.connected = False #self.mainloop = TornadoMainLoop(settings) self.mainloop = EpollMainLoop(settings) self.client = Client(my_jid, [self, version_provider], settings, self.mainloop) self.logger = get_logger() self.msg_dispatch = MessageDispatch(self, self.webqq, BRIDGES) self.xmpp_msg_queue = Queue.Queue()
def newclient(self): version_provider = VersionProvider(self.settings) self.client = Client( self.jid, [self, version_provider], self.settings, main_loop=self.main_loop, )
def __init__(self, my_jid, settings): version_provider = VersionProvider(settings) self.main_loop = SelectMainLoop(settings) #self.main_loop = ThreadPool(settings) #self.main_loop.start(daemon=True) self.client = Client(my_jid, [self, version_provider], settings, main_loop=self.main_loop)
def start(self): """ 服务开始 :return: """ logger.warn("XMPPClient::start listen on %s:%s:%s" % (self.protocol, self.JID, self.password)) self.xmpp_client = Client(self.JID, [self], self.settings) self.xmpp_client.connect() self.xmpp_client.run() self.is_auth = False
def __init__(self): self.droid = android.Android() settings = XMPPSettings({"software_name": "Say Chat"}) settings["jid"] = self.droid.dialogGetInput("Google Talk Username").result settings["password"] = self.droid.dialogGetInput("Google Talk Password").result settings["server"] = "talk.google.com" settings["starttls"] = True self.client = Client( JID(settings["jid"]), [self, VersionProvider(settings)], settings)
def __init__(self, your_jid, your_pass, target_jid, messages): self.target_jid = target_jid self.messages = messages self.connected = False self.established = False settings = XMPPSettings({ u"password": your_pass, u"starttls": True, u"tls_verify_peer": False, }) self.client = Client(JID(your_jid), [self], settings) self.client.connect()
def __init__(self): my_jid = JID(USER+'/Bot') self.my_jid = my_jid settings = XMPPSettings({ "software_name": "qxbot", "software_version": __version__, "software_os": "Linux", "tls_verify_peer": False, "starttls": True, "ipv6":False, "poll_interval": 10, }) settings["password"] = PASSWORD version_provider = VersionProvider(settings) event_queue = settings["event_queue"] self.webqq = WebQQ(QQ, event_queue) self.connected = False #self.mainloop = TornadoMainLoop(settings) self.mainloop = EpollMainLoop(settings) self.client = Client(my_jid, [self, version_provider], settings, self.mainloop) self.logger = get_logger() self.msg_dispatch = MessageDispatch(self, self.webqq, BRIDGES) self.xmpp_msg_queue = Queue.Queue()
def __init__(self): self.droid = android.Android() settings = XMPPSettings({"software_name": "Say Chat"}) settings["jid"] = self.droid.dialogGetInput("Google Talk Username").result settings["password"] = self.droid.dialogGetInput("Google Talk Password").result settings["server"] = "talk.google.com" settings["starttls"] = True self.client = Client(JID(settings["jid"]), [self, VersionProvider(settings)], settings)
def __init__(self, my_jid, settings, myname, events, text): version_provider = VersionProvider(settings) self.client = Client(my_jid, [self, version_provider], settings) self.myname = myname # first and last name of user self.logs = {} self.parser = ttp.Parser() # twitter text processing lib handler self.events = events self.do_text = text self.last_msg = ""
def submit(self): for admin in settings_file.users['administrators']: self.target_jid = settings_file.users['administrators'][admin] if sys.version_info.major < 3: self.your_jid = self.your_jid.decode("utf-8") self.your_password = self.your_password.decode("utf-8") self.target_jid = self.target_jid.decode("utf-8") self.message = self.message.decode("utf-8") handler = MyHandler(JID(self.target_jid), self.message) settings = XMPPSettings({ u"password": self.your_password, u"starttls": True, u"tls_verify_peer": False, }) client = Client(JID(self.your_jid), [handler], settings) client.connect() client.run()
def __init__(self, jid, settings): if 'software_name' not in settings: settings['software_name'] = self.__class__.__name__ if 'software_version' not in settings: settings['software_version'] = __version__ version_provider = VersionProvider(settings) self.client = Client(jid, [self, version_provider], settings) self.presence = defaultdict(dict) self.subscribes = ExpiringDictionary(default_timeout=5) self.invited = {}
def __init__(self, jid, settings, botsettings=None): if 'software_name' not in settings: settings['software_name'] = self.__class__.__name__ if 'software_version' not in settings: settings['software_version'] = __version__ version_provider = VersionProvider(settings) handlers = [] if ReceiptSender: self.receipt_sender = rs = ReceiptSender() handlers.append(rs) handlers.extend([self, version_provider]) self.client = Client(jid, handlers, settings) self.presence = defaultdict(dict) self.subscribes = ExpiringDictionary(default_timeout=5) self.invited = {} self.avatar_hash = None self.settings = botsettings
def send(self, req_id, stanzas): self.req_id = req_id self.stanzas = stanzas logging.debug(u"XmppClient start sending messages for request #%s", self.req_id) try: settings = XMPPSettings({ u"password": self.password, u"starttls": self.use_tls, u"tls_verify_peer": self.tls_verify_peer, u"server": self.host, u"port": self.port, u"default_stanza_timeout": self.timeout, }) self.client = Client(self.from_jid, [self], settings) self.client.connect() self.client.run(timeout=self.timeout) except Exception, e: logging.error( "Error sending XMPP notification for request #%s: %s", req_id, e, exc_info=1)
def __init__(self): my_jid = JID(USER + '/Bot') self.my_jid = my_jid settings = XMPPSettings({ "software_name": "Clubot", "software_version": __version__, "software_os": "Linux", "tls_verify_peer": False, "starttls": True, "ipv6": False, "poll_interval": 10, }) settings["password"] = PASSWORD version_provider = VersionProvider(settings) self.connected = False mainloop = TornadoMainLoop(settings) self.client = Client(my_jid, [self, version_provider], settings, mainloop) #self.client = Client(my_jid, [self, version_provider], settings) self.logger = get_logger() self.trytimes = 0 self.sended = [] Logics.empty_status()
class SayChat(EventHandler, XMPPFeatureHandler): def __init__(self): self.droid = android.Android() settings = XMPPSettings({"software_name": "Say Chat"}) settings["jid"] = self.droid.dialogGetInput("Google Talk Username").result settings["password"] = self.droid.dialogGetInput("Google Talk Password").result settings["server"] = "talk.google.com" settings["starttls"] = True self.client = Client( JID(settings["jid"]), [self, VersionProvider(settings)], settings) def connect(self): self.client.connect() self.client.run() def disconnect(self): self.client.disconnect() self.client.run(timeout = 2) @message_stanza_handler() def handle_message(self, stanza): self.droid.ttsSpeak( "{!s} says {!s}".format(stanza.from_jid.as_unicode(), stanza.body)) return "" @event_handler(DisconnectedEvent) def handle_disconnected(self, event): return QUIT @event_handler() def handle_all(self, event): """If it's not logged, it didn't happen.""" logging.info("-- {}".format(event)) def run(self): try: self.connect() except KeyboardInterrupt: self.disconnect()
class SayChat(EventHandler, XMPPFeatureHandler): def __init__(self): self.droid = sl4a.Android() settings = XMPPSettings({"software_name": "Say Chat"}) settings["jid"] = self.droid.dialogGetInput("Google Talk Username").result settings["password"] = self.droid.dialogGetInput("Google Talk Password").result settings["server"] = "talk.google.com" settings["starttls"] = True self.client = Client( JID(settings["jid"]), [self, VersionProvider(settings)], settings) def connect(self): self.client.connect() self.client.run() def disconnect(self): self.client.disconnect() self.client.run(timeout = 2) @message_stanza_handler() def handle_message(self, stanza): self.droid.ttsSpeak( "{!s} says {!s}".format(stanza.from_jid.as_unicode(), stanza.body)) return "" @event_handler(DisconnectedEvent) def handle_disconnected(self, event): return QUIT @event_handler() def handle_all(self, event): """If it's not logged, it didn't happen.""" logging.info("-- {}".format(event)) def run(self): try: self.connect() except KeyboardInterrupt: self.disconnect()
def push(self): settings = XMPPSettings({ u"password": self.from_pwd, u"starttls": True, u"tls_verify_peer": False, u'server': self.xmpp_server, u'c2s_port': int(self.xmpp_port), }) xml = self.msg client = Client(JID(self.from_jid), [MyHandler(xml.encode('utf-8'))], settings) client.connect() client.run()
def __init__(self): my_jid = JID(USER+'/Bot') self.my_jid = my_jid settings = XMPPSettings({ "software_name": "Clubot", "software_version": __version__, "software_os": "Linux", "tls_verify_peer": False, "starttls": True, "ipv6":False, }) settings["password"] = PASSWORD version_provider = VersionProvider(settings) self.connected = False self.client = Client(my_jid, [self, version_provider], settings) self.logger = get_logger() self.trytimes = 0 empty_status()
class SmsRobotClient(EventHandler, XMPPFeatureHandler): def __init__(self, your_jid, your_pass, target_jid, messages): self.target_jid = target_jid self.messages = messages self.connected = False self.established = False settings = XMPPSettings({ u"password": your_pass, u"starttls": True, u"tls_verify_peer": False, }) self.client = Client(JID(your_jid), [self], settings) self.client.connect() def run(self): while self.messages: if self.connected and not self.established: print("Connecting...") self.client.stream.send( Message(to_jid=self.target_jid, body="?", stanza_type='chat')) self.client.run(timeout=2) @event_handler(AuthorizedEvent) def handle_authorized(self, event): self.connected = True @message_stanza_handler() def handle_message(self, stanza): if not self.established: if '"help"' not in stanza.body: return self.established = True if not self.messages: self.client.disconnect() return None body = 'sms:%s:%s' % self.messages.pop() print(body) return Message(to_jid=self.target_jid, body=body, stanza_type='chat') @event_handler(DisconnectedEvent) def handle_disconnected(self, event): return QUIT
class SmsRobotClient(EventHandler, XMPPFeatureHandler): def __init__(self, your_jid, your_pass, target_jid, messages): self.target_jid = target_jid self.messages = messages self.connected = False self.established = False settings = XMPPSettings({ u"password": your_pass, u"starttls": True, u"tls_verify_peer": False, }) self.client = Client(JID(your_jid), [self], settings) self.client.connect() def run(self): while self.messages: if self.connected and not self.established: print("Connecting...") self.client.stream.send(Message(to_jid = self.target_jid, body = "?", stanza_type = 'chat')) self.client.run(timeout = 2) @event_handler(AuthorizedEvent) def handle_authorized(self, event): self.connected = True @message_stanza_handler() def handle_message(self, stanza): if not self.established: if '"help"' not in stanza.body: return self.established = True if not self.messages: self.client.disconnect() return None body = 'sms:%s:%s' % self.messages.pop() print(body) return Message(to_jid = self.target_jid, body = body, stanza_type = 'chat') @event_handler(DisconnectedEvent) def handle_disconnected(self, event): return QUIT
def send(self, req_id, stanzas): self.req_id = req_id self.stanzas = stanzas logging.debug(u"XmppClient start sending messages for request #%s", self.req_id) try: settings = XMPPSettings({ u"password": self.password, u"starttls": self.use_tls, u"tls_verify_peer": self.tls_verify_peer, u"server" : self.host, u"port": self.port, u"default_stanza_timeout": self.timeout, }) self.client = Client(self.from_jid, [self], settings) self.client.connect() self.client.run( timeout = self.timeout ) except Exception, e: logging.error("Error sending XMPP notification for request #%s: %s", req_id, e, exc_info=1)
def __init__(self): my_jid = JID(USER+'/Bot') self.my_jid = my_jid settings = XMPPSettings({ "software_name": "Clubot", "software_version": __version__, "software_os": "Linux", "tls_verify_peer": False, "starttls": True, "ipv6":False, "poll_interval": 10, }) settings["password"] = PASSWORD version_provider = VersionProvider(settings) self.connected = False mainloop = TornadoMainLoop(settings) self.client = Client(my_jid, [self, version_provider], settings, mainloop) #self.client = Client(my_jid, [self, version_provider], settings) self.logger = get_logger() self.trytimes = 0 self.sended = [] Logics.empty_status()
def __init__(self, QQ, QQ_PWD, xmpp_account, xmpp_pwd, control_account, debug=True, command=None): self.input_queue = InputQueue(self.send_control_msg) self.qq = QQClient(QQ, QQ_PWD, debug) self.qq.set_control_msg(self.send_control_msg, self) self.command = command or Command(self, self.qq) self.jid = JID(xmpp_account + '/Bridge') self.control_account = control_account settings = XMPPSettings( {"software_name": "Magpie", "software_version": ".".join(str(x) for x in __version__), "software_os": "Linux", "tls_verify_peer": False, "starttls": True, "ipv6": False, "password": xmpp_pwd, "poll_interval": 10}) version_provider = VersionProvider(settings) mainloop = TornadoMainLoop(settings) self.client = Client(self.jid, [self, version_provider], settings, mainloop)
class XmppClient(EventHandler): """ A client to manage the XMPP connection and dispatch messages. """ NAME = "Review Board XMPP Notification Client" VERSION = 0.1 def __init__(self, host, port, timeout, from_jid, password, use_tls, tls_verify_peer): self.host = host self.port = port self.timeout = timeout or 5 self.from_jid = from_jid self.password = password self.use_tls = use_tls self.tls_verify_peer = tls_verify_peer self.req_id = None self.client = None self.stanzas = None @event_handler(AuthorizedEvent) def handle_authorized(self, event): logging.debug(u"XmppClient event handler for request #%s authorized: %s", self.req_id, event) if self.client.stream != event.stream: logging.debug(u"XmppClient event handler ignore event") return for stanza in self.stanzas: logging.debug("XmppHandler for request #%s send message to %s", self.req_id, stanza.as_xml()) event.stream.send(stanza) logging.debug(u"XmppHandler disconnecting stream for request #%s", self.req_id) self.client.disconnect() @event_handler(DisconnectedEvent) def handle_disconnected(self, event): logging.debug("XmppClient event handler for request #%s disconnected: %s", self.req_id, event) if self.client.stream != event.stream: logging.debug(u"XmppClient event handler ignore event") return logging.debug(u"XmppClient event handler closing stream for request #%s", self.req_id) self.client.close_stream() self.client = None return QUIT @event_handler() def handle_all(self, event): logging.debug(u"XmppClient event handler for request #%s: %s", self.req_id, event) def send(self, req_id, stanzas): self.req_id = req_id self.stanzas = stanzas logging.debug(u"XmppClient start sending messages for request #%s", self.req_id) try: settings = XMPPSettings({ u"password": self.password, u"starttls": self.use_tls, u"tls_verify_peer": self.tls_verify_peer, u"server" : self.host, u"port": self.port, u"default_stanza_timeout": self.timeout, }) self.client = Client(self.from_jid, [self], settings) self.client.connect() self.client.run( timeout = self.timeout ) except Exception, e: logging.error("Error sending XMPP notification for request #%s: %s", req_id, e, exc_info=1)
class Bot(EventHandler, XMPPFeatureHandler): def __init__(self, my_jid, settings): version_provider = VersionProvider(settings) self.main_loop = SelectMainLoop(settings) #self.main_loop = ThreadPool(settings) #self.main_loop.start(daemon=True) self.client = Client(my_jid, [self, version_provider], settings, main_loop=self.main_loop) #self.client = Client(my_jid, [self, version_provider], settings) def run(self): """Request client connection and start the main loop.""" self.client.connect() self.client.run() def disconnect(self): """Request disconnection and let the main loop run for a 2 more seconds for graceful disconnection.""" self.client.disconnect() self.client.run(timeout=2) @presence_stanza_handler("subscribe") def handle_presence_subscribe(self, stanza): logging.info(u"{0} requested presence subscription".format( stanza.from_jid)) presence = Presence(to_jid=stanza.from_jid.bare(), stanza_type="subscribe") return [stanza.make_accept_response(), presence] @presence_stanza_handler("subscribed") def handle_presence_subscribed(self, stanza): logging.info(u"{0!r} accepted our subscription request".format( stanza.from_jid)) return True @presence_stanza_handler("unsubscribe") def handle_presence_unsubscribe(self, stanza): logging.info(u"{0} canceled presence subscription".format( stanza.from_jid)) presence = Presence(to_jid=stanza.from_jid.bare(), stanza_type="unsubscribe") return [stanza.make_accept_response(), presence] @presence_stanza_handler("unsubscribed") def handle_presence_unsubscribed(self, stanza): logging.info(u"{0!r} acknowledged our subscrption cancelation".format( stanza.from_jid)) return True # @message_stanza_handler() # def handle_message(self, stanza): # """Echo every non-error ``<message/>`` stanza. # Add "Re: " to subject, if any. # """ # if stanza.subject: # subject = u"Re: " + stanza.subject # else: # subject = None # if stanza.body is None: # txt = None # else: # txt = stanza.body+'!' # msg = Message(stanza_type = stanza.stanza_type, # from_jid = stanza.to_jid, to_jid = stanza.from_jid, # subject = subject, body = txt, # thread = stanza.thread) # return msg @message_stanza_handler() def handle_message(self, stanza): if stanza.stanza_type == 'chat' and not hasattr(stanza, 'processed'): #print stanza stanza.processed = True to_jid = stanza.to_jid.as_unicode() from_jid = stanza.from_jid.as_unicode() im_tcp_tunneler.handle_message(from_jid, to_jid, stanza.body) return True @event_handler(DisconnectedEvent) def handle_disconnected(self, event): """Quit the main loop upon disconnection.""" return QUIT @event_handler() def handle_all(self, event): """Log all events.""" logging.info(u"-- {0}".format(event))
class Bot(EventHandler, XMPPFeatureHandler): def __init__(self, my_jid, settings): version_provider = VersionProvider(settings) self.main_loop = SelectMainLoop(settings) #self.main_loop = ThreadPool(settings) #self.main_loop.start(daemon=True) self.client = Client(my_jid, [self, version_provider], settings, main_loop=self.main_loop) #self.client = Client(my_jid, [self, version_provider], settings) def run(self): """Request client connection and start the main loop.""" self.client.connect() self.client.run() def disconnect(self): """Request disconnection and let the main loop run for a 2 more seconds for graceful disconnection.""" self.client.disconnect() self.client.run(timeout = 2) @presence_stanza_handler("subscribe") def handle_presence_subscribe(self, stanza): logging.info(u"{0} requested presence subscription".format(stanza.from_jid)) presence = Presence(to_jid = stanza.from_jid.bare(), stanza_type = "subscribe") return [stanza.make_accept_response(), presence] @presence_stanza_handler("subscribed") def handle_presence_subscribed(self, stanza): logging.info(u"{0!r} accepted our subscription request".format(stanza.from_jid)) return True @presence_stanza_handler("unsubscribe") def handle_presence_unsubscribe(self, stanza): logging.info(u"{0} canceled presence subscription".format(stanza.from_jid)) presence = Presence(to_jid = stanza.from_jid.bare(), stanza_type = "unsubscribe") return [stanza.make_accept_response(), presence] @presence_stanza_handler("unsubscribed") def handle_presence_unsubscribed(self, stanza): logging.info(u"{0!r} acknowledged our subscrption cancelation".format(stanza.from_jid)) return True # @message_stanza_handler() # def handle_message(self, stanza): # """Echo every non-error ``<message/>`` stanza. # Add "Re: " to subject, if any. # """ # if stanza.subject: # subject = u"Re: " + stanza.subject # else: # subject = None # if stanza.body is None: # txt = None # else: # txt = stanza.body+'!' # msg = Message(stanza_type = stanza.stanza_type, # from_jid = stanza.to_jid, to_jid = stanza.from_jid, # subject = subject, body = txt, # thread = stanza.thread) # return msg @message_stanza_handler() def handle_message(self, stanza): if stanza.stanza_type == 'chat' and not hasattr(stanza, 'processed'): #print stanza stanza.processed = True to_jid = stanza.to_jid.as_unicode() from_jid = stanza.from_jid.as_unicode() im_tcp_tunneler.handle_message(from_jid, to_jid, stanza.body) return True @event_handler(DisconnectedEvent) def handle_disconnected(self, event): """Quit the main loop upon disconnection.""" return QUIT @event_handler() def handle_all(self, event): """Log all events.""" logging.info(u"-- {0}".format(event))
class QXBot(EventHandler, XMPPFeatureHandler): def __init__(self): my_jid = JID(USER+'/Bot') self.my_jid = my_jid settings = XMPPSettings({ "software_name": "qxbot", "software_version": __version__, "software_os": "Linux", "tls_verify_peer": False, "starttls": True, "ipv6":False, "poll_interval": 10, }) settings["password"] = PASSWORD version_provider = VersionProvider(settings) event_queue = settings["event_queue"] self.webqq = WebQQ(QQ, event_queue) self.connected = False #self.mainloop = TornadoMainLoop(settings) self.mainloop = EpollMainLoop(settings) self.client = Client(my_jid, [self, version_provider], settings, self.mainloop) self.logger = get_logger() self.msg_dispatch = MessageDispatch(self, self.webqq, BRIDGES) self.xmpp_msg_queue = Queue.Queue() def run(self, timeout = None): self.client.connect() self.client.run(timeout) def disconnect(self): self.client.disconnect() while True: try: self.run(2) except: pass else: break @presence_stanza_handler("subscribe") def handle_presence_subscribe(self, stanza): self.logger.info(u"{0} join us".format(stanza.from_jid)) return stanza.make_accept_response() @presence_stanza_handler("subscribed") def handle_presence_subscribed(self, stanza): self.logger.info(u"{0!r} accepted our subscription request" .format(stanza.from_jid)) return stanza.make_accept_response() @presence_stanza_handler("unsubscribe") def handle_presence_unsubscribe(self, stanza): self.logger.info(u"{0} canceled presence subscription" .format(stanza.from_jid)) return stanza.make_accept_response() @presence_stanza_handler("unsubscribed") def handle_presence_unsubscribed(self, stanza): self.logger.info(u"{0!r} acknowledged our subscrption cancelation" .format(stanza.from_jid)) @presence_stanza_handler(None) def handle_presence_available(self, stanza): self.logger.info(r"{0} has been online".format(stanza.from_jid)) @presence_stanza_handler("unavailable") def handle_presence_unavailable(self, stanza): self.logger.info(r"{0} has been offline".format(stanza.from_jid)) @message_stanza_handler() def handle_message(self, stanza): if self.webqq.connected: self.msg_dispatch.dispatch_xmpp(stanza) else: self.xmpp_msg_queue.put(stanza) @event_handler(DisconnectedEvent) def handle_disconnected(self, event): return QUIT @event_handler(ConnectedEvent) def handle_connected(self, event): pass @event_handler(RosterReceivedEvent) def handle_roster_received(self, event): """ 此处代表xmpp已经连接 开始连接QQ, 先将检查是否需要验证码的handler加入到mainloop """ checkhandler = CheckHandler(self.webqq) self.mainloop.add_handler(checkhandler) self.connected = True @event_handler(CheckedEvent) def handle_webqq_checked(self, event): """ 第一步已经完毕, 删除掉检查的handler, 将登录前handler加入mainloop""" bloginhandler = BeforeLoginHandler(self.webqq, password = QQ_PWD) self.mainloop.remove_handler(event.handler) self.mainloop.add_handler(bloginhandler) @event_handler(BeforeLoginEvent) def handle_webqq_blogin(self, event): """ 登录前完毕开始真正的登录 """ loginhandler = LoginHandler(self.webqq) self.mainloop.remove_handler(event.handler) self.mainloop.add_handler(loginhandler) @event_handler(WebQQLoginedEvent) def handle_webqq_logined(self, event): """ 登录后将获取群列表的handler放入mainloop """ self.mainloop.remove_handler(event.handler) self.mainloop.add_handler(GroupListHandler(self.webqq)) @event_handler(GroupListEvent) def handle_webqq_group_list(self, event): """ 获取群列表后""" self.mainloop.remove_handler(event.handler) data = event.data group_map = {} if data.get("retcode") == 0: group_list = data.get("result", {}).get("gnamelist", []) for group in group_list: gcode = group.get("code") group_map[gcode] = group self.webqq.group_map = group_map self.webqq.group_lst_updated = False # 开放添加GroupListHandler i = 1 for gcode in group_map: if i == len(group_map): self.mainloop.add_handler( GroupMembersHandler(self.webqq, gcode = gcode, done = True)) else: self.mainloop.add_handler( GroupMembersHandler(self.webqq, gcode = gcode, done = False)) i += 1 @event_handler(GroupMembersEvent) def handle_group_members(self, event): """ 获取所有群成员 """ self.mainloop.remove_handler(event.handler) members = event.data.get("result", {}).get("minfo", []) self.webqq.group_m_map[event.gcode] = {} for m in members: uin = m.get("uin") self.webqq.group_m_map[event.gcode][uin] = m cards = event.data.get("result", {}).get("cards", []) for card in cards: uin = card.get("muin") group_name = card.get("card") self.webqq.group_m_map[event.gcode][uin]["nick"] = group_name # 防止重复添加GroupListHandler if not self.webqq.group_lst_updated: self.webqq.group_lst_updated = True self.mainloop.add_handler(GroupListHandler(self.webqq, delay = 300)) @event_handler(WebQQRosterUpdatedEvent) def handle_webqq_roster(self, event): """ 群成员都获取完毕后开启,Poll获取消息和心跳 """ self.mainloop.remove_handler(event.handler) self.msg_dispatch.get_map() if not self.webqq.polled: self.webqq.polled = True self.mainloop.add_handler(PollHandler(self.webqq)) if not self.webqq.heartbeated: self.webqq.heartbeated = True hb = HeartbeatHandler(self.webqq) self.mainloop.add_handler(hb) while True: try: stanza = self.xmpp_msg_queue.get_nowait() self.msg_dispatch.dispatch_xmpp(stanza) except Queue.Empty: break self.webqq.connected = True @event_handler(WebQQHeartbeatEvent) def handle_webqq_hb(self, event): """ 心跳完毕后, 延迟60秒在此触发此事件 重复心跳 """ self.mainloop.remove_handler(event.handler) self.mainloop.add_handler(HeartbeatHandler(self.webqq, delay = 60)) @event_handler(WebQQPollEvent) def handle_webqq_poll(self, event): """ 延迟1秒重复触发此事件, 轮询获取消息 """ self.mainloop.remove_handler(event.handler) self.mainloop.add_handler(PollHandler(self.webqq)) @event_handler(WebQQMessageEvent) def handle_webqq_msg(self, event): """ 有消息到达, 处理消息 """ self.msg_dispatch.dispatch_qq(event.message) @event_handler(RetryEvent) def handle_retry(self, event): """ 有handler触发异常, 需重试 """ self.mainloop.remove_handler(event.handler) handler = event.cls(self.webqq, event.req, *event.args, **event.kwargs) self.mainloop.add_handler(handler) @event_handler(RemoveEvent) def handle_remove(self, event): """ 触发此事件, 移除handler """ self.mainloop.remove_handler(event.handler) def send_qq_group_msg(self, group_uin, content): """ 发送qq群消息 """ handler = GroupMsgHandler(self.webqq, group_uin = group_uin, content = content) self.mainloop.add_handler(handler) @property def roster(self): return self.client.roster @property def stream(self): return self.client.stream @event_handler() def handle_all(self, event): self.logger.info(u"-- {0}".format(event)) def make_message(self, to, typ, body): """ 构造消息 `to` - 接收人 JID `typ` - 消息类型 `body` - 消息主体 """ if typ not in ['normal', 'chat', 'groupchat', 'headline']: typ = 'chat' m = Message(from_jid = self.my_jid, to_jid = to, stanza_type = typ, body = body) return m def send_msg(self, to, body): if not isinstance(to, JID): to = JID(to) msg = self.make_message(to, 'chat', body) self.stream.send(msg)
class Rodney(EventHandler, XMPPFeatureHandler): """Personal Secretary for facebook chat.""" def __init__(self, my_jid, settings, myname, events, text): version_provider = VersionProvider(settings) self.client = Client(my_jid, [self, version_provider], settings) self.myname = myname # first and last name of user self.logs = {} self.parser = ttp.Parser() # twitter text processing lib handler self.events = events self.do_text = text self.last_msg = "" def run(self): """Request client connection and start the main loop.""" self.client.connect() self.client.run() def disconnect(self): """Request disconnection and let the main loop run for a 2 more seconds for graceful disconnection.""" self.client.disconnect() self.client.run(timeout=2) @presence_stanza_handler("subscribe") def handle_presence_subscribe(self, stanza): logging.info(u"{0} requested presence subscription".format(stanza.from_jid)) presence = Presence(to_jid=stanza.from_jid.bare(), stanza_type="subscribe") return [stanza.make_accept_response(), presence] @presence_stanza_handler("subscribed") def handle_presence_subscribed(self, stanza): logging.info(u"{0!r} accepted our subscription request".format(stanza.from_jid)) return True @presence_stanza_handler("unsubscribe") def handle_presence_unsubscribe(self, stanza): logging.info(u"{0} canceled presence subscription".format(stanza.from_jid)) presence = Presence(to_jid=stanza.from_jid.bare(), stanza_type="unsubscribe") return [stanza.make_accept_response(), presence] @presence_stanza_handler("unsubscribed") def handle_presence_unsubscribed(self, stanza): logging.info(u"{0!r} acknowledged our subscrption cancelation".format(stanza.from_jid)) return True @event_handler(DisconnectedEvent) def handle_disconnected(self, event): endtime = int(time.time()) filename = "rodney.{0}.log".format(endtime) f = open(filename, "w") from pprint import PrettyPrinter pp = PrettyPrinter(depth=10, stream=f) pp.pprint(self.logs) print "My transcript has been written to {0}".format(filename) """Quit the main loop upon disconnection.""" return QUIT @event_handler() def handle_all(self, event): """Log all events.""" logging.info(u"-- {0}".format(event)) @event_handler(RosterReceivedEvent) def handle_roster_received(self, event): self.roster_items = self.client.roster.items() print type(self.roster_items) print "Roster received!" @message_stanza_handler() def handle_message(self, stanza): """ Does message dispatching: 1) Checks when you're free on calendar 2) Sends you a text 3) Playful responses """ if stanza.body is None: print stanza elif stanza.body == self.last_msg: print "bad" return else: self.last_msg = stanza.body parsed = self.parser.parse(stanza.body) sender = (i for i in self.roster_items if i.jid == stanza.from_jid).next() if sender.name not in self.logs.keys(): self.logs[sender.name] = [] if sender == None: print "no name found, making it fuzz" name = "fuzz" else: name = sender.name print "{0} sent the message: {1}".format(name, stanza.body) inmsg = stanza.body.lower() if len(self.logs[name]) == 0 or "help" in parsed.tags: res = " ".join( [ "Hi there! I'm Rodney, the personal fbchat secretary. {0}'s not around right now, can I help you with anything?".format( self.myname ), "\n 1) When is he free? (the question or '#free')", "\n 2) Text him. ('#text message')", "\n 3) #random", "#help", ] ) else: if "free" in parsed.tags or ("when" in inmsg and "free" in inmsg): res = " ".join([word for word in stanza.body.split() if not word == "#free"]) res += "?\n" res += check_gcal(self.events).format(self.myname.split()[0]) elif "text" in parsed.tags: if not self.do_text: res = "Sorry, texting is disabled for now ({0} is really cheap!)".format(self.myname.split()[0]) elif inmsg.strip() == "#text": res = "Don't send an empty message! The texting costs come out of my salary :(" else: out = " ".join([w for w in stanza.body.split() if not w == "#text"]) outmsg = send_text(out, name) res = "Ok! I sent the message: {0} to {1}".format(outmsg, self.myname.split()[0]) elif "random" in parsed.tags: # corpus from nltk res = "coming soon...." else: res = lolz(stanza.body) msg = Message( stanza_type=stanza.stanza_type, from_jid=stanza.to_jid, to_jid=stanza.from_jid, body=res, thread=stanza.thread, ) self.logs[name].append(time.asctime() + " {0}: ".format(name) + stanza.body) self.logs[name].append(time.asctime() + " {0}: ".format(self.myname) + res) return msg
def __init__(self, my_jid, args, settings): self.args = args self.client = Client(my_jid, [self], settings) self.presence = defaultdict(dict)
class Talkbot(DB_oper, EventHandler, XMPPFeatureHandler, Messages, Command): def __init__(self, jid, settings): self.client = Client(JID(jid), [self], settings) def run_bot(self): self.client.connect() self.client.run() def stop_bot(self): self.client.disconnect() @event_handler(DisconnectedEvent) def handle_disconnect(self, event): return QUIT @event_handler() def handle_all(self, event): logging.info(u"--{0}".format(event)) @message_stanza_handler() def handle_message(self, stanza): if stanza.stanza_type != 'chat': return True current_jid = stanza.from_jid body = stanza.body if body[0] == '-': logging.info(u"handle command which is {0}".format(body)) command = body.split(' ')[0] print 'in main command is %s' % (command) self.dispatch_command(command, stanza) logging.info(u"handle command which is {0} done".format(body)) else: logging.info(u"handle common message which is {0}".format(body)) self.dispatch_message(stanza.body, current_jid.bare()) logging.info( u"handle common message whcih is {0} done".format(body)) return True @presence_stanza_handler("subscribe") def handle_subscribe(self, stanza): logging.info(u"{0} request presence subscripiton ".format( stanza.from_jid)) sender = stanza.from_jid bare_jid = sender.bare().as_string() self.add_user(bare_jid) presence = Presence(to_jid=stanza.from_jid.bare(), stanza_type="subscribe") return [stanza.make_accept_response(), presence] def get_online_users(self): users = [x.jid for x in self.client.roster if x.subscription == 'both'] print self.client.roster return users def send_message(self, receiver, msg): if isinstance(receiver, str): receiver = JID(receiver) message = Message( stanza_type='chat', from_jid=self.client.jid, to_jid=receiver, body=msg, ) self.send(message) def send(self, stanza): self.client.stream.send(stanza) def do_unsubscribe(self, jid, type='unsubscribe'): jid = JID(jid) presence = Presence(to_jid=jid, stanza_type=type) self.send(presence) def delete_from_roster(self, jid): self.client.roster.delItem(jid)
class BotChat(EventHandler, XMPPFeatureHandler): trytimes = 0 def __init__(self): my_jid = JID(USER + '/Bot') self.my_jid = my_jid settings = XMPPSettings({ "software_name": "Clubot", "software_version": __version__, "software_os": "Linux", "tls_verify_peer": False, "starttls": True, "ipv6": False, "poll_interval": 10, }) settings["password"] = PASSWORD version_provider = VersionProvider(settings) self.connected = False mainloop = TornadoMainLoop(settings) self.client = Client(my_jid, [self, version_provider], settings, mainloop) #self.client = Client(my_jid, [self, version_provider], settings) self.logger = get_logger() self.trytimes = 0 self.sended = [] Logics.empty_status() def run(self, timeout=None): self.client.connect() self.client.run(timeout) def disconnect(self): self.client.disconnect() @presence_stanza_handler("subscribe") def handle_presence_subscribe(self, stanza): self.logger.info(u"{0} join us".format(stanza.from_jid)) frm = stanza.from_jid presence = Presence(to_jid=frm, stanza_type="subscribe") Logics.add(frm, None, stanza.show) r = [stanza.make_accept_response(), presence] if frm not in self.sended: self.message_bus.send_sys_msg(stanza, new_member(frm)) self.message_bus.send_back_msg(stanza, welcome(frm)) self.sended.append(frm) return r @presence_stanza_handler("subscribed") def handle_presence_subscribed(self, stanza): self.logger.info(u"{0!r} accepted our subscription request".format( stanza.from_jid)) frm = stanza.from_jid presence = Presence(to_jid=frm, stanza_type="subscribe") Logics.add(frm, None, stanza.show) r = [presence] r = [stanza.make_accept_response(), presence] if frm not in self.sended: self.message_bus.send_sys_msg(stanza, new_member(frm)) self.message_bus.send_back_msg(stanza, welcome(frm)) self.sended.append(frm) return r @presence_stanza_handler("unsubscribe") def handle_presence_unsubscribe(self, stanza): self.logger.info(u"{0} canceled presence subscription".format( stanza.from_jid)) presence = Presence(to_jid=stanza.from_jid.bare(), stanza_type="unsubscribe") nick = Logics.get_one(stanza.from_jid).nick self.message_bus.send_sys_msg(stanza, u'{0} 离开群'.format(nick)) Logics.drop(stanza.from_jid.bare()) r = [stanza.make_accept_response(), presence] return r @presence_stanza_handler("unsubscribed") def handle_presence_unsubscribed(self, stanza): self.logger.info( u"{0!r} acknowledged our subscrption cancelation".format( stanza.from_jid)) Logics.drop(stanza.from_jid.bare()) return True @presence_stanza_handler(None) def handle_presence_available(self, stanza): self.logger.info(r"{0} has been online".format(stanza.from_jid)) if stanza.from_jid.bare().as_string() != USER: Logics.set_online(stanza.from_jid, stanza.show) self.message_bus.send_offline_message(stanza) @presence_stanza_handler("unavailable") def handle_presence_unavailable(self, stanza): self.logger.info(r"{0} has been offline".format(stanza.from_jid)) frm = stanza.from_jid if frm.bare().as_string() == USER: self.logger.info('bot go to offline') self.disconnect() Logics.set_offline(frm) @message_stanza_handler() def handle_message(self, stanza): body = stanza.body frm = stanza.from_jid.bare().as_string() if not body: return True self.logger.info("receive message '{0}' from {1}".format( body, stanza.from_jid)) if body.startswith('$') or body.startswith('-'): self.message_bus.send_command(stanza, body) #elif body.startswith('<') and frm == BRIDGE: # self.message_bus.send_qq_msg(stanza, body) else: self.message_bus.send_all_msg(stanza, body) return True @event_handler(DisconnectedEvent) def handle_disconnected(self, event): return QUIT @event_handler(ConnectedEvent) def handle_connected(self, event): self.message_bus = MessageBus(self.my_jid, self.stream) self.connected = True BotChat.trytimes = 0 @property def roster(self): return self.client.roster @property def stream(self): return self.client.stream def invite_member(self, jid): logging.info('invite {0}'.format(jid)) p1 = Presence(from_jid=self.my_jid, to_jid=jid, stanza_type='subscribe') p = Presence(from_jid=self.my_jid, to_jid=jid, stanza_type='subscribed') self.stream.send(p) self.stream.send(p1) @event_handler(RosterUpdatedEvent) def handle_roster_update(self, event): item = event.item @event_handler(RosterReceivedEvent) def handle_roster_received(self, event): dbstatus = Logics.get_global_info('status').value if not dbstatus: status = STATUS else: status = dbstatus p = Presence(status=status) self.client.stream.send(p) ret = [x.jid.bare() for x in self.roster if x.subscription == 'both'] self.logger.info(' -- roster:{0}'.format(ret)) members = Logics.get_members() members = [m.email for m in members] [Logics.add(frm) for frm in ret if not Logics.get_one(frm)] if IMPORT: [self.invite_member(JID(m)) for m in members if JID(m) not in ret] #else: #[del_member(JID(m)) for m in members if JID(m) not in ret] @event_handler() def handle_all(self, event): self.logger.info(u"-- {0}".format(event))
class transmissionRobot(EventHandler, XMPPFeatureHandler, TimeoutHandler): userlist={}; lastcycle={}; def __init__(self, my_jid, settings): version_provider = VersionProvider(settings) self.client = Client(my_jid, [self, version_provider], settings) self.rpc=transmissionrpc.Client(TRANSURL,TRANSPORT,TRANSUSER,TRANSPASS) for user in SUBSCRIBERS: self.userlist[JID(user).local]=JID(user) def run(self): """Request client connection and start the main loop.""" self.client.connect() self.client.run() def disconnect(self): """Request disconnection and let the main loop run for a 2 more seconds for graceful disconnection.""" self.client.disconnect() self.client.run(timeout = 2) @presence_stanza_handler("subscribe") def handle_presence_subscribe(self, stanza): logging.info(u"{0} requested presence subscription" .format(stanza.from_jid)) presence = Presence(to_jid = stanza.from_jid.bare(), stanza_type = "subscribe") return [stanza.make_accept_response(), presence] @presence_stanza_handler("subscribed") def handle_presence_subscribed(self, stanza): logging.info(u"{0!r} accepted our subscription request" .format(stanza.from_jid)) return True @presence_stanza_handler("unsubscribe") def handle_presence_unsubscribe(self, stanza): logging.info(u"{0} canceled presence subscription" .format(stanza.from_jid)) presence = Presence(to_jid = stanza.from_jid.bare(), stanza_type = "unsubscribe") return [stanza.make_accept_response(), presence] @presence_stanza_handler("unsubscribed") def handle_presence_unsubscribed(self, stanza): logging.info(u"{0!r} acknowledged our subscrption cancelation" .format(stanza.from_jid)) return True @message_stanza_handler() def handle_message(self, stanza): messagebody='Robot connected.' if stanza.body=="connect": if not stanza.from_jid.local in self.userlist: self.userlist[stanza.from_jid.local]=stanza.from_jid; else: messagebody="Already connected." msg = Message(stanza_type = stanza.stanza_type, from_jid = self.client.jid, to_jid = stanza.from_jid, subject = None, body = messagebody, thread = stanza.thread) return msg elif stanza.body=="disconnect": messagebody="Robot disconnected." try: del self.userlist[stanza.from_jid.local]; except: messagebody="Already disconnected" msg = Message(stanza_type = stanza.stanza_type, from_jid = self.client.jid, to_jid = stanza.from_jid, subject = None, body = messagebody, thread = stanza.thread) return msg if stanza.from_jid.local+'@'+stanza.from_jid.domain in SUBSCRIBERS: try: #print stanza.body torrent=self.rpc.add_torrent(stanza.body,timeout=10) except: return True messagebody="Torrent added: "+str(torrent) msg = Message(stanza_type = stanza.stanza_type, from_jid = self.client.jid, to_jid = stanza.from_jid, subject = None, body = messagebody, thread = stanza.thread) return msg return True @event_handler(DisconnectedEvent) def handle_disconnected(self, event): """Quit the main loop upon disconnection.""" return QUIT @event_handler() def handle_all(self, event): """Log all events.""" logging.info(u"-- {0}".format(event)) @timeout_handler(3,True) def handle_transmission_query(self): print "Checking transmission daemon." torrentlist=self.rpc.get_torrents() for torrent in torrentlist: if torrent.doneDate>0 and torrent.hashString in self.lastcycle: del self.lastcycle[torrent.hashString] messagebody="Torrent finished: "+ torrent.name + ". https://cloud.xiw.im/index.php/apps/files?dir=/Transmission" print messagebody for i in self.userlist: msg = Message(stanza_type = "normal", from_jid = self.client.jid, to_jid = self.userlist[i], subject = None, body = messagebody, thread = None) self.client.send(msg) elif torrent.doneDate<=0 and not torrent.hashString in self.lastcycle: self.lastcycle[torrent.hashString]=1 return 3
# (4) XMPPのメッセージを受信したときの処理を記述 @message_stanza_handler() def handle_message(self, stanza): # (4-1)メッセージのタイトルを設定 if stanza.subject: subject = "Re: " + stanza.subject else: subject = None if stanza.body: # (4-2)メッセージの本文の作成 body = 'You said "' + stanza.body + '".' # (5) メッセージオブジェクトの作成 msg = Message(stanza_type=stanza.stanza_type, from_jid=stanza.to_jid, to_jid=stanza.from_jid, subject=subject, body=body, thread=stanza.thread) return msg # (6) XMPPの初期化とイベントループ jid = sys.argv[1] password = sys.argv[2] settings = XMPPSettings({"password": password}) client = Client(JID(jid), [EchoBotHandler()], settings) client.connect() client.run()
class VersionChecker(EventHandler): """Version checker implementation.""" def __init__(self, my_jid, target_jid, settings): self.client = Client(my_jid, [self], settings) self.target_jid = target_jid def run(self): """Request client connection and start the main loop.""" self.client.connect() self.client.run() def disconnect(self): """Request disconnection and let the main loop run for a 2 more seconds for graceful disconnection.""" self.client.disconnect() self.client.run(timeout=2) @event_handler(AuthorizedEvent) def handle_authorized(self, event): """Send the initial presence after log-in.""" request_software_version(self.client, self.target_jid, self.success, self.failure) def success(self, version): print("Name: {0}".format(version.name)) print("Version: {0}".format(version.version)) if version.os_name is not None: print("Operating System: {0}".format(version.os_name)) else: print("Operating System name not available") self.client.disconnect() def failure(self, stanza): print("Version query failed") if stanza and stanza.stanza_type == "error": cond_name = stanza.error.condition_name text = stanza.error.text if text: print("Error: {0} ({1})".format(cond_name, text)) else: print("Error: {0}".format(cond_name)) self.client.disconnect() @event_handler(DisconnectedEvent) def handle_disconnected(self, event): """Quit the main loop upon disconnection.""" return QUIT
def __init__(self, my_jid, target_jid, settings): self.client = Client(my_jid, [self], settings) self.target_jid = target_jid
class Talkbot(DB_oper,EventHandler,XMPPFeatureHandler,Messages,Command): def __init__(self,jid,settings): self.client = Client(JID(jid),[self],settings) def run_bot(self): self.client.connect() self.client.run() def stop_bot(self): self.client.disconnect() @event_handler(DisconnectedEvent) def handle_disconnect(self,event): return QUIT @event_handler() def handle_all(self,event): logging.info(u"--{0}".format(event)) @message_stanza_handler() def handle_message(self,stanza): if stanza.stanza_type!='chat': return True current_jid = stanza.from_jid body = stanza.body if body[0]=='-': logging.info(u"handle command which is {0}".format(body)) command = body.split(' ')[0] print 'in main command is %s' % (command) self.dispatch_command(command,stanza) logging.info(u"handle command which is {0} done".format(body)) else: logging.info(u"handle common message which is {0}".format(body)) self.dispatch_message(stanza.body,current_jid.bare()) logging.info(u"handle common message whcih is {0} done".format(body)) return True @presence_stanza_handler("subscribe") def handle_subscribe(self,stanza): logging.info(u"{0} request presence subscripiton ".format(stanza.from_jid)) sender = stanza.from_jid bare_jid = sender.bare().as_string() self.add_user(bare_jid) presence = Presence(to_jid=stanza.from_jid.bare(),stanza_type="subscribe") return [stanza.make_accept_response(),presence] def get_online_users(self): users = [x.jid for x in self.client.roster if x.subscription=='both'] print self.client.roster return users def send_message(self,receiver,msg): if isinstance(receiver,str): receiver=JID(receiver) message = Message( stanza_type='chat', from_jid = self.client.jid, to_jid = receiver, body = msg,) self.send(message) def send(self,stanza): self.client.stream.send(stanza) def do_unsubscribe(self,jid,type = 'unsubscribe'): jid = JID(jid) presence = Presence(to_jid=jid,stanza_type=type) self.send(presence) def delete_from_roster(self,jid): self.client.roster.delItem(jid)
def __init__(self, jid, settings): self.client = Client(JID(jid), [self], settings)
class XMPPBot(EventHandler, XMPPFeatureHandler): autoReconnect = False def __init__(self, my_jid, settings, autoReconnect=None, main_loop=None): self.jid = my_jid self.settings = settings if autoReconnect is not None: self.autoReconnect = autoReconnect self.do_quit = False self.main_loop = main_loop def newclient(self): version_provider = VersionProvider(self.settings) self.client = Client( self.jid, [self, version_provider], self.settings, main_loop=self.main_loop, ) def start(self): while not self.do_quit: logging.info('XMPP connecting...') self.connect() self.run() if not self.autoReconnect: self.do_quit = True def connect(self): self.newclient() self.client.connect() def run(self): self.client.run() def disconnect(self): self.do_quit = True self.client.disconnect() try: self.client.run(timeout=2) except RuntimeError: # IOLoop is already running pass @property def roster(self): return self.client.roster @message_stanza_handler() def handle_message(self, stanza): if stanza.stanza_type and stanza.stanza_type.endswith('chat') and stanza.body: logging.info("%s said: %s", stanza.from_jid, stanza.body) self.last_chat_message = stanza else: logging.info("%s message: %s", stanza.from_jid, stanza.serialize()) return True def send_message(self, receiver, msg): m = Message( stanza_type = 'chat', from_jid = self.client.jid, to_jid = receiver, body = msg, ) self.send(m) def send(self, stanza): self.client.stream.send(stanza) def delayed_call(self, seconds, func, *args, **kwargs): self.client.main_loop.delayed_call(seconds, partial(func, *args, **kwargs)) def get_vcard(self, jid, callback): '''callback is used as both result handler and error handler''' q = Iq( to_jid = jid.bare(), stanza_type = 'get' ) vc = ET.Element("{vcard-temp}vCard") q.add_payload(vc) self.stanza_processor.set_response_handlers(q, callback, callback) self.send(q) def update_roster(self, jid, name=NO_CHANGE, groups=NO_CHANGE): self.client.roster_client.update_item(jid, name, groups) @presence_stanza_handler() def handle_presence_available(self, stanza): logging.info('%s[%s]', stanza.from_jid, stanza.show or 'available') return True @event_handler(DisconnectedEvent) def handle_disconnected(self, event): if self.do_quit: return QUIT else: logging.warn('XMPP disconnected. Reconnecting...') # We can't restart here because the stack will overflow return True @event_handler() def handle_all(self, event): """Log all events.""" logging.info("-- {0}".format(event))
class ChatBot(MessageMixin, UserMixin, EventHandler, XMPPFeatureHandler): got_roster = False message_queue = None receipt_sender = None ignore = set() def __init__(self, jid, settings, botsettings=None): if 'software_name' not in settings: settings['software_name'] = self.__class__.__name__ if 'software_version' not in settings: settings['software_version'] = __version__ version_provider = VersionProvider(settings) handlers = [] if ReceiptSender: self.receipt_sender = rs = ReceiptSender() handlers.append(rs) handlers.extend([self, version_provider]) self.client = Client(jid, handlers, settings) self.presence = defaultdict(dict) self.subscribes = ExpiringDictionary(default_timeout=5) self.invited = {} self.avatar_hash = None self.settings = botsettings def run(self): self.client.connect() self.jid = self.client.jid.bare() logger.info('self jid: %r', self.jid) self.update_on_setstatus = set() if self.receipt_sender: self.receipt_sender.stream = self.client.stream self.client.run() def disconnect(self): '''Request disconnection and let the main loop run for a 2 more seconds for graceful disconnection.''' self.client.disconnect() while True: try: self.client.run(timeout=2) except pyxmpp2.exceptions.StreamParseError: # we raise SystemExit to exit, expat says XML_ERROR_FINISHED pass else: break def handle_early_message(self): self.got_roster = True q = self.message_queue if q: self.now = datetime.datetime.utcnow() for sender, stanza in q: self.current_jid = sender self._cached_jid = None try: timestamp = stanza.as_xml().find( '{urn:xmpp:delay}delay').attrib['stamp'] except AttributeError: timestamp = None self.handle_message(stanza.body, timestamp) self.message_queue = self.__class__.message_queue = None @event_handler(RosterReceivedEvent) def roster_received(self, stanze): self.delayed_call(2, self.handle_early_message) self.delayed_call(getattr(config, 'reconnect_timeout', 24 * 3600), self.signal_connect) nick, avatar_type, avatar_file = (getattr(config, x, None) for x in ('nick', 'avatar_type', 'avatar_file')) if nick or (avatar_type and avatar_file): self.set_vcard(nick, (avatar_type, avatar_file)) return True def signal_connect(self): logging.info('Schedule to re-connecting...') self.client.disconnect() @message_stanza_handler() def message_received(self, stanza): if stanza.stanza_type != 'chat': return True if not stanza.body: logging.info("%s message: %s", stanza.from_jid, stanza.serialize()) return True sender = stanza.from_jid body = stanza.body self.current_jid = sender self.now = datetime.datetime.utcnow() logging.info('[%s] %s', sender, stanza.body) if str(sender.bare()) in self.ignore: logging.info('(The above message is ignored on purpose)') return True if not self.got_roster: if not self.message_queue: self.message_queue = [] self.message_queue.append((sender, stanza)) else: self.handle_message(body) logging.info('done with new message') return True def send_message(self, receiver, msg): if isinstance(receiver, str): receiver = JID(receiver) m = Message( stanza_type='chat', from_jid=self.jid, to_jid=receiver, body=msg, ) self.send(m) def reply(self, msg): self.send_message(self.current_jid, msg) def send(self, stanza): self.client.stream.send(stanza) def delayed_call(self, seconds, func, *args, **kwargs): self.client.main_loop.delayed_call(seconds, partial(func, *args, **kwargs)) @event_handler(DisconnectedEvent) def handle_disconnected(self, event): return QUIT @property def roster(self): return self.client.roster def get_online_users(self): ret = [x.jid for x in self.roster if x.subscription == 'both' and \ str(x.jid) in self.presence] logging.info('%d online buddies: %r', len(ret), ret) return ret def get_xmpp_status(self, jid): return sorted(self.presence[str(jid)].values(), key=lambda x: x['priority'], reverse=True)[0] def xmpp_setstatus(self, status, to_jid=None): if isinstance(to_jid, str): to_jid = JID(to_jid) presence = Presence(status=status, to_jid=to_jid) self.send(presence) def update_roster(self, jid, name=NO_CHANGE, groups=NO_CHANGE): self.client.roster_client.update_item(jid, name, groups) def removeInvitation(self): for ri in self.roster.values(): if ri.ask is not None: self.client.roster_client.remove_item(ri.jid) logging.info('%s removed', ri.jid) def unsubscribe(self, jid, type='unsubscribe'): presence = Presence(to_jid=jid, stanza_type=type) self.send(presence) def subscribe(self, jid): self.invited[jid] = 2 presence = Presence(to_jid=jid, stanza_type='subscribe') self.send(presence) @presence_stanza_handler('subscribe') def handle_presence_subscribe(self, stanza): logging.info('%s subscribe', stanza.from_jid) sender = stanza.from_jid bare = sender.bare() # avoid repeated request invited = False if bare not in self.subscribes: invited = self.invited.get(bare, False) if invited is not False: if invited == 2: self.invited[bare] = 1 else: del self.invited[bare] return stanza.make_accept_response() # We won't deny inivted members self.handle_userjoin_before() else: if config.private and str(bare) != config.root: self.send_message( sender, _('Sorry, this is a private group, and you are not invited.' )) return stanza.make_deny_response() if not self.handle_userjoin_before(): return stanza.make_deny_response() self.current_jid = sender self.now = datetime.datetime.utcnow() try: self.handle_userjoin(action=stanza.stanza_type) except ValidationError: #The server is subscribing pass self.subscribes[bare] = True if stanza.stanza_type.endswith('ed'): return stanza.make_accept_response() if invited is False: presence = Presence(to_jid=stanza.from_jid.bare(), stanza_type='subscribe') return [stanza.make_accept_response(), presence] @presence_stanza_handler('subscribed') def handle_presence_subscribed(self, stanza): # use the same function logging.info('%s subscribed', stanza.from_jid) return self.handle_presence_subscribe(stanza) @presence_stanza_handler('unsubscribe') def handle_presence_unsubscribe(self, stanza): logging.info('%s unsubscribe', stanza.from_jid) sender = stanza.from_jid self.current_jid = sender self.now = datetime.datetime.utcnow() self.handle_userleave(action=stanza.stanza_type) if stanza.stanza_type.endswith('ed'): return stanza.make_accept_response() presence = Presence(to_jid=stanza.from_jid.bare(), stanza_type='unsubscribe') return [stanza.make_accept_response(), presence] @presence_stanza_handler('unsubscribed') def handle_presence_unsubscribed(self, stanza): # use the same function logging.info('%s unsubscribed', stanza.from_jid) return self.handle_presence_unsubscribe(stanza) @presence_stanza_handler() def handle_presence_available(self, stanza): if stanza.stanza_type not in ('available', None): return False jid = stanza.from_jid plainjid = str(jid.bare()) if plainjid == str(self.jid): return self.now = datetime.datetime.utcnow() if plainjid not in self.presence: type = 'new' self.current_jid = jid self.user_update_presence(plainjid) if conn_lost_interval and self.current_user.last_seen and \ self.now - self.current_user.last_seen < conn_lost_interval: type = 'reconnect' self.send_lost_message() logging.info('%s[%s] (%s)', jid, stanza.show or 'available', type) else: if jid.resource not in self.presence[plainjid]: self.user_update_presence(plainjid) logging.info('%s[%s]', jid, stanza.show or 'available') self.presence[plainjid][jid.resource] = { 'show': stanza.show, 'status': stanza.status, 'priority': stanza.priority, } if self.get_user_by_jid(plainjid) is None: try: self.current_jid = jid self.handle_userjoin() except ValidationError: #The server is subscribing pass if config.warnv105 and jid.resource and \ jid.resource.startswith('Talk.') and not jid.resource.startswith('Talk.v104'): # Got a Talk.v107... # No need to translate; GTalk only has a v105 for Chinese. self.send_message( jid, '警告:你正在使用的可能是不加密的 GTalk v105 版本。网络上的其它人可能会截获您的消息。这样不安全!请使用 GTalk v104 英文版或者其它 XMPP 客户端。\nGTalk 英文版: http://www.google.com/talk/index.html\nPidgin: http://www.pidgin.im/' ) return True @presence_stanza_handler('unavailable') def handle_presence_unavailable(self, stanza): jid = stanza.from_jid plainjid = str(jid.bare()) if plainjid in self.presence and plainjid != str(self.jid): try: del self.presence[plainjid][jid.resource] except KeyError: pass if self.presence[plainjid]: logging.info('%s[unavailable] (partly)', jid) else: del self.presence[plainjid] self.now = datetime.datetime.utcnow() self.user_disappeared(plainjid) logging.info('%s[unavailable] (totally)', jid) return True @event_handler() def handle_all(self, event): '''Log all events.''' logging.info('-- {0}'.format(event)) def get_name(self, jid): if isinstance(jid, str): jid = JID(jid) else: jid = jid.bare() try: return self.roster[jid].name or hashjid(jid) except KeyError: return hashjid(jid) def get_vcard(self, jid=None, callback=None): '''callback is used as both result handler and error handler''' q = Iq( to_jid=jid and jid.bare(), stanza_type='get', ) vc = ET.Element("{vcard-temp}vCard") q.add_payload(vc) if callback: self.stanza_processor.set_response_handlers(q, callback, callback) self.send(q) def set_vcard(self, nick=None, avatar=None): self.get_vcard(callback=partial(self._set_vcard, nick, avatar)) def _set_vcard(self, nick=None, avatar=None, stanza=None): #FIXME: This doesn't seem to work with jabber.org q = Iq( from_jid=self.jid, stanza_type='set', ) vc = ET.Element("{vcard-temp}vCard") if nick is not None: n = ET.SubElement(vc, '{vcard-temp}FN') n.text = nick if avatar is not None: type, picfile = avatar photo = ET.SubElement(vc, '{vcard-temp}PHOTO') t = ET.SubElement(photo, '{vcard-temp}TYPE') t.text = type d = ET.SubElement(photo, '{vcard-temp}BINVAL') data = open(picfile, 'rb').read() d.text = base64.b64encode(data).decode('ascii') self.avatar_hash = hashlib.new('sha1', data).hexdigest() q.add_payload(vc) self.stanza_processor.set_response_handlers(q, self._set_vcard_callback, self._set_vcard_callback) self.send(q) def _set_vcard_callback(self, stanza): if stanza.stanza_type == 'error': logging.error('failed to set my vCard.') else: logging.info('my vCard set.') self.update_presence() def update_presence(self): #TODO: update for individual users presence = self.settings['presence'] x = ET.Element('{vcard-temp:x:update}x') if self.avatar_hash: photo = ET.SubElement(x, '{vcard-temp:x:update}photo') photo.text = self.avatar_hash presence.add_payload(x) self.send(presence)
class VersionChecker(EventHandler): """Version checker implementation.""" def __init__(self, my_jid, target_jid, settings): self.client = Client(my_jid, [self], settings) self.target_jid = target_jid def run(self): """Request client connection and start the main loop.""" self.client.connect() self.client.run() def disconnect(self): """Request disconnection and let the main loop run for a 2 more seconds for graceful disconnection.""" self.client.disconnect() self.client.run(timeout = 2) @event_handler(AuthorizedEvent) def handle_authorized(self, event): """Send the initial presence after log-in.""" request_software_version(self.client, self.target_jid, self.success, self.failure) def success(self, version): print("Name: {0}".format(version.name)) print("Version: {0}".format(version.version)) if version.os_name is not None: print("Operating System: {0}".format(version.os_name)) else: print("Operating System name not available") self.client.disconnect() def failure(self, stanza): print("Version query failed") if stanza and stanza.stanza_type == "error": cond_name = stanza.error.condition_name text = stanza.error.text if text: print("Error: {0} ({1})".format(cond_name, text)) else: print("Error: {0}".format(cond_name)) self.client.disconnect() @event_handler(DisconnectedEvent) def handle_disconnected(self, event): """Quit the main loop upon disconnection.""" return QUIT
def __init__(self, my_jid, settings): version_provider = VersionProvider(settings) self.client = Client(my_jid, [self, version_provider], settings)
def __init__(self,jid,settings): self.client = Client(JID(jid),[self],settings)
class XmppClient(EventHandler): """ A client to manage the XMPP connection and dispatch messages. """ NAME = "Review Board XMPP Notification Client" VERSION = 0.1 def __init__(self, host, port, timeout, from_jid, password, use_tls, tls_verify_peer): self.host = host self.port = port self.timeout = timeout or 5 self.from_jid = from_jid self.password = password self.use_tls = use_tls self.tls_verify_peer = tls_verify_peer self.req_id = None self.client = None self.stanzas = None @event_handler(AuthorizedEvent) def handle_authorized(self, event): logging.debug( u"XmppClient event handler for request #%s authorized: %s", self.req_id, event) if self.client.stream != event.stream: logging.debug(u"XmppClient event handler ignore event") return for stanza in self.stanzas: logging.debug("XmppHandler for request #%s send message to %s", self.req_id, stanza.as_xml()) event.stream.send(stanza) logging.debug(u"XmppHandler disconnecting stream for request #%s", self.req_id) self.client.disconnect() @event_handler(DisconnectedEvent) def handle_disconnected(self, event): logging.debug( "XmppClient event handler for request #%s disconnected: %s", self.req_id, event) if self.client.stream != event.stream: logging.debug(u"XmppClient event handler ignore event") return logging.debug( u"XmppClient event handler closing stream for request #%s", self.req_id) self.client.close_stream() self.client = None return QUIT @event_handler() def handle_all(self, event): logging.debug(u"XmppClient event handler for request #%s: %s", self.req_id, event) def send(self, req_id, stanzas): self.req_id = req_id self.stanzas = stanzas logging.debug(u"XmppClient start sending messages for request #%s", self.req_id) try: settings = XMPPSettings({ u"password": self.password, u"starttls": self.use_tls, u"tls_verify_peer": self.tls_verify_peer, u"server": self.host, u"port": self.port, u"default_stanza_timeout": self.timeout, }) self.client = Client(self.from_jid, [self], settings) self.client.connect() self.client.run(timeout=self.timeout) except Exception, e: logging.error( "Error sending XMPP notification for request #%s: %s", req_id, e, exc_info=1)
class XMPPClient(EventHandler, XMPPFeatureHandler): """ xmpp 客户端 """ def __init__(self): self.subject_to_fun_dic = {} self.xmpp_client = None self.is_auth = False self.protocol = PT_XMPP self.jid_bare_str = None def init(self, jid, password, c2s_port=5222): """ 初始化 :param jid: jid :param password: 密码 :return: """ self.JID = jid if isinstance(jid, JID) else JID(jid) self.jid_bare_str = self.JID.bare().as_string() self.password = password self.settings = XMPPSettings({ u"password": password, u"starttls": True, u"tls_verify_peer": False, u"c2s_port": c2s_port }) if c2s_port != 5222: logger.warn("XMPPClient::init c2s_port is :%s!!!!!" % c2s_port) @gevent_adaptor(use_join_result=False) def start(self): """ 服务开始 :return: """ logger.warn("XMPPClient::start listen on %s:%s:%s" % (self.protocol, self.JID, self.password)) self.xmpp_client = Client(self.JID, [self], self.settings) self.xmpp_client.connect() self.xmpp_client.run() self.is_auth = False def stop(self): """ Request disconnection and let the main loop run for a 2 more seconds for graceful disconnection. """ logger.warn("XMPPClient::stop listen on %s:%s:%s" % (self.protocol, self.JID, self.password)) assert self.xmpp_client self.xmpp_client.disconnect() self.xmpp_client.run(timeout=2) self.is_auth = False def restart(self): """ 服务重启 :return: """ logger.warn("XMPPClient::restart listen on %s:%s:%s" % (self.protocol, self.JID, self.password)) self.stop() self.start() @xmpp_send_adaptor() def _send(self, tgt_jid, subject, body): """ 发送消息 :param tgt_jid:目的jid :param subject: 主题 :param body: 文本 :return: """ if not self.xmpp_client.stream: self.restart() self.wait_for_auth() tgt_jid = tgt_jid if isinstance(tgt_jid, JID) else JID(tgt_jid) msg = Message(to_jid=tgt_jid, body=body, subject=subject, stanza_type="normal") # _send与send的区别,send的锁有点奇怪,有时候会卡主,暂时不用锁 # def send(self, stanza): # """Write stanza to the stream. # # :Parameters: # - `stanza`: XMPP stanza to send. # :Types: # - `stanza`: `pyxmpp2.stanza.Stanza` # """ # with self.lock: # return self._send(stanza) self.xmpp_client.stream._send(msg) logger.info("XMPPClient::_send, src_jid:%s ,src_pass:%s, des_jid:%s, subject:%s, body:%s" %\ (self.JID,self.password, tgt_jid, subject, body)) @gevent_adaptor() def send_async(self, sto_jid, ssubject, sbody): """ 协程非阻塞发送 :param sto_jid: :param ssubject: :param sbody: :return: """ self._send(sto_jid, ssubject, sbody) def send_sync(self, sto_jid, ssubject, sbody): """ 阻塞发送 :param sto_jid: :param ssubject: :param sbody: :return: """ self._send(sto_jid, ssubject, sbody) @event_handler(ConnectingEvent) def handle_connected(self, event): """ XMPP 连接成功 :param event: :return: """ pass @event_handler(DisconnectedEvent) def handle_disconnected(self, event): """ XMPP 断开连接 :param event: :return: """ """Quit the main loop upon disconnection.""" logger.error("XMPPClient::handle_disconnected: JID:%s!!! event:%s" % (self.JID, event)) return QUIT @event_handler(AuthorizedEvent) def handle_authorized(self, event): """ OPENFIRE 授权成功 :param event: :return: """ logger.info("XMPPClient::handle_authorized: JID:%s!!!" % self.JID) self.is_auth = True @event_handler(RosterReceivedEvent) def handle_roster_received(self, event): """ XMPP 接收到roster列表 :param event: :return: """ return True @event_handler(RosterUpdatedEvent) def handle_roster_update(self, event): """ XMPP 接收到roster列表更新 :param event: :return: """ log_params = "jid:%s item:%s old_item:%s" % ( self.jid_bare_str, roster_item_2_dic( event.item), roster_item_2_dic(event.old_item)) logger.info("XMPPClient::handle_roster_update, %s" % log_params) added_ls = [] removed_ls = [] modified_ls = [] item = event.item if item.subscription == "remove": self.on_roster_del_notify(item) removed_ls.append(item) elif item.subscription == "both": self.on_roster_add_notify(item) modified_ls.append(item) if event.old_item else added_ls.append( item) self.on_roster_update_notify(added_ls, removed_ls, modified_ls) def reg_message(self, subject, hander_fun): """ 注册主题接收回调 :param subject: 主题 :param hander_fun: 回调函数 :return: """ self.subject_to_fun_dic[subject] = hander_fun @message_stanza_handler("normal") @except_adaptor() @xmpp_recv_adaptor() def handle_message(self, from_jid, subject, body): """ 消息接收分发 :param from_jid: 发送者jid :param subject: 发送主题 :param body: 发送内容 :return: """ if subject not in self.subject_to_fun_dic: error_msg = "subject:%s not register, details:%s" % ( subject, self.subject_to_fun_dic) logger.error(error_msg) return True self.subject_to_fun_dic[subject](self, from_jid, body) return True @presence_stanza_handler() @except_adaptor() def handle_presence_available(self, stanza): """ XMPP 上线通知 :param stanza: :return: """ return True @presence_stanza_handler("unavailable") @except_adaptor() def handle_presence_unavailable(self, stanza): """ XMPP 下线通知 :param stanza: :return: """ return True @presence_stanza_handler("subscribe") def handle_presence_subscribe(self, stanza): """ 上下线状态预定请求 :param stanza: :return: """ presence = Presence(to_jid=stanza.from_jid.bare(), stanza_type="subscribe") return [stanza.make_accept_response(), presence] @presence_stanza_handler("subscribed") def handle_presence_subscribed(self, stanza): """ 上下线状态预定通知 :param stanza: :return: """ return True @presence_stanza_handler("unsubscribe") def handle_presence_unsubscribe(self, stanza): """ 上下线状态取消预定请求 :param stanza: :return: """ if not self.is_jid_in_roster(stanza.from_jid): return True presence = Presence(to_jid=stanza.from_jid.bare(), stanza_type="unsubscribe") return [stanza.make_accept_response(), presence] @presence_stanza_handler("unsubscribed") def handle_presence_unsubscribed(self, stanza): """ 上下线状态取消预定通知 :param stanza: :return: """ return True def is_jid_in_roster(self, jid): """ 判断某个jid是否在roster中 :param jid: jid :return:True/False """ if not self.xmpp_client.roster_client.roster: return False for item in self.xmpp_client.roster_client.roster.items(): if JidMgr().get_jid_str(item.jid) == JidMgr().get_jid_str(jid): return True return False @gevent_adaptor(use_join_result=False) def add_roster(self, Jid, name=None, groups=None): """ 添加好友 :param Jid: 添加的jid :param name: 添加的用户名 :param groups: 添加的用户组 :return: """ if self.is_jid_in_roster(Jid): return self.xmpp_client.roster_client.add_item(Jid, name, groups) self.xmpp_client.stream._send( Presence(to_jid=Jid, stanza_type='subscribe')) # 注意:以下方式也可以实现添加roster功能,但是用userservice 的add roster则没有handle_presence_available通知 # UserService().add_roster(self.JID.local, Jid.local) # UserService().add_roster(Jid.local, self.JID.local) @gevent_adaptor(use_join_result=False) def del_roster(self, Jid): """ 删除好友 :param Jid: 删除的jid :return: """ if isinstance(Jid, str) or isinstance(Jid, unicode): Jid = JID(Jid) if not self.is_jid_in_roster(Jid): return UserService().del_roster(self.JID.local, Jid.bare().as_string()) UserService().del_roster(Jid.local, self.JID.as_string()) self.xmpp_client.stream._send( Presence(to_jid=Jid, stanza_type='unsubscribe')) def on_roster_del_notify(self, roster_item): """ roster删除成功通知 :param roster_item: RosterItem 对象 :return: """ pass def on_roster_add_notify(self, roster_item): """ roster添加成功通知 :param roster_item: RosterItem 对象 :return: """ pass def on_roster_update_notify(self, added_ls, removed_ls, modified_ls): """ roster添加成功通知 :param added_ls: added_ls RosterItem 列表 :param removed_ls: removed RosterItem 列表 :param modified_ls: modified RosterItem 列表 :return: """ pass def wait_for_auth(self): """ 等待xmpp登陆授权成功 :return: """ while not self.is_auth: logger.warn("XMPPClient::wait_for_auth, sleep 1s to wait for auth") gevent.sleep(5)
def __init__(self, my_jid, settings): version_provider = VersionProvider(settings) self.client = Client(my_jid, [self, version_provider], settings) self.rpc=transmissionrpc.Client(TRANSURL,TRANSPORT,TRANSUSER,TRANSPASS) for user in SUBSCRIBERS: self.userlist[JID(user).local]=JID(user)
def handle_disconnected(self, event): return QUIT @event_handler() def handle_all(self, event): logging.info(u"-- {0}".format(event)) logging.basicConfig(level=logging.INFO) # change to 'DEBUG' to see more your_jid = raw_input("Your jid: ") your_password = getpass("Your password: "******"Target jid: ") message = raw_input("Message: ") if sys.version_info.major < 3: your_jid = your_jid.decode("utf-8") your_password = your_password.decode("utf-8") target_jid = target_jid.decode("utf-8") message = message.decode("utf-8") handler = MyHandler(JID(target_jid), message) settings = XMPPSettings({ u"password": your_password, u"starttls": True, u"tls_verify_peer": False, }) client = Client(JID(your_jid), [handler], settings) client.connect() client.run()
class XMPPBot(EventHandler, XMPPFeatureHandler): autoReconnect = False def __init__(self, my_jid, settings, autoReconnect=None, main_loop=None): self.jid = my_jid self.settings = settings if autoReconnect is not None: self.autoReconnect = autoReconnect self.do_quit = False self.main_loop = main_loop def newclient(self): version_provider = VersionProvider(self.settings) self.client = Client( self.jid, [self, version_provider], self.settings, main_loop=self.main_loop, ) def start(self): while not self.do_quit: logging.info('XMPP connecting...') self.connect() self.run() if not self.autoReconnect: self.do_quit = True def connect(self): self.newclient() self.client.connect() def run(self): self.client.run() def disconnect(self): self.do_quit = True self.client.disconnect() try: self.client.run(timeout=2) except RuntimeError: # IOLoop is already running pass @property def roster(self): return self.client.roster @message_stanza_handler() def handle_message(self, stanza): if stanza.stanza_type and stanza.stanza_type.endswith( 'chat') and stanza.body: logging.info("%s said: %s", stanza.from_jid, stanza.body) self.last_chat_message = stanza else: logging.info("%s message: %s", stanza.from_jid, stanza.serialize()) return True def send_message(self, receiver, msg): m = Message( stanza_type='chat', from_jid=self.client.jid, to_jid=receiver, body=msg, ) self.send(m) def send(self, stanza): self.client.stream.send(stanza) def delayed_call(self, seconds, func, *args, **kwargs): self.client.main_loop.delayed_call(seconds, partial(func, *args, **kwargs)) def get_vcard(self, jid, callback): '''callback is used as both result handler and error handler''' q = Iq(to_jid=jid.bare(), stanza_type='get') vc = ET.Element("{vcard-temp}vCard") q.add_payload(vc) self.stanza_processor.set_response_handlers(q, callback, callback) self.send(q) def update_roster(self, jid, name=NO_CHANGE, groups=NO_CHANGE): self.client.roster_client.update_item(jid, name, groups) @presence_stanza_handler() def handle_presence_available(self, stanza): logging.info('%s[%s]', stanza.from_jid, stanza.show or 'available') return True @event_handler(DisconnectedEvent) def handle_disconnected(self, event): if self.do_quit: return QUIT else: logging.warn('XMPP disconnected. Reconnecting...') # We can't restart here because the stack will overflow return True @event_handler() def handle_all(self, event): """Log all events.""" logging.info("-- {0}".format(event))
class BotChat(EventHandler, XMPPFeatureHandler): trytimes = 0 def __init__(self): my_jid = JID(USER+'/Bot') self.my_jid = my_jid settings = XMPPSettings({ "software_name": "Clubot", "software_version": __version__, "software_os": "Linux", "tls_verify_peer": False, "starttls": True, "ipv6":False, "poll_interval": 10, }) settings["password"] = PASSWORD version_provider = VersionProvider(settings) self.connected = False mainloop = TornadoMainLoop(settings) self.client = Client(my_jid, [self, version_provider], settings, mainloop) #self.client = Client(my_jid, [self, version_provider], settings) self.logger = get_logger() self.trytimes = 0 self.sended = [] Logics.empty_status() def run(self, timeout = None): self.client.connect() self.client.run(timeout) def disconnect(self): self.client.disconnect() @presence_stanza_handler("subscribe") def handle_presence_subscribe(self, stanza): self.logger.info(u"{0} join us".format(stanza.from_jid)) frm = stanza.from_jid presence = Presence(to_jid = frm, stanza_type = "subscribe") Logics.add(frm, None, stanza.show) r =[stanza.make_accept_response(), presence] if frm not in self.sended: self.message_bus.send_sys_msg(stanza, new_member(frm)) self.message_bus.send_back_msg(stanza, welcome(frm)) self.sended.append(frm) return r @presence_stanza_handler("subscribed") def handle_presence_subscribed(self, stanza): self.logger.info(u"{0!r} accepted our subscription request" .format(stanza.from_jid)) frm = stanza.from_jid presence = Presence(to_jid = frm, stanza_type = "subscribe") Logics.add(frm, None, stanza.show) r =[presence] r =[stanza.make_accept_response(), presence] if frm not in self.sended: self.message_bus.send_sys_msg(stanza, new_member(frm)) self.message_bus.send_back_msg(stanza, welcome(frm)) self.sended.append(frm) return r @presence_stanza_handler("unsubscribe") def handle_presence_unsubscribe(self, stanza): self.logger.info(u"{0} canceled presence subscription" .format(stanza.from_jid)) presence = Presence(to_jid = stanza.from_jid.bare(), stanza_type = "unsubscribe") nick = Logics.get_one(stanza.from_jid).nick self.message_bus.send_sys_msg(stanza, u'{0} 离开群'.format(nick)) Logics.drop(stanza.from_jid.bare()) r =[stanza.make_accept_response(), presence] return r @presence_stanza_handler("unsubscribed") def handle_presence_unsubscribed(self, stanza): self.logger.info(u"{0!r} acknowledged our subscrption cancelation" .format(stanza.from_jid)) Logics.drop(stanza.from_jid.bare()) return True @presence_stanza_handler(None) def handle_presence_available(self, stanza): self.logger.info(r"{0} has been online".format(stanza.from_jid)) if stanza.from_jid.bare().as_string() != USER: Logics.set_online(stanza.from_jid, stanza.show) self.message_bus.send_offline_message(stanza) @presence_stanza_handler("unavailable") def handle_presence_unavailable(self, stanza): self.logger.info(r"{0} has been offline".format(stanza.from_jid)) frm = stanza.from_jid if frm.bare().as_string() == USER: self.logger.info('bot go to offline') self.disconnect() Logics.set_offline(frm) @message_stanza_handler() def handle_message(self, stanza): body = stanza.body frm = stanza.from_jid.bare().as_string() if not body: return True self.logger.info("receive message '{0}' from {1}" .format(body, stanza.from_jid)) if body.startswith('$') or body.startswith('-'): self.message_bus.send_command(stanza, body) #elif body.startswith('<') and frm == BRIDGE: # self.message_bus.send_qq_msg(stanza, body) else: self.message_bus.send_all_msg(stanza, body) return True @event_handler(DisconnectedEvent) def handle_disconnected(self, event): return QUIT @event_handler(ConnectedEvent) def handle_connected(self, event): self.message_bus = MessageBus(self.my_jid, self.stream) self.connected = True BotChat.trytimes = 0 @property def roster(self): return self.client.roster @property def stream(self): return self.client.stream def invite_member(self, jid): logging.info('invite {0}'.format(jid)) p1 = Presence(from_jid = self.my_jid, to_jid = jid, stanza_type = 'subscribe') p = Presence(from_jid = self.my_jid, to_jid = jid, stanza_type = 'subscribed') self.stream.send(p) self.stream.send(p1) @event_handler(RosterUpdatedEvent) def handle_roster_update(self, event): item = event.item @event_handler(RosterReceivedEvent) def handle_roster_received(self, event): dbstatus = Logics.get_global_info('status').value if not dbstatus: status = STATUS else: status = dbstatus p = Presence(status=status) self.client.stream.send(p) ret = [x.jid.bare() for x in self.roster if x.subscription == 'both'] self.logger.info(' -- roster:{0}'.format(ret)) members = Logics.get_members() members = [m.email for m in members] [Logics.add(frm) for frm in ret if not Logics.get_one(frm)] if IMPORT: [self.invite_member(JID(m)) for m in members if JID(m) not in ret] #else: #[del_member(JID(m)) for m in members if JID(m) not in ret] @event_handler() def handle_all(self, event): self.logger.info(u"-- {0}".format(event))
class ChatBot(MessageMixin, UserMixin, EventHandler, XMPPFeatureHandler): got_roster = False message_queue = None ignore = set() def __init__(self, jid, settings, botsettings=None): if 'software_name' not in settings: settings['software_name'] = self.__class__.__name__ if 'software_version' not in settings: settings['software_version'] = __version__ version_provider = VersionProvider(settings) self.client = Client(jid, [self, version_provider], settings) self.presence = defaultdict(dict) self.subscribes = ExpiringDictionary(default_timeout=5) self.invited = {} self.avatar_hash = None self.settings = botsettings def run(self): self.client.connect() self.jid = self.client.jid.bare() logger.info('self jid: %r', self.jid) self.update_on_setstatus = set() self.client.run() def disconnect(self): '''Request disconnection and let the main loop run for a 2 more seconds for graceful disconnection.''' self.client.disconnect() while True: try: self.client.run(timeout = 2) except pyxmpp2.exceptions.StreamParseError: # we raise SystemExit to exit, expat says XML_ERROR_FINISHED pass else: break def handle_early_message(self): self.got_roster = True q = self.message_queue if q: self.now = datetime.datetime.utcnow() for sender, stanza in q: self.current_jid = sender self._cached_jid = None try: timestamp = stanza.as_xml().find('{urn:xmpp:delay}delay').attrib['stamp'] except AttributeError: timestamp = None self.handle_message(stanza.body, timestamp) self.message_queue = self.__class__.message_queue = None @event_handler(RosterReceivedEvent) def roster_received(self, stanze): self.delayed_call(2, self.handle_early_message) self.delayed_call(getattr(config, 'reconnect_timeout', 24 * 3600), self.signal_connect) nick, avatar_type, avatar_file = (getattr(config, x, None) for x in ('nick', 'avatar_type', 'avatar_file')) if nick or (avatar_type and avatar_file): self.set_vcard(nick, (avatar_type, avatar_file)) return True def signal_connect(self): logging.info('Schedule to re-connecting...') self.client.disconnect() @message_stanza_handler() def message_received(self, stanza): if stanza.stanza_type != 'chat': return True if not stanza.body: logging.info("%s message: %s", stanza.from_jid, stanza.serialize()) return True sender = stanza.from_jid body = stanza.body self.current_jid = sender self.now = datetime.datetime.utcnow() logging.info('[%s] %s', sender, stanza.body) if str(sender.bare()) in self.ignore: logging.info('(The above message is ignored on purpose)') return True if not self.got_roster: if not self.message_queue: self.message_queue = [] self.message_queue.append((sender, stanza)) else: self.handle_message(body) logging.info('done with new message') return True def send_message(self, receiver, msg): if isinstance(receiver, str): receiver = JID(receiver) m = Message( stanza_type = 'chat', from_jid = self.jid, to_jid = receiver, body = msg, ) self.send(m) def reply(self, msg): self.send_message(self.current_jid, msg) def send(self, stanza): self.client.stream.send(stanza) def delayed_call(self, seconds, func, *args, **kwargs): self.client.main_loop.delayed_call(seconds, partial(func, *args, **kwargs)) @event_handler(DisconnectedEvent) def handle_disconnected(self, event): return QUIT @property def roster(self): return self.client.roster def get_online_users(self): ret = [x.jid for x in self.roster if x.subscription == 'both' and \ str(x.jid) in self.presence] logging.info('%d online buddies: %r', len(ret), ret) return ret def get_xmpp_status(self, jid): return sorted(self.presence[str(jid)].values(), key=lambda x: x['priority'], reverse=True)[0] def xmpp_add_user(self, jid): presence = Presence(to_jid=jid, stanza_type='subscribe') self.send(presence) def xmpp_setstatus(self, status, to_jid=None): if isinstance(to_jid, str): to_jid = JID(to_jid) presence = Presence(status=status, to_jid=to_jid) self.send(presence) def update_roster(self, jid, name=NO_CHANGE, groups=NO_CHANGE): self.client.roster_client.update_item(jid, name, groups) def removeInvitation(self): for ri in self.roster.values(): if ri.ask is not None: self.client.roster_client.remove_item(ri.jid) logging.info('%s removed', ri.jid) def unsubscribe(self, jid, type='unsubscribe'): presence = Presence(to_jid=jid, stanza_type=type) self.send(presence) def subscribe(self, jid): self.invited[jid] = 2 presence = Presence(to_jid=jid, stanza_type='subscribe') self.send(presence) @presence_stanza_handler('subscribe') def handle_presence_subscribe(self, stanza): logging.info('%s subscribe', stanza.from_jid) sender = stanza.from_jid bare = sender.bare() # avoid repeated request invited = False if bare not in self.subscribes: invited = self.invited.get(bare, False) if invited is not False: if invited == 2: self.invited[bare] = 1 else: del self.invited[bare] return stanza.make_accept_response() # We won't deny inivted members self.handle_userjoin_before() else: if config.private and str(bare) != config.root: self.send_message(sender, _('Sorry, this is a private group, and you are not invited.')) return stanza.make_deny_response() if not self.handle_userjoin_before(): return stanza.make_deny_response() self.current_jid = sender self.now = datetime.datetime.utcnow() try: self.handle_userjoin(action=stanza.stanza_type) except ValidationError: #The server is subscribing pass self.subscribes[bare] = True if stanza.stanza_type.endswith('ed'): return stanza.make_accept_response() if invited is False: presence = Presence(to_jid=stanza.from_jid.bare(), stanza_type='subscribe') return [stanza.make_accept_response(), presence] @presence_stanza_handler('subscribed') def handle_presence_subscribed(self, stanza): # use the same function logging.info('%s subscribed', stanza.from_jid) return self.handle_presence_subscribe(stanza) @presence_stanza_handler('unsubscribe') def handle_presence_unsubscribe(self, stanza): logging.info('%s unsubscribe', stanza.from_jid) sender = stanza.from_jid self.current_jid = sender self.now = datetime.datetime.utcnow() self.handle_userleave(action=stanza.stanza_type) if stanza.stanza_type.endswith('ed'): return stanza.make_accept_response() presence = Presence(to_jid=stanza.from_jid.bare(), stanza_type='unsubscribe') return [stanza.make_accept_response(), presence] presence_stanza_handler('unsubscribed') def handle_presence_unsubscribed(self, stanza): # use the same function logging.info('%s unsubscribed', stanza.from_jid) return self.handle_presence_unsubscribe(stanza) @presence_stanza_handler() def handle_presence_available(self, stanza): if stanza.stanza_type not in ('available', None): return False jid = stanza.from_jid plainjid = str(jid.bare()) if plainjid == str(self.jid): return self.now = datetime.datetime.utcnow() if plainjid not in self.presence: type = 'new' self.current_jid = jid self.user_update_presence(plainjid) if conn_lost_interval and self.current_user.last_seen and \ self.now - self.current_user.last_seen < conn_lost_interval: type = 'reconnect' self.send_lost_message() logging.info('%s[%s] (%s)', jid, stanza.show or 'available', type) else: if jid.resource not in self.presence[plainjid]: self.user_update_presence(plainjid) logging.info('%s[%s]', jid, stanza.show or 'available') self.presence[plainjid][jid.resource] = { 'show': stanza.show, 'status': stanza.status, 'priority': stanza.priority, } if self.get_user_by_jid(plainjid) is None: try: self.current_jid = jid self.handle_userjoin() except ValidationError: #The server is subscribing pass if config.warnv105 and jid.resource and \ jid.resource.startswith('Talk.') and not jid.resource.startswith('Talk.v104'): # Got a Talk.v107... # No need to translate; GTalk only has a v105 for Chinese. self.send_message(jid, '警告:你正在使用的可能是不加密的 GTalk v105 版本。网络上的其它人可能会截获您的消息。这样不安全!请使用 GTalk v104 英文版或者其它 XMPP 客户端。\nGTalk 英文版: http://www.google.com/talk/index.html\nPidgin: http://www.pidgin.im/') return True @presence_stanza_handler('unavailable') def handle_presence_unavailable(self, stanza): jid = stanza.from_jid plainjid = str(jid.bare()) if plainjid in self.presence and plainjid != str(self.jid): try: del self.presence[plainjid][jid.resource] except KeyError: pass if self.presence[plainjid]: logging.info('%s[unavailable] (partly)', jid) else: del self.presence[plainjid] self.now = datetime.datetime.utcnow() self.user_disappeared(plainjid) logging.info('%s[unavailable] (totally)', jid) return True @event_handler() def handle_all(self, event): '''Log all events.''' logging.info('-- {0}'.format(event)) def get_name(self, jid): if isinstance(jid, str): jid = JID(jid) else: jid = jid.bare() try: return self.roster[jid].name or hashjid(jid) except KeyError: return hashjid(jid) def get_vcard(self, jid=None, callback=None): '''callback is used as both result handler and error handler''' q = Iq( to_jid = jid and jid.bare(), stanza_type = 'get', ) vc = ET.Element("{vcard-temp}vCard") q.add_payload(vc) if callback: self.stanza_processor.set_response_handlers(q, callback, callback) self.send(q) def set_vcard(self, nick=None, avatar=None): self.get_vcard(callback=partial(self._set_vcard, nick, avatar)) def _set_vcard(self, nick=None, avatar=None, stanza=None): #FIXME: This doesn't seem to work with jabber.org q = Iq( from_jid = self.jid, stanza_type = 'set', ) vc = ET.Element("{vcard-temp}vCard") if nick is not None: n = ET.SubElement(vc, '{vcard-temp}FN') n.text = nick if avatar is not None: type, picfile = avatar photo = ET.SubElement(vc, '{vcard-temp}PHOTO') t = ET.SubElement(photo, '{vcard-temp}TYPE') t.text = type d = ET.SubElement(photo, '{vcard-temp}BINVAL') data = open(picfile, 'rb').read() d.text = base64.b64encode(data).decode('ascii') self.avatar_hash = hashlib.new('sha1', data).hexdigest() q.add_payload(vc) self.stanza_processor.set_response_handlers( q, self._set_vcard_callback, self._set_vcard_callback) self.send(q) def _set_vcard_callback(self, stanza): if stanza.stanza_type == 'error': logging.error('failed to set my vCard.') else: logging.info('my vCard set.') self.update_presence() def update_presence(self): #TODO: update for individual users presence = self.settings['presence'] x = ET.Element('{vcard-temp:x:update}x') if self.avatar_hash: photo = ET.SubElement(x, '{vcard-temp:x:update}photo') photo.text = self.avatar_hash presence.add_payload(x) self.send(presence)
class QXBot(EventHandler, XMPPFeatureHandler): def __init__(self): my_jid = JID(USER + '/Bot') self.my_jid = my_jid settings = XMPPSettings({ "software_name": "qxbot", "software_version": __version__, "software_os": "Linux", "tls_verify_peer": False, "starttls": True, "ipv6": False, "poll_interval": 10, }) settings["password"] = PASSWORD version_provider = VersionProvider(settings) event_queue = settings["event_queue"] self.webqq = WebQQ(QQ, event_queue) self.connected = False #self.mainloop = TornadoMainLoop(settings) self.mainloop = EpollMainLoop(settings) self.client = Client(my_jid, [self, version_provider], settings, self.mainloop) self.logger = get_logger() self.msg_dispatch = MessageDispatch(self, self.webqq, BRIDGES) self.xmpp_msg_queue = Queue.Queue() def run(self, timeout=None): self.client.connect() self.client.run(timeout) def disconnect(self): self.client.disconnect() while True: try: self.run(2) except: pass else: break @presence_stanza_handler("subscribe") def handle_presence_subscribe(self, stanza): self.logger.info(u"{0} join us".format(stanza.from_jid)) return stanza.make_accept_response() @presence_stanza_handler("subscribed") def handle_presence_subscribed(self, stanza): self.logger.info(u"{0!r} accepted our subscription request".format( stanza.from_jid)) return stanza.make_accept_response() @presence_stanza_handler("unsubscribe") def handle_presence_unsubscribe(self, stanza): self.logger.info(u"{0} canceled presence subscription".format( stanza.from_jid)) return stanza.make_accept_response() @presence_stanza_handler("unsubscribed") def handle_presence_unsubscribed(self, stanza): self.logger.info( u"{0!r} acknowledged our subscrption cancelation".format( stanza.from_jid)) @presence_stanza_handler(None) def handle_presence_available(self, stanza): self.logger.info(r"{0} has been online".format(stanza.from_jid)) @presence_stanza_handler("unavailable") def handle_presence_unavailable(self, stanza): self.logger.info(r"{0} has been offline".format(stanza.from_jid)) @message_stanza_handler() def handle_message(self, stanza): if self.webqq.connected: self.msg_dispatch.dispatch_xmpp(stanza) else: self.xmpp_msg_queue.put(stanza) @event_handler(DisconnectedEvent) def handle_disconnected(self, event): return QUIT @event_handler(ConnectedEvent) def handle_connected(self, event): pass @event_handler(RosterReceivedEvent) def handle_roster_received(self, event): """ 此处代表xmpp已经连接 开始连接QQ, 先将检查是否需要验证码的handler加入到mainloop """ checkhandler = CheckHandler(self.webqq) self.mainloop.add_handler(checkhandler) self.connected = True @event_handler(CheckedEvent) def handle_webqq_checked(self, event): """ 第一步已经完毕, 删除掉检查的handler, 将登录前handler加入mainloop""" bloginhandler = BeforeLoginHandler(self.webqq, password=QQ_PWD) self.mainloop.remove_handler(event.handler) self.mainloop.add_handler(bloginhandler) @event_handler(BeforeLoginEvent) def handle_webqq_blogin(self, event): """ 登录前完毕开始真正的登录 """ loginhandler = LoginHandler(self.webqq) self.mainloop.remove_handler(event.handler) self.mainloop.add_handler(loginhandler) @event_handler(WebQQLoginedEvent) def handle_webqq_logined(self, event): """ 登录后将获取群列表的handler放入mainloop """ self.mainloop.remove_handler(event.handler) self.mainloop.add_handler(GroupListHandler(self.webqq)) @event_handler(GroupListEvent) def handle_webqq_group_list(self, event): """ 获取群列表后""" self.mainloop.remove_handler(event.handler) data = event.data group_map = {} if data.get("retcode") == 0: group_list = data.get("result", {}).get("gnamelist", []) for group in group_list: gcode = group.get("code") group_map[gcode] = group self.webqq.group_map = group_map self.webqq.group_lst_updated = False # 开放添加GroupListHandler i = 1 for gcode in group_map: if i == len(group_map): self.mainloop.add_handler( GroupMembersHandler(self.webqq, gcode=gcode, done=True)) else: self.mainloop.add_handler( GroupMembersHandler(self.webqq, gcode=gcode, done=False)) i += 1 @event_handler(GroupMembersEvent) def handle_group_members(self, event): """ 获取所有群成员 """ self.mainloop.remove_handler(event.handler) members = event.data.get("result", {}).get("minfo", []) self.webqq.group_m_map[event.gcode] = {} for m in members: uin = m.get("uin") self.webqq.group_m_map[event.gcode][uin] = m cards = event.data.get("result", {}).get("cards", []) for card in cards: uin = card.get("muin") group_name = card.get("card") self.webqq.group_m_map[event.gcode][uin]["nick"] = group_name # 防止重复添加GroupListHandler if not self.webqq.group_lst_updated: self.webqq.group_lst_updated = True self.mainloop.add_handler(GroupListHandler(self.webqq, delay=300)) @event_handler(WebQQRosterUpdatedEvent) def handle_webqq_roster(self, event): """ 群成员都获取完毕后开启,Poll获取消息和心跳 """ self.mainloop.remove_handler(event.handler) self.msg_dispatch.get_map() if not self.webqq.polled: self.webqq.polled = True self.mainloop.add_handler(PollHandler(self.webqq)) if not self.webqq.heartbeated: self.webqq.heartbeated = True hb = HeartbeatHandler(self.webqq) self.mainloop.add_handler(hb) while True: try: stanza = self.xmpp_msg_queue.get_nowait() self.msg_dispatch.dispatch_xmpp(stanza) except Queue.Empty: break self.webqq.connected = True @event_handler(WebQQHeartbeatEvent) def handle_webqq_hb(self, event): """ 心跳完毕后, 延迟60秒在此触发此事件 重复心跳 """ self.mainloop.remove_handler(event.handler) self.mainloop.add_handler(HeartbeatHandler(self.webqq, delay=60)) @event_handler(WebQQPollEvent) def handle_webqq_poll(self, event): """ 延迟1秒重复触发此事件, 轮询获取消息 """ self.mainloop.remove_handler(event.handler) self.mainloop.add_handler(PollHandler(self.webqq)) @event_handler(WebQQMessageEvent) def handle_webqq_msg(self, event): """ 有消息到达, 处理消息 """ self.msg_dispatch.dispatch_qq(event.message) @event_handler(RetryEvent) def handle_retry(self, event): """ 有handler触发异常, 需重试 """ self.mainloop.remove_handler(event.handler) handler = event.cls(self.webqq, event.req, *event.args, **event.kwargs) self.mainloop.add_handler(handler) @event_handler(RemoveEvent) def handle_remove(self, event): """ 触发此事件, 移除handler """ self.mainloop.remove_handler(event.handler) def send_qq_group_msg(self, group_uin, content): """ 发送qq群消息 """ handler = GroupMsgHandler(self.webqq, group_uin=group_uin, content=content) self.mainloop.add_handler(handler) @property def roster(self): return self.client.roster @property def stream(self): return self.client.stream @event_handler() def handle_all(self, event): self.logger.info(u"-- {0}".format(event)) def make_message(self, to, typ, body): """ 构造消息 `to` - 接收人 JID `typ` - 消息类型 `body` - 消息主体 """ if typ not in ['normal', 'chat', 'groupchat', 'headline']: typ = 'chat' m = Message(from_jid=self.my_jid, to_jid=to, stanza_type=typ, body=body) return m def send_msg(self, to, body): if not isinstance(to, JID): to = JID(to) msg = self.make_message(to, 'chat', body) self.stream.send(msg)