def __init__(self, bot, config): initiator = TelegramDBInit(bot.database) self.bot = bot self.tbot = None self.pokemons = config.get('alert_catch', {}) self.whoami = "TelegramHandler" self.config = config self.chat_handler = ChatHandler(self.bot, self.pokemons) self._connect()
def __init__(self, bot, config): self.bot = bot self.dbot = None self.master = config.get('master', None) if self.master == None: return self.pokemons = config.get('alert_catch', {}) self.whoami = "DiscordHandler" self.config = config self.chat_handler = ChatHandler(self.bot, [])
def __init__(self, bot, pokemons, config): self.bot = bot request.CON_POOL_SIZE = 16 self.config = config self.chat_handler = ChatHandler(self.bot, pokemons) self.master = self.config.get('master') with self.bot.database as conn: # initialize the DB table if it does not exist yet initiator = TelegramDBInit(bot.database) if unicode(self.master).isnumeric(): # master is numeric self.bot.logger.info("Telegram master is valid (numeric): {}".format(self.master)) elif self.master is not None: # Master is not numeric, fetch from db self.bot.logger.info("Telegram master is not numeric: {}".format(self.master)) c = conn.cursor() srchmaster = re.sub(r'^@', '', self.master) c.execute("SELECT uid from telegram_uids where username = '******'".format(srchmaster)) results = c.fetchall() if len(results) > 0: # woohoo, we already saw a message from this master and therefore have a uid self.bot.logger.info("Telegram master UID from datastore: {}".format(results[0][0])) self.master = results[0][0] else: # uid not known yet self.bot.logger.info("Telegram master UID not in datastore yet") self.pokemons = pokemons self._tbot = None self.config = config self.master = None
def __init__(self, bot, config): initiator = TelegramDBInit(bot.database) self.bot = bot self.tbot = None self.pokemons = config.get('alert_catch', {}) self.whoami = "TelegramHandler" self.config = config self.chat_handler = ChatHandler(self.bot, self.pokemons) self._connect()
def __init__(self, bot, config): self.bot = bot self.dbot = None self.master = config.get('master', None) if self.master == None: return self.pokemons = config.get('alert_catch', {}) self.whoami = "DiscordHandler" self.config = config self.chat_handler = ChatHandler(self.bot, [])
def __init__(self, bot, pokemons, config): self.bot = bot request.CON_POOL_SIZE = 16 self.config = config self.chat_handler = ChatHandler(self.bot, pokemons) self.master = self.config.get('master') with self.bot.database as conn: # initialize the DB table if it does not exist yet initiator = TelegramDBInit(bot.database) if unicode(self.master).isnumeric(): # master is numeric self.bot.logger.info( "Telegram master is valid (numeric): {}".format( self.master)) elif self.master is not None: # Master is not numeric, fetch from db self.bot.logger.info( "Telegram master is not numeric: {}".format(self.master)) c = conn.cursor() srchmaster = re.sub(r'^@', '', self.master) c.execute( "SELECT uid from telegram_uids where username = '******'". format(srchmaster)) results = c.fetchall() if len( results ) > 0: # woohoo, we already saw a message from this master and therefore have a uid self.bot.logger.info( "Telegram master UID from datastore: {}".format( results[0][0])) self.master = results[0][0] else: # uid not known yet self.bot.logger.info( "Telegram master UID not in datastore yet") self.pokemons = pokemons self._tbot = None self.config = config self.master = None
class DiscordHandler(EventHandler): def __init__(self, bot, config): self.bot = bot self.dbot = None self.master = config.get('master', None) if self.master == None: return self.pokemons = config.get('alert_catch', {}) self.whoami = "DiscordHandler" self.config = config self.chat_handler = ChatHandler(self.bot, []) def catch_notify(self, pokemon, cp, iv, params): if params == " ": return True try: oper = re.search(r'operator:([^ ]+)', params).group(1) rule_cp = int(re.search(r'cp:([0-9]+)', params).group(1)) rule_iv = float(re.search(r'iv:([0-9.]+)', params).group(1)) rule_pkmn = re.search(r'pokemon:([^ ]+)', params).group(1) return rule_pkmn == pokemon and (oper == "or" and (cp >= rule_cp or iv >= rule_iv) or cp >= rule_cp and iv >= rule_iv) except: return False def handle_event(self, event, sender, level, formatted_msg, data): if self.dbot is None: try: self.bot.logger.info("Discord bot not running, Starting..") self.dbot = DiscordClass(self.bot, self.master, self.pokemons, self.config) self.dbot.connect() thread.start_new_thread(self.dbot.run) except Exception as inst: self.dbot = None self.bot.logger.error( "Unable to start Discord bot; master: {}, exception: {}". format(self.master, pprint.pformat(inst))) return # prepare message to send msg = None msg = self.chat_handler.get_event(event, formatted_msg, data) if msg: self.dbot.sendMessage(to=self.master, text=msg)
class DiscordHandler(EventHandler): def __init__(self, bot, config): self.bot = bot self.dbot = None self.master = config.get('master', None) if self.master == None: return self.pokemons = config.get('alert_catch', {}) self.whoami = "DiscordHandler" self.config = config self.chat_handler = ChatHandler(self.bot, []) def catch_notify(self, pokemon, cp, iv, params): if params == " ": return True try: oper = re.search(r'operator:([^ ]+)', params).group(1) rule_cp = int(re.search(r'cp:([0-9]+)', params).group(1)) rule_iv = float(re.search(r'iv:([0-9.]+)', params).group(1)) rule_pkmn = re.search(r'pokemon:([^ ]+)', params).group(1) return rule_pkmn == pokemon and (oper == "or" and (cp >= rule_cp or iv >= rule_iv) or cp >= rule_cp and iv >= rule_iv) except: return False def handle_event(self, event, sender, level, formatted_msg, data): if self.dbot is None: try: self.bot.logger.info("Discord bot not running, Starting..") self.dbot = DiscordClass(self.bot, self.master, self.pokemons, self.config) self.dbot.connect() thread.start_new_thread(self.dbot.run) except Exception as inst: self.dbot = None self.bot.logger.error("Unable to start Discord bot; master: {}, exception: {}".format(self.master, pprint.pformat(inst))) return # prepare message to send msg = None msg = self.chat_handler.get_event(event, formatted_msg, data) if msg: self.dbot.sendMessage(to=self.master, text=msg)
class TelegramHandler(EventHandler): def __init__(self, bot, config): initiator = TelegramDBInit(bot.database) self.bot = bot self.tbot = None self.pokemons = config.get('alert_catch', {}) self.whoami = "TelegramHandler" self.config = config self.chat_handler = ChatHandler(self.bot, self.pokemons) self._connect() def _connect(self): if self.tbot is None: self.bot.logger.info("Telegram bot not running. Starting") self.tbot = TelegramClass(self.bot, self.pokemons, self.config) thread.start_new_thread(self.tbot.run) return self.tbot def catch_notify(self, pokemon, cp, iv, params): if params == " ": return True try: oper = re.search(r'operator:([^ ]+)', params).group(1) rule_cp = int(re.search(r'cp:([0-9]+)', params).group(1)) rule_iv = float(re.search(r'iv:([0-9.]+)', params).group(1)) rule_pkmn = re.search(r'pokemon:([^ ]+)', params).group(1) return rule_pkmn == pokemon and ( oper == "or" and (cp >= rule_cp or iv >= rule_iv) or cp >= rule_cp and iv >= rule_iv) except: return False def handle_event(self, event, sender, level, formatted_msg, data): msg = None # first handle subscriptions; they are independent of master setting. with self.bot.database as conn: subs = conn.execute( "select uid, parameters, event_type from telegram_subscriptions where event_type in (?,'all','debug')", [event]).fetchall() for sub in subs: if DEBUG_ON: self.bot.logger.info("Processing sub {}".format(sub)) (uid, params, event_type) = sub if not self.tbot.isAuthenticated(uid): # UID has subs but not in auth list. return if event != 'pokemon_caught' or self.catch_notify(data["pokemon"], int(data["cp"]), float(data["iv"]), params): if DEBUG_ON: self.bot.logger.info("Matched sub {} event {}".format(sub, event)) elif event_type == "debug": self.bot.logger.info("[{}] {}".format(event, msg)) else: msg = self.chat_handler.get_event(event, formatted_msg, data) if DEBUG_ON: self.bot.logger.info("Telegram message {}".format(msg)) if msg is None: return else: if DEBUG_ON: self.bot.logger.info("No match sub {} event {}".format(sub, event)) if msg is not None: if self.tbot is None: # instantiate tbot (TelegramClass) if not already set if DEBUG_ON: self.bot.logger.info("handle_event Telegram bot not running.") try: self._connect() except Exception as inst: self.bot.logger.error("Unable to start Telegram bot; exception: {}".format(pprint.pformat(inst))) self.tbot = None return if self.tbot is not None: # tbot should be running, but just in case it hasn't started yet self.tbot.sendMessage(chat_id=uid, parse_mode='Markdown', text=msg)
class TelegramClass: update_id = None def __init__(self, bot, pokemons, config): self.bot = bot request.CON_POOL_SIZE = 16 self.config = config self.chat_handler = ChatHandler(self.bot, pokemons) self.master = self.config.get('master') with self.bot.database as conn: # initialize the DB table if it does not exist yet initiator = TelegramDBInit(bot.database) if unicode(self.master).isnumeric(): # master is numeric self.bot.logger.info("Telegram master is valid (numeric): {}".format(self.master)) elif self.master is not None: # Master is not numeric, fetch from db self.bot.logger.info("Telegram master is not numeric: {}".format(self.master)) c = conn.cursor() srchmaster = re.sub(r'^@', '', self.master) c.execute("SELECT uid from telegram_uids where username = '******'".format(srchmaster)) results = c.fetchall() if len(results) > 0: # woohoo, we already saw a message from this master and therefore have a uid self.bot.logger.info("Telegram master UID from datastore: {}".format(results[0][0])) self.master = results[0][0] else: # uid not known yet self.bot.logger.info("Telegram master UID not in datastore yet") self.pokemons = pokemons self._tbot = None self.config = config self.master = None def connect(self): if DEBUG_ON: self.bot.logger.info("Not connected. Reconnecting") self._tbot = telegram.Bot(self.bot.config.telegram_token) try: self.update_id = self._tbot.getUpdates()[0].update_id except IndexError: self.update_id = None def grab_uid(self, update): with self.bot.database as conn: conn.execute("replace into telegram_uids (uid, username) values (?, ?)", (update.message.chat_id, update.message.from_user.username)) conn.commit() if self.master: self.master = update.message.chat_id def isMasterFromConfigFile(self, chat_id): if not hasattr(self, "master") or not self.master: return False if unicode(self.master).isnumeric(): return unicode(chat_id) == unicode(self.master) else: with self.bot.database as conn: cur = conn.cursor() cur.execute("select username from telegram_uids where uid = ?", [chat_id]) res = cur.fetchone() return res != None and unicode(res[0]) == unicode(re.replace(r'^@', '', self.master)) def isMasterFromActiveLogins(self, chat_id): with self.bot.database as conn: cur = conn.cursor() cur.execute("select count(1) from telegram_logins where uid = ?", [chat_id]) res = cur.fetchone() if res[0] == 1: return True return False def isAuthenticated(self, chat_id): return self.isMasterFromConfigFile(chat_id) or self.isMasterFromActiveLogins(chat_id) def deauthenticate(self, update): with self.bot.database as conn: cur = conn.cursor() sql = "delete from telegram_logins where uid = {}".format(update.message.chat_id) cur.execute(sql) conn.commit() self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Logout completed") return def authenticate(self, update): args = update.message.text.split(' ') if len(args) != 2: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Invalid password") return password = args[1] if password != self.config.get('password', None): self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Invalid password") else: with self.bot.database as conn: cur = conn.cursor() cur.execute("insert or replace into telegram_logins(uid) values(?)",[update.message.chat_id]) conn.commit() self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Authentication successful, you can now use all commands") return def sendMessage(self, chat_id=None, parse_mode='Markdown', text=None): try: if self._tbot is None: self.connect() self._tbot.sendMessage(chat_id=chat_id, parse_mode=parse_mode, text=text) except telegram.error.NetworkError: time.sleep(1) except telegram.error.TelegramError: time.sleep(10) except telegram.error.Unauthorized: self.update_id += 1 def sendLocation(self, chat_id, latitude, longitude): try: self._tbot.send_location(chat_id=chat_id, latitude=latitude, longitude=longitude) except telegram.error.NetworkError: time.sleep(1) except telegram.error.TelegramError: time.sleep(10) except telegram.error.Unauthorized: self.update_id += 1 def send_player_stats_to_chat(self, chat_id): stats = self.chat_handler.get_player_stats() if stats: self.sendMessage(chat_id=chat_id, parse_mode='Markdown', text="*{}* \n_Level:_ {} \n_XP:_ {}/{} \n_Pokemons Captured:_ {} ({} _last 24h_) \n_Poke Stop Visits:_ {} ({} _last 24h_) \n_KM Walked:_ {} \n_Stardust:_ {}".format( stats[0], stats[1], stats[2], stats[3], stats[4], stats[5], stats[6], stats[7], stats[8], stats[9])) self.sendLocation(chat_id=chat_id, latitude=self.bot.api._position_lat, longitude=self.bot.api._position_lng) else: self.sendMessage(chat_id=chat_id, parse_mode='Markdown', text="Stats not loaded yet\n") def send_event(self, event, formatted_msg, data): return self.chat_handler.get_event(event, formatted_msg, data) def send_events(self, update): events = self.chat_handler.get_events(update) self.sendMessage(chat_id=update.message.chat_id, parse_mode='HTML', text="\n".join(events)) def send_softbans(self, update, num): softbans = self.chat_handler.get_softbans(num) outMsg = '' if softbans: for x in softbans: outMsg += '*' + x[0] + '* ' + '(' + str(x[2]) + ')\n' self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="".join(outMsg)) else: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="No Softbans found! Good job!\n") def send_subscription_updated(self, update): self.chsub(update.message.text, update.message.chat_id) self.sendMessage(chat_id=update.message.chat_id, parse_mode='HTML', text=("Subscriptions updated.")) def send_info(self, update): self.send_player_stats_to_chat(update.message.chat_id) def send_logout(self, update): self.sendMessage(chat_id=update.message.chat_id, parse_mode='HTML', text=("Logged out.")) self.deauthenticate(update) def send_caught(self, update, num, order): caught = self.chat_handler.get_caught(num, order) outMsg = '' if caught: for x in caught: outMsg += '*' + x[0] + '* ' + '(_CP:_ ' + str(int(x[1])) + ' _IV:_ ' + str( x[2]) + ')\n' self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="".join(outMsg)) else: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="No Pokemon Caught Yet.\n") def request_snipe(self, update, pkm, location): loc_list = location.split(',') snipeSuccess = False try: id = Pokemons.id_for(pkm) except: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Invaild Pokemon") return #Set Telegram Snipe to true and let sniper do its work TelegramSnipe.ENABLED = True TelegramSnipe.ID = int(id) TelegramSnipe.POKEMON_NAME = str(pkm) TelegramSnipe.LATITUDE = float(loc_list[0].strip()) TelegramSnipe.LONGITUDE = float(loc_list[1].strip()) outMsg = 'Catching pokemon: ' + TelegramSnipe.POKEMON_NAME + ' at Latitude: ' + str(TelegramSnipe.LATITUDE) + ' Longitude: ' + str(TelegramSnipe.LONGITUDE) + '\n' self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="".join(outMsg)) def request_snipe_time(self, update, location): last_position = self.bot.position[0:2] loc_list = location.split(',') snipe_distance = convert(distance(last_position[0],last_position[1],float(loc_list[0].strip()),float(loc_list[1].strip())),"m","km") time_to_snipe = wait_time_sec(snipe_distance) time_to_snipe_str_min = time.strftime("%M:%S", time.gmtime(time_to_snipe)) if time_to_snipe <= 900: outMsg = "Estimated Time to Snipe: " + time_to_snipe_str_min + " Distance: " + "{0:.2f}".format(snipe_distance) + "KM" self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="".join(outMsg)) else: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Sniping distance is more than supported distance") def request_snipe_disable(self, update, config): if config.lower() == "true": TelegramSnipe.SNIPE_DISABLED = True return True else: TelegramSnipe.SNIPE_DISABLED = False return False def send_evolved(self, update, num, order): evolved = self.chat_handler.get_evolved(num, order) outMsg = '' if evolved: for x in evolved: outMsg += '*' + x[0] + '* ' + '(_CP:_ ' + str(int(x[1])) + ' _IV:_ ' + str( x[2]) + ')\n' self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="".join(outMsg)) else: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="No Evolutions Found.\n") def request_luckyegg_count(self,update): lucky_egg = inventory.items().get(Item.ITEM_LUCKY_EGG.value) # @UndefinedVariable self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Lucky Egg Count: " + str(lucky_egg.count)) def request_ordincense_count(self,update): ord_incense = inventory.items().get(Item.ITEM_INCENSE_ORDINARY.value) # @UndefinedVariable self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Ordinary Incense Count: " + str(ord_incense.count)) def request_luckyegg(self,update): lucky_egg = inventory.items().get(Item.ITEM_LUCKY_EGG.value) # @UndefinedVariable if lucky_egg.count == 0: return False response_dict = self.bot.use_lucky_egg() if not response_dict: self.bot.logger.info("Telegram Request: Failed to use lucky egg!") self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Failed to use lucky egg!\n") return False result = response_dict.get("responses", {}).get("USE_ITEM_XP_BOOST", {}).get("result", 0) if result == SUCCESS: lucky_egg.remove(1) self.bot.logger.info("Telegram Request: Used lucky egg, {} left.".format(lucky_egg.count)) self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Used lucky egg, " + str(lucky_egg.count) + " left.") return True elif result == ERROR_XP_BOOST_ALREADY_ACTIVE: self.bot.logger.info("Telegram Request: Lucky egg already active, {} left.".format(lucky_egg.count)) self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Lucky egg already active, " + str(lucky_egg.count) + " left.") return True else: self.bot.logger.info("Telegram Request: Failed to use lucky egg!") self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Failed to use lucky egg!\n") return False def request_ordincense(self,update): ord_incense = inventory.items().get(Item.ITEM_INCENSE_ORDINARY.value) # @UndefinedVariable if ord_incense.count == 0: return False request = self.bot.api.create_request() request.use_incense(incense_type=401) response_dict = request.call() if not response_dict: self.bot.logger.info("Telegram Request: Failed to use ordinary incense!") self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Failed to use ordinary incense!\n") return False result = response_dict.get('responses', {}).get('USE_INCENSE', {}).get('result', 0) self.bot.logger.info("Result = " + str(result)) if result == SUCCESS: ord_incense.remove(1) self.bot.logger.info("Telegram Request: Used ordinary incense, {} left.".format(ord_incense.count)) self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Used ordinary incense, " + str(ord_incense.count) + " left.") return True elif result == ERROR_INCENSE_ALREADY_ACTIVE: self.bot.logger.info("Telegram Request: Ordinary incense already active, {} left.".format(ord_incense.count)) self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Ordinary incense already active, " + str(ord_incense.count) + " left and has " + str(currentincense.expire_ms) + " remaining") return True else: self.bot.logger.info("Telegram Request: Failed to use ordinary incense! Result=" + str(result)) self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Failed to use ordinary incense!\n") return False def request_incensetime(self, update): self.bot.logger.info("Time Started") currentincense = inventory.applied_items().get('401') self.bot.logger.info(currentincense) #self.bot.logger.info(currentincense.expire_ms) return True def send_pokestops(self, update, num): pokestops = self.chat_handler.get_pokestops( num) outMsg = '' if pokestops: for x in pokestops: outMsg += '*' + x[0] + '* ' + '(_XP:_ ' + str(x[1]) + ' _Items:_ ' + str(x[2]) + ')\n' self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="".join(outMsg)) else: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="No Pokestops Encountered Yet.\n") def send_hatched(self, update, num, order): hatched = self.chat_handler.get_hatched(num, order) outMsg = '' if hatched: for x in hatched: outMsg += '*' + x[0] + '* ' + '(_CP:_ ' + str(int(x[1])) + ' _IV:_ ' + str( x[2]) + ')\n' self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="".join(outMsg)) else: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="No Eggs Hatched Yet.\n") def send_released(self, update, num, order): released = self.chat_handler.get_released(num, order) outMsg = '' if released: for x in released: outMsg += '*' + x[0] + '* ' + '(_CP:_ ' + str(int(x[1])) + ' _IV:_ ' + str( x[2]) + ')\n' self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="".join(outMsg)) else: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="No Pokemon Released Yet.\n") def send_vanished(self, update, num, order): vanished = self.chat_handler.get_vanished( num, order) outMsg = '' if vanished: for x in vanished: outMsg += '*' + x[0] + '* ' + '(_CP:_ ' + str(int(x[1])) + ' _IV:_ ' + str( x[2]) + ')\n' self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text=outMsg) def send_top(self, update, num, order): top = self.chat_handler.get_top(num, order) outMsg = '' for x in top: outMsg += "*{}* _CP:_ {} _IV:_ {} (Candy: {})\n".format(x[0], x[1], x[2], x[3]) self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text=outMsg) def showsubs(self, update): subs = [] with self.bot.database as conn: for sub in conn.execute("select uid, event_type, parameters from telegram_subscriptions where uid = ?", [update.message.chat_id]).fetchall(): subs.append("{} -> {}".format(sub[1], sub[2])) if subs is []: subs.append( "No subscriptions found. Subscribe using /sub EVENTNAME. For a list of events, send /events") self.sendMessage(chat_id=update.message.chat_id, parse_mode='HTML', text="\n{}".join(subs)) def chsub(self, msg, chatid): (cmd, evt, params) = self.tokenize(msg, 3) if cmd == "/sub": sql = "replace into telegram_subscriptions(uid, event_type, parameters) values (?, ?, ?)" else: if evt == "everything": sql = "delete from telegram_subscriptions where uid = ? and (event_type = ? or parameters = ? or 1 = 1)" # does not look very elegant, but makes unsub'ing everythign possible else: sql = "delete from telegram_subscriptions where uid = ? and event_type = ? and parameters = ?" with self.bot.database as conn: conn.execute(sql, [chatid, evt, params]) conn.commit() return def send_start(self, update): res = ( "*Commands: *", "/info - info about bot", "/login <password> - authenticate with the bot; once authenticated, your ID will be registered with the bot and survive bot restarts", "/logout - remove your ID from the 'authenticated' list", "/sub <eventName> <parameters> - subscribe to eventName, with optional parameters, event name=all will subscribe to ALL events (LOTS of output!)", "/unsub <eventName> <parameters> - unsubscribe from eventName; parameters must match the /sub parameters", "/unsub everything - will remove all subscriptions for this uid", "/showsubs - show current subscriptions", "/events <filter> - show available events, filtered by regular expression <filter>", "/top <num> <cp-or-iv-or-dated> - show top X pokemons, sorted by CP, IV, or Date", "/evolved <num> <cp-or-iv-or-dated> - show top x pokemon evolved, sorted by CP, IV, or Date", "/hatched <num> <cp-or-iv-or-dated> - show top x pokemon hatched, sorted by CP, IV, or Date", "/caught <num> <cp-or-iv-or-dated> - show top x pokemon caught, sorted by CP, IV, or Date", "/pokestops - show last x pokestops visited", "/released <num> <cp-or-iv-or-dated> - show top x released, sorted by CP, IV, or Date", "/vanished <num> <cp-or-iv-or-dated> - show top x vanished, sorted by CP, IV, or Date", "/snipe <PokemonName> <Lat,Lng> - to snipe a pokemon at location Latitude, Longitude", "/snipetime <Lat,Lng> - return time that will be taken to snipe at given location", "/luckyegg - activate luckyegg", "/luckyeggcount - return number of luckyegg", "/ordincense - activate ordinary incense", "/ordincensecount - return number of ordinary incense", "/softbans - info about possible softbans" ) self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="\n".join(res)) def is_configured(self, update): self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="No password nor master configured in TelegramTask section, bot will not accept any commands") def is_master_numeric(self, update): outMessage = "Telegram message received from correct user, but master is not numeric, updating datastore." self.bot.logger.warn(outMessage) # the "master" is not numeric, set self.master to update.message.chat_id and re-instantiate the handler newconfig = self.config newconfig['master'] = update.message.chat_id # insert chat id into database self.grab_uid(update) # remove old handler self.bot.event_manager._handlers = filter(lambda x: not isinstance(x, TelegramHandler), self.bot.event_manager._handlers) # add new handler (passing newconfig as parameter) self.bot.event_manager.add_handler(TelegramHandler(self.bot, newconfig)) def is_known_sender(self, update): # Reject message if sender does not match defined master in config outMessage = "Telegram message received from unknown sender. Please either make sure your username or ID is in TelegramTask/master, or a password is set in TelegramTask section and /login is issued" self.bot.logger.error(outMessage) self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Please /login first") def tokenize(self, string, maxnum): spl = string.split(' ', maxnum - 1) while len(spl) < maxnum: spl.append(" ") return spl def evolve(self, chatid, uid): # TODO: here comes evolve logic (later) self.sendMessage(chat_id=chatid, parse_mode='HTML', text="Evolve logic not implemented yet") return def upgrade(self, chatid, uid): # TODO: here comes upgrade logic (later) self.sendMessage(chat_id=chatid, parse_mode='HTML', text="Upgrade logic not implemented yet") return def run(self): time.sleep(1) while True: if DEBUG_ON: self.bot.logger.info("Telegram loop running") if self._tbot is None: self.connect() for update in self._tbot.getUpdates(offset=self.update_id, timeout=10): self.update_id = update.update_id + 1 if update.message: self.bot.logger.info("Telegram message from {} ({}): {}".format(update.message.from_user.username, update.message.from_user.id, update.message.text)) if re.match(r'^/login [^ ]+', update.message.text): self.authenticate(update) continue if self.config.get('password', None) == None and ( not hasattr(self, "master") or not self.config.get('master', None)):# no auth provided in config self.is_configured(update) continue if not self.isAuthenticated(update.message.from_user.id) and hasattr(self, "master") and self.master and not unicode(self.master).isnumeric() and \ unicode(self.master) == unicode(update.message.from_user.username): self.is_master_numeric(update) continue if not self.isAuthenticated(update.message.from_user.id): self.is_known_sender(update) continue # one way or another, the user is now authenticated # make sure uid is in database self.grab_uid(update) if update.message.text == "/start" or update.message.text == "/help": self.send_start(update) continue if update.message.text == "/info": self.send_info(update) continue if update.message.text == "/logout": self.send_logout(update) continue if re.match("^/events", update.message.text): self.send_events(update) continue if re.match(r'^/sub ', update.message.text): self.send_subscription_updated(update) continue if re.match(r'^/unsub ', update.message.text): self.send_subscription_updated(update) continue if re.match(r'^/showsubs', update.message.text): self.showsubs(update) continue if re.match(r'^/top ', update.message.text): (cmd, num, order) = self.tokenize(update.message.text, 3) self.send_top(update, num, order) continue if re.match(r'^/caught ', update.message.text): (cmd, num, order) = self.tokenize(update.message.text, 3) self.send_caught(update, num, order) continue if re.match(r'^/evolved ', update.message.text): (cmd, num, order) = self.tokenize(update.message.text, 3) self.send_evolved(update, num, order) continue if re.match(r'^/pokestops ', update.message.text): (cmd, num) = self.tokenize(update.message.text, 2) self.send_pokestops(update, num) continue if re.match(r'^/hatched ', update.message.text): (cmd, num, order) = self.tokenize(update.message.text, 3) self.send_hatched(update, num, order) continue if re.match(r'^/released ', update.message.text): (cmd, num, order) = self.tokenize(update.message.text, 3) self.send_released(update, num, order) continue if re.match(r'^/vanished ', update.message.text): (cmd, num, order) = self.tokenize(update.message.text, 3) self.send_vanished(update, num, order) continue if re.match(r'^/snipe ', update.message.text): try: (cmd, pkm, location) = self.tokenize(update.message.text, 3) self.request_snipe(update, pkm, location) except: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="An Error has occured") continue if re.match(r'^/snipetime ', update.message.text): try: (cmd, location) = self.tokenize(update.message.text,2) self.request_snipe_time(update, location) except: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="An Error has occured") continue if re.match(r'^/luckyeggcount', update.message.text): try: self.request_luckyegg_count(update) except: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="An Error has occured") continue if re.match(r'^/luckyegg', update.message.text): try: if self.request_luckyegg(update): self.bot.logger.info("Telegram has called for lucky egg. Success.") else: self.bot.logger.info("Telegram has called for lucky egg. Failed.") except: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="An Error has occured") continue if re.match(r'^/ordincensecount', update.message.text): try: self.request_ordincense_count(update) except: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="An Error has occured") continue if re.match(r'^/ordincense', update.message.text): try: if self.request_ordincense(update): self.bot.logger.info("Telegram has called for ordinary incense. Success.") else: self.bot.logger.info("Telegram has called for ordinary incense. Failed.") except: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="An Error has occured") continue if re.match(r'^/itime', update.message.text): try: if self.request_incensetime(update): self.bot.logger.info("Telegram has called for incense time. Success.") else: self.bot.logger.info("Telegram has called for incense time. Failed.") except: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="An Error has occured") continue if re.match(r'^/snipedisabled ', update.message.text): try: (cmd, config) = self.tokenize(update.message.text, 2) success = self.request_snipe_disable(update, config) if success: msg = "Sniper disabled" else: msg = "Sniper set as default" self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text=msg) except: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="An Error has occured") continue if re.match(r'^/softbans ', update.message.text): (cmd, num) = self.tokenize(update.message.text, 2) self.send_softbans(update, num) continue self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Unrecognized command: {}".format(update.message.text))
class TelegramClass: update_id = None def __init__(self, bot, pokemons, config): self.bot = bot request.CON_POOL_SIZE = 16 self.config = config self.chat_handler = ChatHandler(self.bot, pokemons) self.master = self.config.get('master') with self.bot.database as conn: # initialize the DB table if it does not exist yet initiator = TelegramDBInit(bot.database) if unicode(self.master).isnumeric(): # master is numeric self.bot.logger.info("Telegram master is valid (numeric): {}".format(self.master)) elif self.master is not None: # Master is not numeric, fetch from db self.bot.logger.info("Telegram master is not numeric: {}".format(self.master)) c = conn.cursor() srchmaster = re.sub(r'^@', '', self.master) c.execute("SELECT uid from telegram_uids where username = '******'".format(srchmaster)) results = c.fetchall() if len(results) > 0: # woohoo, we already saw a message from this master and therefore have a uid self.bot.logger.info("Telegram master UID from datastore: {}".format(results[0][0])) self.master = results[0][0] else: # uid not known yet self.bot.logger.info("Telegram master UID not in datastore yet") self.pokemons = pokemons self._tbot = None self.config = config def connect(self): if DEBUG_ON: self.bot.logger.info("Not connected. Reconnecting") self._tbot = telegram.Bot(self.bot.config.telegram_token) try: self.update_id = self._tbot.getUpdates()[0].update_id except IndexError: self.update_id = None def grab_uid(self, update): with self.bot.database as conn: conn.execute("replace into telegram_uids (uid, username) values (?, ?)", (update.message.chat_id, update.message.from_user.username)) conn.commit() if self.master: self.master = update.message.chat_id def isMasterFromConfigFile(self, chat_id): if not hasattr(self, "master") or not self.master: return False if unicode(self.master).isnumeric(): return unicode(chat_id) == unicode(self.master) else: with self.bot.database as conn: cur = conn.cursor() cur.execute("select username from telegram_uids where uid = ?", [chat_id]) res = cur.fetchone() return res != None and unicode(res[0]) == unicode(re.replace(r'^@', '', self.master)) def isMasterFromActiveLogins(self, chat_id): with self.bot.database as conn: cur = conn.cursor() cur.execute("select count(1) from telegram_logins where uid = ?", [chat_id]) res = cur.fetchone() if res[0] == 1: return True return False def isAuthenticated(self, chat_id): return self.isMasterFromConfigFile(chat_id) or self.isMasterFromActiveLogins(chat_id) def deauthenticate(self, update): with self.bot.database as conn: cur = conn.cursor() sql = "delete from telegram_logins where uid = {}".format(update.message.chat_id) cur.execute(sql) conn.commit() self.chat_handler.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Logout completed") return def authenticate(self, update): args = update.message.text.split(' ') if len(args) != 2: self.chat_handler.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Invalid password") return password = args[1] if password != self.config.get('password', None): self.chat_handler.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Invalid password") else: with self.bot.database as conn: cur = conn.cursor() cur.execute("insert or replace into telegram_logins(uid) values(?)",[update.message.chat_id]) conn.commit() self.chat_handler.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Authentication successful, you can now use all commands") return def run(self): time.sleep(1) while True: if DEBUG_ON: self.bot.logger.info("Telegram loop running") if self._tbot is None: self.connect() for update in self._tbot.getUpdates(offset=self.update_id, timeout=10): self.update_id = update.update_id + 1 if update.message: self.bot.logger.info("Telegram message from {} ({}): {}".format(update.message.from_user.username, update.message.from_user.id, update.message.text)) if update.message.text == "/start" or update.message.text == "/help": res = ( "*Commands: *", "/info - info about bot", "/login <password> - authenticate with the bot; once authenticated, your ID will be registered with the bot and survive bot restarts", "/logout - remove your ID from the 'authenticated' list", "/sub <eventName> <parameters> - subscribe to eventName, with optional parameters, event name=all will subscribe to ALL events (LOTS of output!)", "/unsub <eventName> <parameters> - unsubscribe from eventName; parameters must match the /sub parameters", "/unsub everything - will remove all subscriptions for this uid", "/showsubs - show current subscriptions", "/events <filter> - show available events, filtered by regular expression <filter>", "/top <num> <cp-or-iv-or-dated> - show top X pokemons, sorted by CP, IV, or Date", "/evolved <num> <cp-or-iv-or-dated> - show top x pokemon evolved, sorted by CP, IV, or Date", "/hatched <num> <cp-or-iv-or-dated> - show top x pokemon hatched, sorted by CP, IV, or Date", "/caught <num> <cp-or-iv-or-dated> - show top x pokemon caught, sorted by CP, IV, or Date", "/pokestops - show last x pokestops visited", "/released <num> <cp-or-iv-or-dated> - show top x released, sorted by CP, IV, or Date", "/vanished <num> <cp-or-iv-or-dated> - show top x vanished, sorted by CP, IV, or Date", "/softbans - info about possible softbans" ) self.chat_handler.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="\n".join(res)) continue if self.config.get('password', None) == None and ( not hasattr(self, "master") or not self.config.get('master', None)): # no auth provided in config self.chat_handler.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="No password nor master configured in TelegramTask section, bot will not accept any commands") continue if re.match(r'^/login [^ ]+', update.message.text): self.authenticate(update) continue if not self.isAuthenticated(update.message.from_user.id) and hasattr(self, "master") and self.master and not unicode(self.master).isnumeric() and \ unicode(self.master) == unicode(update.message.from_user.username): outMessage = "Telegram message received from correct user, but master is not numeric, updating datastore." self.bot.logger.warn(outMessage) # the "master" is not numeric, set self.master to update.message.chat_id and re-instantiate the handler newconfig = self.config newconfig['master'] = update.message.chat_id # insert chat id into database self.grab_uid(update) # remove old handler self.bot.event_manager._handlers = filter(lambda x: not isinstance(x, TelegramHandler), self.bot.event_manager._handlers) # add new handler (passing newconfig as parameter) self.bot.event_manager.add_handler(TelegramHandler(self.bot, newconfig)) continue if not self.isAuthenticated(update.message.from_user.id): # Reject message if sender does not match defined master in config outMessage = "Telegram message received from unknown sender. Please either make sure your username or ID is in TelegramTask/master, or a password is set in TelegramTask section and /login is issued" self.bot.logger.error(outMessage) self.chat_handler.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Please /login first") continue # one way or another, the user is now authenticated # make sure uid is in database self.grab_uid(update) if update.message.text == "/info": self.chat_handler.send_player_stats_to_chat(update.message.chat_id) continue if update.message.text == "/softbans": self.chat_handler.get_softban(update.message.chat_id) continue if re.match("^/events", update.message.text): events = self.chat_handler.get_events(update) self.chat_handler.sendMessage(chat_id=update.message.chat_id, parse_mode='HTML', text="\n".join(events)) continue if update.message.text == "/logout": self.chat_handler.sendMessage(chat_id=update.message.chat_id, parse_mode='HTML', text=("Logged out.")) self.deauthenticate(update) continue if re.match(r'^/sub ', update.message.text): self.chsub(update.message.text, update.message.chat_id) self.chat_handler.sendMessage(chat_id=update.message.chat_id, parse_mode='HTML', text=("Subscriptions updated.")) continue if re.match(r'^/unsub ', update.message.text): self.chsub(update.message.text, update.message.chat_id) self.chat_handler.sendMessage(chat_id=update.message.chat_id, parse_mode='HTML', text=("Subscriptions updated.")) continue if re.match(r'^/showsubs', update.message.text): self.showsubs(update.message.chat_id) continue if re.match(r'^/top ', update.message.text): (cmd, num, order) = self.tokenize(update.message.text, 3) self.chat_handler.showtop(update.message.chat_id, num, order) continue if re.match(r'^/caught ', update.message.text): (cmd, num, order) = self.tokenize(update.message.text, 3) self.chat_handler.get_caught(update.message.chat_id, num, order) continue if re.match(r'^/evolved ', update.message.text): (cmd, num, order) = self.tokenize(update.message.text, 3) self.chat_handler.get_evolved(update.message.chat_id, num, order) continue if re.match(r'^/pokestops ', update.message.text): (cmd, num) = self.tokenize(update.message.text, 2) self.chat_handler.get_pokestops(update.message.chat_id, num) continue if re.match(r'^/hatched ', update.message.text): (cmd, num, order) = self.tokenize(update.message.text, 3) self.chat_handler.get_hatched(update.message.chat_id, num, order) continue if re.match(r'^/released ', update.message.text): (cmd, num, order) = self.tokenize(update.message.text, 3) self.chat_handler.get_released(update.message.chat_id, num, order) continue if re.match(r'^/vanished ', update.message.text): (cmd, num, order) = self.tokenize(update.message.text, 3) self.chat_handler.get_vanished(update.message.chat_id, num, order) continue self.chat_handler.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Unrecognized command: {}".format(update.message.text)) def showsubs(self, chatid): subs = [] with self.bot.database as conn: for sub in conn.execute("select uid, event_type, parameters from telegram_subscriptions where uid = ?", [chatid]).fetchall(): if "{}".format(sub[2]) not in ["", " "]: subs.append("<b>{}</b> -> .{}.".format(sub[1], sub[2])) else: subs.append("<b>{}</b>".format(sub[1])) if subs == []: subs.append( "No subscriptions found. Subscribe using /sub EVENTNAME. For a list of events, send /events") self.chat_handler.sendMessage(chat_id=chatid, parse_mode='HTML', text="\n".join(subs)) def chsub(self, msg, chatid): (cmd, evt, params) = self.tokenize(msg, 3) if cmd == "/sub": sql = "replace into telegram_subscriptions(uid, event_type, parameters) values (?, ?, ?)" else: if evt == "everything": sql = "delete from telegram_subscriptions where uid = ? and (event_type = ? or parameters = ? or 1 = 1)" # does not look very elegant, but makes unsub'ing everythign possible else: sql = "delete from telegram_subscriptions where uid = ? and event_type = ? and parameters = ?" with self.bot.database as conn: conn.execute(sql, [chatid, evt, params]) conn.commit() return def tokenize(self, string, maxnum): spl = string.split(' ', maxnum - 1) while len(spl) < maxnum: spl.append(" ") return spl
class TelegramHandler(EventHandler): def __init__(self, bot, config): initiator = TelegramDBInit(bot.database) self.bot = bot self.tbot = None self.pokemons = config.get('alert_catch', {}) self.whoami = "TelegramHandler" self.config = config self.chat_handler = ChatHandler(self.bot, self.pokemons) self._connect() def _connect(self): if self.tbot is None: self.bot.logger.info("Telegram bot not running. Starting") self.tbot = TelegramClass(self.bot, self.pokemons, self.config) thread.start_new_thread(self.tbot.run) return self.tbot def catch_notify(self, pokemon, cp, iv, params): if params == " ": return True try: oper = re.search(r'operator:([^ ]+)', params).group(1) rule_cp = int(re.search(r'cp:([0-9]+)', params).group(1)) rule_iv = float(re.search(r'iv:([0-9.]+)', params).group(1)) rule_pkmn = re.search(r'pokemon:([^ ]+)', params).group(1) return rule_pkmn == pokemon and (oper == "or" and (cp >= rule_cp or iv >= rule_iv) or cp >= rule_cp and iv >= rule_iv) except: return False def handle_event(self, event, sender, level, formatted_msg, data): msg = None # first handle subscriptions; they are independent of master setting. with self.bot.database as conn: subs = conn.execute( "select uid, parameters, event_type from telegram_subscriptions where event_type in (?,'all','debug')", [event]).fetchall() for sub in subs: if DEBUG_ON: self.bot.logger.info("Processing sub {}".format(sub)) (uid, params, event_type) = sub if not self.tbot.isAuthenticated( uid): # UID has subs but not in auth list. return if event != 'pokemon_caught' or self.catch_notify( data["pokemon"], int(data["cp"]), float(data["iv"]), params): if DEBUG_ON: self.bot.logger.info("Matched sub {} event {}".format( sub, event)) elif event_type == "debug": self.bot.logger.info("[{}] {}".format(event, msg)) else: msg = self.chat_handler.get_event( event, formatted_msg, data) if DEBUG_ON: self.bot.logger.info("Telegram message {}".format(msg)) if msg is None: return else: if DEBUG_ON: self.bot.logger.info("No match sub {} event {}".format( sub, event)) if msg is not None: if self.tbot is None: # instantiate tbot (TelegramClass) if not already set if DEBUG_ON: self.bot.logger.info( "handle_event Telegram bot not running.") try: self._connect() except Exception as inst: self.bot.logger.error( "Unable to start Telegram bot; exception: {}".format( pprint.pformat(inst))) self.tbot = None return if self.tbot is not None: # tbot should be running, but just in case it hasn't started yet self.tbot.sendMessage(chat_id=uid, parse_mode='Markdown', text=msg)
class TelegramClass: update_id = None def __init__(self, bot, pokemons, config): self.bot = bot request.CON_POOL_SIZE = 16 self.config = config self.chat_handler = ChatHandler(self.bot, pokemons) self.master = self.config.get('master') with self.bot.database as conn: # initialize the DB table if it does not exist yet initiator = TelegramDBInit(bot.database) if unicode(self.master).isnumeric(): # master is numeric self.bot.logger.info( "Telegram master is valid (numeric): {}".format( self.master)) elif self.master is not None: # Master is not numeric, fetch from db self.bot.logger.info( "Telegram master is not numeric: {}".format(self.master)) c = conn.cursor() srchmaster = re.sub(r'^@', '', self.master) c.execute( "SELECT uid from telegram_uids where username = '******'". format(srchmaster)) results = c.fetchall() if len( results ) > 0: # woohoo, we already saw a message from this master and therefore have a uid self.bot.logger.info( "Telegram master UID from datastore: {}".format( results[0][0])) self.master = results[0][0] else: # uid not known yet self.bot.logger.info( "Telegram master UID not in datastore yet") self.pokemons = pokemons self._tbot = None self.config = config self.master = None def connect(self): if DEBUG_ON: self.bot.logger.info("Not connected. Reconnecting") self._tbot = telegram.Bot(self.bot.config.telegram_token) try: self.update_id = self._tbot.getUpdates()[0].update_id except IndexError: self.update_id = None def grab_uid(self, update): with self.bot.database as conn: conn.execute( "replace into telegram_uids (uid, username) values (?, ?)", (update.message.chat_id, update.message.from_user.username)) conn.commit() if self.master: self.master = update.message.chat_id def isMasterFromConfigFile(self, chat_id): if not hasattr(self, "master") or not self.master: return False if unicode(self.master).isnumeric(): return unicode(chat_id) == unicode(self.master) else: with self.bot.database as conn: cur = conn.cursor() cur.execute("select username from telegram_uids where uid = ?", [chat_id]) res = cur.fetchone() return res != None and unicode(res[0]) == unicode( re.replace(r'^@', '', self.master)) def isMasterFromActiveLogins(self, chat_id): with self.bot.database as conn: cur = conn.cursor() cur.execute("select count(1) from telegram_logins where uid = ?", [chat_id]) res = cur.fetchone() if res[0] == 1: return True return False def isAuthenticated(self, chat_id): return self.isMasterFromConfigFile( chat_id) or self.isMasterFromActiveLogins(chat_id) def deauthenticate(self, update): with self.bot.database as conn: cur = conn.cursor() sql = "delete from telegram_logins where uid = {}".format( update.message.chat_id) cur.execute(sql) conn.commit() self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Logout completed") return def authenticate(self, update): args = update.message.text.split(' ') if len(args) != 2: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Invalid password") return password = args[1] if password != self.config.get('password', None): self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Invalid password") else: with self.bot.database as conn: cur = conn.cursor() cur.execute( "insert or replace into telegram_logins(uid) values(?)", [update.message.chat_id]) conn.commit() self.sendMessage( chat_id=update.message.chat_id, parse_mode='Markdown', text="Authentication successful, you can now use all commands") return def sendMessage(self, chat_id=None, parse_mode='Markdown', text=None): try: if self._tbot is None: self.connect() self._tbot.sendMessage(chat_id=chat_id, parse_mode=parse_mode, text=text) except telegram.error.NetworkError: time.sleep(1) except telegram.error.TelegramError: time.sleep(10) except telegram.error.Unauthorized: self.update_id += 1 def sendLocation(self, chat_id, latitude, longitude): try: self._tbot.send_location(chat_id=chat_id, latitude=latitude, longitude=longitude) except telegram.error.NetworkError: time.sleep(1) except telegram.error.TelegramError: time.sleep(10) except telegram.error.Unauthorized: self.update_id += 1 def send_player_stats_to_chat(self, chat_id): stats = self.chat_handler.get_player_stats() if stats: self.sendMessage( chat_id=chat_id, parse_mode='Markdown', text= "*{}* \n_Level:_ {} \n_XP:_ {}/{} \n_Pokemons Captured:_ {} ({} _last 24h_) \n_Poke Stop Visits:_ {} ({} _last 24h_) \n_KM Walked:_ {} \n_Stardust:_ {}" .format(stats[0], stats[1], stats[2], stats[3], stats[4], stats[5], stats[6], stats[7], stats[8], stats[9])) self.sendLocation(chat_id=chat_id, latitude=self.bot.api._position_lat, longitude=self.bot.api._position_lng) else: self.sendMessage(chat_id=chat_id, parse_mode='Markdown', text="Stats not loaded yet\n") def send_event(self, event, formatted_msg, data): return self.chat_handler.get_event(event, formatted_msg, data) def send_events(self, update): events = self.chat_handler.get_events(update) self.sendMessage(chat_id=update.message.chat_id, parse_mode='HTML', text="\n".join(events)) def send_softbans(self, update, num): softbans = self.chat_handler.get_softbans(num) outMsg = '' if softbans: for x in softbans: outMsg += '*' + x[0] + '* ' + '(' + str(x[2]) + ')\n' self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="".join(outMsg)) else: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="No Softbans found! Good job!\n") def send_subscription_updated(self, update): self.chsub(update.message.text, update.message.chat_id) self.sendMessage(chat_id=update.message.chat_id, parse_mode='HTML', text=("Subscriptions updated.")) def send_info(self, update): self.send_player_stats_to_chat(update.message.chat_id) def send_logout(self, update): self.sendMessage(chat_id=update.message.chat_id, parse_mode='HTML', text=("Logged out.")) self.deauthenticate(update) def send_caught(self, update, num, order): caught = self.chat_handler.get_caught(num, order) outMsg = '' if caught: for x in caught: outMsg += '*' + x[0] + '* ' + '(_CP:_ ' + str(int( x[1])) + ' _IV:_ ' + str(x[2]) + ')\n' self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="".join(outMsg)) else: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="No Pokemon Caught Yet.\n") def request_snipe(self, update, pkm, lat, lng): snipeSuccess = False try: id = Pokemons.id_for(pkm) except: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Invaild Pokemon") return #Set Telegram Snipe to true and let sniper do its work TelegramSnipe.ENABLED = True TelegramSnipe.ID = int(id) TelegramSnipe.POKEMON_NAME = str(pkm) TelegramSnipe.LATITUDE = float(lat) TelegramSnipe.LONGITUDE = float(lng) outMsg = 'Catching pokemon: ' + TelegramSnipe.POKEMON_NAME + ' at Latitude: ' + str( TelegramSnipe.LATITUDE) + ' Longitude: ' + str( TelegramSnipe.LONGITUDE) + '\n' self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="".join(outMsg)) def request_snipe_time(self, update, lat, lng): last_position = self.bot.position[0:2] snipe_distance = convert( distance(last_position[0], last_position[1], float(lat), float(lng)), "m", "km") time_to_snipe = wait_time_sec(snipe_distance) / 60 if time_to_snipe <= 900: outMsg = "Estimate Time to Snipe: " + "{0:.2f}".format( time_to_snipe) + " Mins. Distance: " + "{0:.2f}".format( snipe_distance) + "KM" self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="".join(outMsg)) else: self.sendMessage( chat_id=update.message.chat_id, parse_mode='Markdown', text="Sniping distance is more than supported distance") def request_snipe_disable(self, update, config): if config.lower() == "true": TelegramSnipe.SNIPE_DISABLED = True return True else: TelegramSnipe.SNIPE_DISABLED = False return False def send_evolved(self, update, num, order): evolved = self.chat_handler.get_evolved(num, order) outMsg = '' if evolved: for x in evolved: outMsg += '*' + x[0] + '* ' + '(_CP:_ ' + str(int( x[1])) + ' _IV:_ ' + str(x[2]) + ')\n' self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="".join(outMsg)) else: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="No Evolutions Found.\n") def request_luckyegg_count(self, update): lucky_egg = inventory.items().get( Item.ITEM_LUCKY_EGG.value) # @UndefinedVariable self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Lucky Egg Count: " + str(lucky_egg.count)) def request_ordincense_count(self, update): ord_incense = inventory.items().get( Item.ITEM_INCENSE_ORDINARY.value) # @UndefinedVariable self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Ordinary Incense Count: " + str(ord_incense.count)) def request_luckyegg(self, update): lucky_egg = inventory.items().get( Item.ITEM_LUCKY_EGG.value) # @UndefinedVariable if lucky_egg.count == 0: return False response_dict = self.bot.use_lucky_egg() if not response_dict: self.bot.logger.info("Telegram Request: Failed to use lucky egg!") self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Failed to use lucky egg!\n") return False result = response_dict.get("responses", {}).get("USE_ITEM_XP_BOOST", {}).get("result", 0) if result == SUCCESS: lucky_egg.remove(1) self.bot.logger.info( "Telegram Request: Used lucky egg, {} left.".format( lucky_egg.count)) self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Used lucky egg, " + str(lucky_egg.count) + " left.") return True elif result == ERROR_XP_BOOST_ALREADY_ACTIVE: self.bot.logger.info( "Telegram Request: Lucky egg already active, {} left.".format( lucky_egg.count)) self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Lucky egg already active, " + str(lucky_egg.count) + " left.") return True else: self.bot.logger.info("Telegram Request: Failed to use lucky egg!") self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Failed to use lucky egg!\n") return False def request_ordincense(self, update): ord_incense = inventory.items().get( Item.ITEM_INCENSE_ORDINARY.value) # @UndefinedVariable if ord_incense.count == 0: return False request = self.bot.api.create_request() request.use_incense(incense_type=401) response_dict = request.call() if not response_dict: self.bot.logger.info( "Telegram Request: Failed to use ordinary incense!") self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Failed to use ordinary incense!\n") return False result = response_dict.get('responses', {}).get('USE_INCENSE', {}).get('result', 0) self.bot.logger.info("Result = " + str(result)) if result == SUCCESS: ord_incense.remove(1) self.bot.logger.info( "Telegram Request: Used ordinary incense, {} left.".format( ord_incense.count)) self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Used ordinary incense, " + str(ord_incense.count) + " left.") return True elif result == ERROR_INCENSE_ALREADY_ACTIVE: self.bot.logger.info( "Telegram Request: Ordinary incense already active, {} left.". format(ord_incense.count)) self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Ordinary incense already active, " + str(ord_incense.count) + " left and has " + str(currentincense.expire_ms) + " remaining") return True else: self.bot.logger.info( "Telegram Request: Failed to use ordinary incense! Result=" + str(result)) self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Failed to use ordinary incense!\n") return False def request_incensetime(self, update): self.bot.logger.info("Time Started") currentincense = inventory.applied_items().get('401') self.bot.logger.info(currentincense) #self.bot.logger.info(currentincense.expire_ms) return True def send_pokestops(self, update, num): pokestops = self.chat_handler.get_pokestops(num) outMsg = '' if pokestops: for x in pokestops: outMsg += '*' + x[0] + '* ' + '(_XP:_ ' + str( x[1]) + ' _Items:_ ' + str(x[2]) + ')\n' self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="".join(outMsg)) else: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="No Pokestops Encountered Yet.\n") def send_hatched(self, update, num, order): hatched = self.chat_handler.get_hatched(num, order) outMsg = '' if hatched: for x in hatched: outMsg += '*' + x[0] + '* ' + '(_CP:_ ' + str(int( x[1])) + ' _IV:_ ' + str(x[2]) + ')\n' self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="".join(outMsg)) else: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="No Eggs Hatched Yet.\n") def send_released(self, update, num, order): released = self.chat_handler.get_released(num, order) outMsg = '' if released: for x in released: outMsg += '*' + x[0] + '* ' + '(_CP:_ ' + str(int( x[1])) + ' _IV:_ ' + str(x[2]) + ')\n' self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="".join(outMsg)) else: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="No Pokemon Released Yet.\n") def send_vanished(self, update, num, order): vanished = self.chat_handler.get_vanished(num, order) outMsg = '' if vanished: for x in vanished: outMsg += '*' + x[0] + '* ' + '(_CP:_ ' + str(int( x[1])) + ' _IV:_ ' + str(x[2]) + ')\n' self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text=outMsg) def send_top(self, update, num, order): top = self.chat_handler.get_top(num, order) outMsg = '' for x in top: outMsg += "*{}* _CP:_ {} _IV:_ {} (Candy: {})\n".format( x[0], x[1], x[2], x[3]) self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text=outMsg) def showsubs(self, update): subs = [] with self.bot.database as conn: for sub in conn.execute( "select uid, event_type, parameters from telegram_subscriptions where uid = ?", [update.message.chat_id]).fetchall(): subs.append("{} -> {}".format(sub[1], sub[2])) if subs is []: subs.append( "No subscriptions found. Subscribe using /sub EVENTNAME. For a list of events, send /events" ) self.sendMessage(chat_id=update.message.chat_id, parse_mode='HTML', text="\n{}".join(subs)) def chsub(self, msg, chatid): (cmd, evt, params) = self.tokenize(msg, 3) if cmd == "/sub": sql = "replace into telegram_subscriptions(uid, event_type, parameters) values (?, ?, ?)" else: if evt == "everything": sql = "delete from telegram_subscriptions where uid = ? and (event_type = ? or parameters = ? or 1 = 1)" # does not look very elegant, but makes unsub'ing everythign possible else: sql = "delete from telegram_subscriptions where uid = ? and event_type = ? and parameters = ?" with self.bot.database as conn: conn.execute(sql, [chatid, evt, params]) conn.commit() return def send_start(self, update): res = ( "*Commands: *", "/info - info about bot", "/login <password> - authenticate with the bot; once authenticated, your ID will be registered with the bot and survive bot restarts", "/logout - remove your ID from the 'authenticated' list", "/sub <eventName> <parameters> - subscribe to eventName, with optional parameters, event name=all will subscribe to ALL events (LOTS of output!)", "/unsub <eventName> <parameters> - unsubscribe from eventName; parameters must match the /sub parameters", "/unsub everything - will remove all subscriptions for this uid", "/showsubs - show current subscriptions", "/events <filter> - show available events, filtered by regular expression <filter>", "/top <num> <cp-or-iv-or-dated> - show top X pokemons, sorted by CP, IV, or Date", "/evolved <num> <cp-or-iv-or-dated> - show top x pokemon evolved, sorted by CP, IV, or Date", "/hatched <num> <cp-or-iv-or-dated> - show top x pokemon hatched, sorted by CP, IV, or Date", "/caught <num> <cp-or-iv-or-dated> - show top x pokemon caught, sorted by CP, IV, or Date", "/pokestops - show last x pokestops visited", "/released <num> <cp-or-iv-or-dated> - show top x released, sorted by CP, IV, or Date", "/vanished <num> <cp-or-iv-or-dated> - show top x vanished, sorted by CP, IV, or Date", "/snipe <PokemonName> <Lat> <Lng> - to snipe a pokemon at location Latitude, Longitude", "/snipetime <Lag> <Lng> - return time that will be teaken to snipe at given location", "/luckyegg - activate luckyegg", "/luckyeggcount - return number of luckyegg", "/ordincense - activate ordinary incense", "/ordincensecount - return number of ordinary incense", "/softbans - info about possible softbans") self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="\n".join(res)) def is_configured(self, update): self.sendMessage( chat_id=update.message.chat_id, parse_mode='Markdown', text= "No password nor master configured in TelegramTask section, bot will not accept any commands" ) def is_master_numeric(self, update): outMessage = "Telegram message received from correct user, but master is not numeric, updating datastore." self.bot.logger.warn(outMessage) # the "master" is not numeric, set self.master to update.message.chat_id and re-instantiate the handler newconfig = self.config newconfig['master'] = update.message.chat_id # insert chat id into database self.grab_uid(update) # remove old handler self.bot.event_manager._handlers = filter( lambda x: not isinstance(x, TelegramHandler), self.bot.event_manager._handlers) # add new handler (passing newconfig as parameter) self.bot.event_manager.add_handler(TelegramHandler( self.bot, newconfig)) def is_known_sender(self, update): # Reject message if sender does not match defined master in config outMessage = "Telegram message received from unknown sender. Please either make sure your username or ID is in TelegramTask/master, or a password is set in TelegramTask section and /login is issued" self.bot.logger.error(outMessage) self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Please /login first") def tokenize(self, string, maxnum): spl = string.split(' ', maxnum - 1) while len(spl) < maxnum: spl.append(" ") return spl def evolve(self, chatid, uid): # TODO: here comes evolve logic (later) self.sendMessage(chat_id=chatid, parse_mode='HTML', text="Evolve logic not implemented yet") return def upgrade(self, chatid, uid): # TODO: here comes upgrade logic (later) self.sendMessage(chat_id=chatid, parse_mode='HTML', text="Upgrade logic not implemented yet") return def run(self): time.sleep(1) while True: if DEBUG_ON: self.bot.logger.info("Telegram loop running") if self._tbot is None: self.connect() for update in self._tbot.getUpdates(offset=self.update_id, timeout=10): self.update_id = update.update_id + 1 if update.message: self.bot.logger.info( "Telegram message from {} ({}): {}".format( update.message.from_user.username, update.message.from_user.id, update.message.text)) if re.match(r'^/login [^ ]+', update.message.text): self.authenticate(update) continue if self.config.get('password', None) == None and ( not hasattr(self, "master") or not self.config.get( 'master', None)): # no auth provided in config self.is_configured(update) continue if not self.isAuthenticated(update.message.from_user.id) and hasattr(self, "master") and self.master and not unicode(self.master).isnumeric() and \ unicode(self.master) == unicode(update.message.from_user.username): self.is_master_numeric(update) continue if not self.isAuthenticated(update.message.from_user.id): self.is_known_sender(update) continue # one way or another, the user is now authenticated # make sure uid is in database self.grab_uid(update) if update.message.text == "/start" or update.message.text == "/help": self.send_start(update) continue if update.message.text == "/info": self.send_info(update) continue if update.message.text == "/logout": self.send_logout(update) continue if re.match("^/events", update.message.text): self.send_events(update) continue if re.match(r'^/sub ', update.message.text): self.send_subscription_updated(update) continue if re.match(r'^/unsub ', update.message.text): self.send_subscription_updated(update) continue if re.match(r'^/showsubs', update.message.text): self.showsubs(update) continue if re.match(r'^/top ', update.message.text): (cmd, num, order) = self.tokenize(update.message.text, 3) self.send_top(update, num, order) continue if re.match(r'^/caught ', update.message.text): (cmd, num, order) = self.tokenize(update.message.text, 3) self.send_caught(update, num, order) continue if re.match(r'^/evolved ', update.message.text): (cmd, num, order) = self.tokenize(update.message.text, 3) self.send_evolved(update, num, order) continue if re.match(r'^/pokestops ', update.message.text): (cmd, num) = self.tokenize(update.message.text, 2) self.send_pokestops(update, num) continue if re.match(r'^/hatched ', update.message.text): (cmd, num, order) = self.tokenize(update.message.text, 3) self.send_hatched(update, num, order) continue if re.match(r'^/released ', update.message.text): (cmd, num, order) = self.tokenize(update.message.text, 3) self.send_released(update, num, order) continue if re.match(r'^/vanished ', update.message.text): (cmd, num, order) = self.tokenize(update.message.text, 3) self.send_vanished(update, num, order) continue if re.match(r'^/snipe ', update.message.text): try: (cmd, pkm, lat, lng) = self.tokenize(update.message.text, 4) self.request_snipe(update, pkm, lat, lng) except: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="An Error has occured") continue if re.match(r'^/snipetime ', update.message.text): try: (cmd, lat, lng) = self.tokenize(update.message.text, 3) self.request_snipe_time(update, lat, lng) except: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="An Error has occured") continue if re.match(r'^/luckyeggcount', update.message.text): try: self.request_luckyegg_count(update) except: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="An Error has occured") continue if re.match(r'^/luckyegg', update.message.text): try: if self.request_luckyegg(update): self.bot.logger.info( "Telegram has called for lucky egg. Success." ) else: self.bot.logger.info( "Telegram has called for lucky egg. Failed." ) except: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="An Error has occured") continue if re.match(r'^/ordincensecount', update.message.text): try: self.request_ordincense_count(update) except: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="An Error has occured") continue if re.match(r'^/ordincense', update.message.text): try: if self.request_ordincense(update): self.bot.logger.info( "Telegram has called for ordinary incense. Success." ) else: self.bot.logger.info( "Telegram has called for ordinary incense. Failed." ) except: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="An Error has occured") continue if re.match(r'^/itime', update.message.text): try: if self.request_incensetime(update): self.bot.logger.info( "Telegram has called for incense time. Success." ) else: self.bot.logger.info( "Telegram has called for incense time. Failed." ) except: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="An Error has occured") continue if re.match(r'^/snipedisabled ', update.message.text): try: (cmd, config) = self.tokenize(update.message.text, 2) success = self.request_snipe_disable( update, config) if success: msg = "Sniper disabled" else: msg = "Sniper set as default" self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text=msg) except: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="An Error has occured") continue if re.match(r'^/softbans ', update.message.text): (cmd, num) = self.tokenize(update.message.text, 2) self.send_softbans(update, num) continue self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Unrecognized command: {}".format( update.message.text))
from chat_handler import ChatHandler if __name__ == "__main__": chatHandler = ChatHandler('localhost', 4006) chatHandler.start()
def conversations_main(conversations): res_list = [] for conversation in conversations: app = ChatHandler().main(conversation) res_list.append((conversation.title, app)) return res_list
class TelegramClass: update_id = None def __init__(self, bot, pokemons, config): self.bot = bot request.CON_POOL_SIZE = 16 self.config = config self.chat_handler = ChatHandler(self.bot, pokemons) self.master = self.config.get('master') with self.bot.database as conn: # initialize the DB table if it does not exist yet initiator = TelegramDBInit(bot.database) if unicode(self.master).isnumeric(): # master is numeric self.bot.logger.info( "Telegram master is valid (numeric): {}".format( self.master)) elif self.master is not None: # Master is not numeric, fetch from db self.bot.logger.info( "Telegram master is not numeric: {}".format(self.master)) c = conn.cursor() srchmaster = re.sub(r'^@', '', self.master) c.execute( "SELECT uid from telegram_uids where username = '******'". format(srchmaster)) results = c.fetchall() if len( results ) > 0: # woohoo, we already saw a message from this master and therefore have a uid self.bot.logger.info( "Telegram master UID from datastore: {}".format( results[0][0])) self.master = results[0][0] else: # uid not known yet self.bot.logger.info( "Telegram master UID not in datastore yet") self.pokemons = pokemons self._tbot = None self.config = config self.master = None def connect(self): if DEBUG_ON: self.bot.logger.info("Not connected. Reconnecting") self._tbot = telegram.Bot(self.bot.config.telegram_token) try: self.update_id = self._tbot.getUpdates()[0].update_id except IndexError: self.update_id = None def grab_uid(self, update): with self.bot.database as conn: conn.execute( "replace into telegram_uids (uid, username) values (?, ?)", (update.message.chat_id, update.message.from_user.username)) conn.commit() if self.master: self.master = update.message.chat_id def isMasterFromConfigFile(self, chat_id): if not hasattr(self, "master") or not self.master: return False if unicode(self.master).isnumeric(): return unicode(chat_id) == unicode(self.master) else: with self.bot.database as conn: cur = conn.cursor() cur.execute("select username from telegram_uids where uid = ?", [chat_id]) res = cur.fetchone() return res != None and unicode(res[0]) == unicode( re.replace(r'^@', '', self.master)) def isMasterFromActiveLogins(self, chat_id): with self.bot.database as conn: cur = conn.cursor() cur.execute("select count(1) from telegram_logins where uid = ?", [chat_id]) res = cur.fetchone() if res[0] == 1: return True return False def isAuthenticated(self, chat_id): return self.isMasterFromConfigFile( chat_id) or self.isMasterFromActiveLogins(chat_id) def deauthenticate(self, update): with self.bot.database as conn: cur = conn.cursor() sql = "delete from telegram_logins where uid = {}".format( update.message.chat_id) cur.execute(sql) conn.commit() self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Logout completed") return def authenticate(self, update): args = update.message.text.split(' ') if len(args) != 2: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Invalid password") return password = args[1] if password != self.config.get('password', None): self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Invalid password") else: with self.bot.database as conn: cur = conn.cursor() cur.execute( "insert or replace into telegram_logins(uid) values(?)", [update.message.chat_id]) conn.commit() self.sendMessage( chat_id=update.message.chat_id, parse_mode='Markdown', text="Authentication successful, you can now use all commands") return def sendMessage(self, chat_id=None, parse_mode='Markdown', text=None): try: if self._tbot is None: self.connect() self._tbot.sendMessage(chat_id=chat_id, parse_mode=parse_mode, text=text) except telegram.error.NetworkError: time.sleep(1) except telegram.error.TelegramError: time.sleep(10) except telegram.error.Unauthorized: self.update_id += 1 def sendLocation(self, chat_id, latitude, longitude): try: self._tbot.send_location(chat_id=chat_id, latitude=latitude, longitude=longitude) except telegram.error.NetworkError: time.sleep(1) except telegram.error.TelegramError: time.sleep(10) except telegram.error.Unauthorized: self.update_id += 1 def send_player_stats_to_chat(self, chat_id): stats = self.chat_handler.get_player_stats() if stats: self.sendMessage( chat_id=chat_id, parse_mode='Markdown', text= "*{}* \n_Level:_ {} \n_XP:_ {}/{} \n_Pokemons Captured:_ {} ({} _last 24h_) \n_Poke Stop Visits:_ {} ({} _last 24h_) \n_KM Walked:_ {} \n_Stardust:_ {}" .format(stats[0], stats[1], stats[2], stats[3], stats[4], stats[5], stats[6], stats[7], stats[8], stats[9])) self.sendLocation(chat_id=chat_id, latitude=self.bot.api._position_lat, longitude=self.bot.api._position_lng) else: self.sendMessage(chat_id=chat_id, parse_mode='Markdown', text="Stats not loaded yet\n") def send_event(self, event, formatted_msg, data): return self.chat_handler.get_event(event, formatted_msg, data) def send_events(self, update): events = self.chat_handler.get_events(update) self.sendMessage(chat_id=update.message.chat_id, parse_mode='HTML', text="\n".join(events)) def send_softbans(self, update, num): softbans = self.chat_handler.get_softbans(num) outMsg = '' if softbans: for x in softbans: outMsg += '*' + x[0] + '* ' + '(' + str(x[2]) + ')\n' self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="".join(outMsg)) else: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="No Softbans found! Good job!\n") def send_subscription_updated(self, update): self.chsub(update.message.text, update.message.chat_id) self.sendMessage(chat_id=update.message.chat_id, parse_mode='HTML', text=("Subscriptions updated.")) def send_info(self, update): self.send_player_stats_to_chat(update.message.chat_id) def send_logout(self, update): self.sendMessage(chat_id=update.message.chat_id, parse_mode='HTML', text=("Logged out.")) self.deauthenticate(update) def send_caught(self, update, num, order): caught = self.chat_handler.get_caught(num, order) outMsg = '' if caught: for x in caught: outMsg += '*' + x[0] + '* ' + '(_CP:_ ' + str(int( x[1])) + ' _IV:_ ' + str(x[2]) + ')\n' self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="".join(outMsg)) else: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="No Pokemon Caught Yet.\n") def send_evolved(self, update, num, order): evolved = self.chat_handler.get_evolved(num, order) outMsg = '' if evolved: for x in evolved: outMsg += '*' + x[0] + '* ' + '(_CP:_ ' + str(int( x[1])) + ' _IV:_ ' + str(x[2]) + ')\n' self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="".join(outMsg)) else: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="No Evolutions Found.\n") def send_pokestops(self, update, num): pokestops = self.chat_handler.get_pokestops(num) outMsg = '' if pokestops: for x in pokestops: outMsg += '*' + x[0] + '* ' + '(_XP:_ ' + str( x[1]) + ' _Items:_ ' + str(x[2]) + ')\n' self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="".join(outMsg)) else: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="No Pokestops Encountered Yet.\n") def send_hatched(self, update, num, order): hatched = self.chat_handler.get_hatched(num, order) outMsg = '' if hatched: for x in hatched: outMsg += '*' + x[0] + '* ' + '(_CP:_ ' + str(int( x[1])) + ' _IV:_ ' + str(x[2]) + ')\n' self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="".join(outMsg)) else: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="No Eggs Hatched Yet.\n") def send_released(self, update, num, order): released = self.chat_handler.get_released(num, order) outMsg = '' if released: for x in released: outMsg += '*' + x[0] + '* ' + '(_CP:_ ' + str(int( x[1])) + ' _IV:_ ' + str(x[2]) + ')\n' self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="".join(outMsg)) else: self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="No Pokemon Released Yet.\n") def send_vanished(self, update, num, order): vanished = self.chat_handler.get_vanished(num, order) outMsg = '' if vanished: for x in vanished: outMsg += '*' + x[0] + '* ' + '(_CP:_ ' + str(int( x[1])) + ' _IV:_ ' + str(x[2]) + ')\n' self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text=outMsg) def send_top(self, update, num, order): top = self.chat_handler.get_top(num, order) outMsg = '' for x in top: outMsg += "*{}* _CP:_ {} _IV:_ {} (Candy: {})\n".format( x[0], x[1], x[2], x[3]) self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text=outMsg) def showsubs(self, update): subs = [] with self.bot.database as conn: for sub in conn.execute( "select uid, event_type, parameters from telegram_subscriptions where uid = ?", [update.message.chat_id]).fetchall(): subs.append("{} -> {}".format(sub[1], sub[2])) if subs is []: subs.append( "No subscriptions found. Subscribe using /sub EVENTNAME. For a list of events, send /events" ) self.sendMessage(chat_id=update.message.chat_id, parse_mode='HTML', text="\n{}".join(subs)) def chsub(self, msg, chatid): (cmd, evt, params) = self.tokenize(msg, 3) if cmd == "/sub": sql = "replace into telegram_subscriptions(uid, event_type, parameters) values (?, ?, ?)" else: if evt == "everything": sql = "delete from telegram_subscriptions where uid = ? and (event_type = ? or parameters = ? or 1 = 1)" # does not look very elegant, but makes unsub'ing everythign possible else: sql = "delete from telegram_subscriptions where uid = ? and event_type = ? and parameters = ?" with self.bot.database as conn: conn.execute(sql, [chatid, evt, params]) conn.commit() return def send_start(self, update): res = ( "*Commands: *", "/info - info about bot", "/login <password> - authenticate with the bot; once authenticated, your ID will be registered with the bot and survive bot restarts", "/logout - remove your ID from the 'authenticated' list", "/sub <eventName> <parameters> - subscribe to eventName, with optional parameters, event name=all will subscribe to ALL events (LOTS of output!)", "/unsub <eventName> <parameters> - unsubscribe from eventName; parameters must match the /sub parameters", "/unsub everything - will remove all subscriptions for this uid", "/showsubs - show current subscriptions", "/events <filter> - show available events, filtered by regular expression <filter>", "/top <num> <cp-or-iv-or-dated> - show top X pokemons, sorted by CP, IV, or Date", "/evolved <num> <cp-or-iv-or-dated> - show top x pokemon evolved, sorted by CP, IV, or Date", "/hatched <num> <cp-or-iv-or-dated> - show top x pokemon hatched, sorted by CP, IV, or Date", "/caught <num> <cp-or-iv-or-dated> - show top x pokemon caught, sorted by CP, IV, or Date", "/pokestops - show last x pokestops visited", "/released <num> <cp-or-iv-or-dated> - show top x released, sorted by CP, IV, or Date", "/vanished <num> <cp-or-iv-or-dated> - show top x vanished, sorted by CP, IV, or Date", "/softbans - info about possible softbans") self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="\n".join(res)) def is_configured(self, update): self.sendMessage( chat_id=update.message.chat_id, parse_mode='Markdown', text= "No password nor master configured in TelegramTask section, bot will not accept any commands" ) def is_master_numeric(self, update): outMessage = "Telegram message received from correct user, but master is not numeric, updating datastore." self.bot.logger.warn(outMessage) # the "master" is not numeric, set self.master to update.message.chat_id and re-instantiate the handler newconfig = self.config newconfig['master'] = update.message.chat_id # insert chat id into database self.grab_uid(update) # remove old handler self.bot.event_manager._handlers = filter( lambda x: not isinstance(x, TelegramHandler), self.bot.event_manager._handlers) # add new handler (passing newconfig as parameter) self.bot.event_manager.add_handler(TelegramHandler( self.bot, newconfig)) def is_known_sender(self, update): # Reject message if sender does not match defined master in config outMessage = "Telegram message received from unknown sender. Please either make sure your username or ID is in TelegramTask/master, or a password is set in TelegramTask section and /login is issued" self.bot.logger.error(outMessage) self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Please /login first") def tokenize(self, string, maxnum): spl = string.split(' ', maxnum - 1) while len(spl) < maxnum: spl.append(" ") return spl def evolve(self, chatid, uid): # TODO: here comes evolve logic (later) self.sendMessage(chat_id=chatid, parse_mode='HTML', text="Evolve logic not implemented yet") return def upgrade(self, chatid, uid): # TODO: here comes upgrade logic (later) self.sendMessage(chat_id=chatid, parse_mode='HTML', text="Upgrade logic not implemented yet") return def run(self): time.sleep(1) while True: if DEBUG_ON: self.bot.logger.info("Telegram loop running") if self._tbot is None: self.connect() for update in self._tbot.getUpdates(offset=self.update_id, timeout=10): self.update_id = update.update_id + 1 if update.message: self.bot.logger.info( "Telegram message from {} ({}): {}".format( update.message.from_user.username, update.message.from_user.id, update.message.text)) if re.match(r'^/login [^ ]+', update.message.text): self.authenticate(update) continue if self.config.get('password', None) == None and ( not hasattr(self, "master") or not self.config.get( 'master', None)): # no auth provided in config self.is_configured(update) continue if not self.isAuthenticated(update.message.from_user.id) and hasattr(self, "master") and self.master and not unicode(self.master).isnumeric() and \ unicode(self.master) == unicode(update.message.from_user.username): self.is_master_numeric(update) continue if not self.isAuthenticated(update.message.from_user.id): self.is_known_sender(update) continue # one way or another, the user is now authenticated # make sure uid is in database self.grab_uid(update) if update.message.text == "/start" or update.message.text == "/help": self.send_start(update) continue if update.message.text == "/info": self.send_info(update) continue if update.message.text == "/logout": self.send_logout(update) continue if re.match("^/events", update.message.text): self.send_events(update) continue if re.match(r'^/sub ', update.message.text): self.send_subscription_updated(update) continue if re.match(r'^/unsub ', update.message.text): self.send_subscription_updated(update) continue if re.match(r'^/showsubs', update.message.text): self.showsubs(update) continue if re.match(r'^/top ', update.message.text): (cmd, num, order) = self.tokenize(update.message.text, 3) self.send_top(update, num, order) continue if re.match(r'^/caught ', update.message.text): (cmd, num, order) = self.tokenize(update.message.text, 3) self.send_caught(update, num, order) continue if re.match(r'^/evolved ', update.message.text): (cmd, num, order) = self.tokenize(update.message.text, 3) self.send_evolved(update, num, order) continue if re.match(r'^/pokestops ', update.message.text): (cmd, num) = self.tokenize(update.message.text, 2) self.send_pokestops(update, num) continue if re.match(r'^/hatched ', update.message.text): (cmd, num, order) = self.tokenize(update.message.text, 3) self.send_hatched(update, num, order) continue if re.match(r'^/released ', update.message.text): (cmd, num, order) = self.tokenize(update.message.text, 3) self.send_released(update, num, order) continue if re.match(r'^/vanished ', update.message.text): (cmd, num, order) = self.tokenize(update.message.text, 3) self.send_vanished(update, num, order) continue if re.match(r'^/softbans ', update.message.text): (cmd, num) = self.tokenize(update.message.text, 2) self.send_softbans(update, num) continue self.sendMessage(chat_id=update.message.chat_id, parse_mode='Markdown', text="Unrecognized command: {}".format( update.message.text))