def cmd_anniv(msg): (matches, name) = findName(msg) if len(matches) == 1: name = matches[0] tyd = context.data.index[name].getDate("born") tyd = datetime(date.today().year, tyd.month, tyd.day) if (tyd.day == datetime.today().day and tyd.month == datetime.today().month): return Response( countdown_format( context.data.index[name].getDate("born"), "", "C'est aujourd'hui l'anniversaire de %s !" " Il a %s. Joyeux anniversaire :)" % (name, "%s")), msg.channel) else: if tyd < datetime.today(): tyd = datetime(date.today().year + 1, tyd.month, tyd.day) return Response( countdown_format( tyd, "Il reste %s avant l'anniversaire de %s !" % ("%s", name), ""), msg.channel) else: return Response( "désolé, je ne connais pas la date d'anniversaire" " de %s. Quand est-il né ?" % name, msg.channel, msg.frm)
def cmd_sleep(msg): if len(msg.args) and re.match("[0-9]{1,2}[h':.,-]([0-9]{1,2})?[m'\":.,-]?", msg.args[0]) is not None: # First, parse the hour p = re.match("([0-9]{1,2})[h':.,-]([0-9]{1,2})?[m':.,-]?", msg.args[0]) f = [ datetime(datetime.now(timezone.utc).year, datetime.now(timezone.utc).month, datetime.now(timezone.utc).day, hour=int(p.group(1))) ] if p.group(2) is not None: f[0] += timedelta(minutes=int(p.group(2))) g = list() for i in range(6): f.append(f[i] - timedelta(hours=1, minutes=30)) g.append(f[i + 1].strftime("%H:%M")) return Response("You should try to fall asleep at one of the following" " times: %s" % ', '.join(g), channel=msg.channel) # Just get awake times else: f = [datetime.now(timezone.utc) + timedelta(minutes=15)] g = list() for i in range(6): f.append(f[i] + timedelta(hours=1, minutes=30)) g.append(f[i + 1].strftime("%H:%M")) return Response("If you head to bed right now, you should try to wake" " up at one of the following times: %s" % ', '.join(g), channel=msg.channel)
def go(msg, what): if not len(msg.args): raise IMException("de quel mot veux-tu connaître la liste des synonymes ?") lang = msg.kwargs["lang"] if "lang" in msg.kwargs else "fr" word = ' '.join(msg.args) try: best, synos, anton = lang_binding[lang](word) except: best, synos, anton = (list(), list(), list()) if what == "synonymes": if len(synos) > 0 or len(best) > 0: res = Response(channel=msg.channel, title="Synonymes de %s" % word) if len(best) > 0: res.append_message(best) if len(synos) > 0: res.append_message(synos) return res else: raise IMException("Aucun synonyme de %s n'a été trouvé" % word) elif what == "antonymes": if len(anton) > 0: res = Response(anton, channel=msg.channel, title="Antonymes de %s" % word) return res else: raise IMException("Aucun antonyme de %s n'a été trouvé" % word) else: raise IMException("WHAT?!")
def parseask(msg): res = re.match( r"^(\S+)\s*('s|suis|est|is|was|were)?\s+(birthday|geburtstag|née? |nee? le|born on).*$", msg.message, re.I) if res is not None: try: extDate = extractDate(msg.message) if extDate is None or extDate.year > datetime.now().year: return Response("la date de naissance ne paraît pas valide...", msg.channel, msg.frm) else: nick = res.group(1) if nick == "my" or nick == "I" or nick == "i" or nick == "je" or nick == "mon" or nick == "ma": nick = msg.frm if nick.lower() in context.data.index: context.data.index[nick.lower()]["born"] = extDate else: ms = ModuleState("birthday") ms.setAttribute("name", nick.lower()) ms.setAttribute("born", extDate) context.data.addChild(ms) context.save() return Response( "ok, c'est noté, %s est né le %s" % (nick, extDate.strftime("%A %d %B %Y à %H:%M")), msg.channel, msg.frm) except: raise IMException("la date de naissance ne paraît pas valide.")
def ask_ratp(msg): l = len(msg.args) transport = msg.args[0] if l > 0 else None line = msg.args[1] if l > 1 else None station = msg.args[2] if l > 2 else None direction = msg.args[3] if l > 3 else None if station is not None: times = sorted(ratp.getNextStopsAtStation(transport, line, station, direction), key=lambda i: i[0]) if len(times) == 0: raise IMException("la station %s n'existe pas sur le %s ligne %s." % (station, transport, line)) (time, direction, stationname) = times[0] return Response(message=["\x03\x02%s\x03\x02 direction %s" % (time, direction) for time, direction, stationname in times], title="Prochains passages du %s ligne %s à l'arrêt %s" % (transport, line, stationname), channel=msg.channel) elif line is not None: stations = ratp.getAllStations(transport, line) if len(stations) == 0: raise IMException("aucune station trouvée.") return Response(stations, title="Stations", channel=msg.channel) elif transport is not None: lines = ratp.getTransportLines(transport) if len(lines) == 0: raise IMException("aucune ligne trouvée.") return Response(lines, title="Lignes", channel=msg.channel) else: raise IMException("précise au moins un moyen de transport.")
def cmd_alias(msg): if not len(msg.args): raise IMException("!alias takes as argument an alias to extend.") alias = context.subparse(msg, msg.args[0]) if alias is None or not isinstance(alias, Command): raise IMException("%s is not a valid alias" % msg.args[0]) if alias.cmd in context.data.getNode("aliases").index: return Response( "%s corresponds to %s" % (alias.cmd, context.data.getNode("aliases").index[alias.cmd]["origin"]), channel=msg.channel, nick=msg.frm) elif len(msg.args) > 1: create_alias(alias.cmd, " ".join(msg.args[1:]), channel=msg.channel, creator=msg.frm) return Response("New alias %s successfully registered." % alias.cmd, channel=msg.channel) else: wym = [ m for m in guess(alias.cmd, context.data.getNode("aliases").index) ] raise IMException(msg.args[0] + " is not an alias." + (" Would you mean: %s?" % ", ".join(wym) if len(wym) else ""))
def parseask(msg): if msg.message.find("Free") >= 0 and ( msg.message.find("API") >= 0 or msg.message.find("api") >= 0) and ( msg.message.find("SMS") >= 0 or msg.message.find("sms") >= 0): resuser = apiuser_ask.search(msg.message) reskey = apikey_ask.search(msg.message) if resuser is not None and reskey is not None: apiuser = resuser.group("user") apikey = reskey.group("key") test = send_sms( "nemubot", apiuser, apikey, "Vous avez enregistré vos codes d'authentification dans nemubot, félicitation !" ) if test is not None: return Response( "je n'ai pas pu enregistrer tes identifiants : %s" % test, msg.channel, msg.frm) if msg.frm in context.data.index: context.data.index[msg.frm]["user"] = apiuser context.data.index[msg.frm]["key"] = apikey else: ms = ModuleState("phone") ms.setAttribute("name", msg.frm) ms.setAttribute("user", apiuser) ms.setAttribute("key", apikey) ms.setAttribute("lastuse", 0) context.data.addChild(ms) context.save() return Response( "ok, c'est noté. Je t'ai envoyé un SMS pour tester ;)", msg.channel, msg.frm)
def mediawiki_response(site, term, to, **kwargs): ns = get_namespaces(site, **kwargs) terms = term.split("#", 1) try: # Print the article if it exists return Response(strip_model( get_page(site, terms[0], subpart=terms[1] if len(terms) > 1 else None, **kwargs)), line_treat=lambda line: irc_format( parse_wikitext(site, line, ns, **kwargs)), channel=to) except: pass # Try looking at opensearch os = [x for x, _, _ in opensearch(site, terms[0], **kwargs)] print(os) # Fallback to global search if not len(os): os = [ x for x, _ in search(site, terms[0], **kwargs) if x is not None and x != "" ] return Response(os, channel=to, title="Article not found, would you mean")
def shodan(msg): if not msg.args: raise IMException("indicate an IP or a term to search!") terms = " ".join(msg.args) try: ip = ipaddress.ip_address(terms) except ValueError: ip = None if ip: h = host_lookup(terms) res = Response( channel=msg.channel, title="%s" % ((h["ip_str"] if ip.version == 4 else "[%s]" % h["ip_str"]) + (" (" + ", ".join(h["hostnames"]) + ")") if h["hostnames"] else "")) res.append_message( "{isp} ({asn}) -> {city} ({country_code}), running {os}. Vulns: {vulns_str}. Open ports: {open_ports}. Last update: {last_update}" .format(open_ports=", ".join(map(lambda a: str(a), h["ports"])), vulns_str=", ".join(h["vulns"]) if "vulns" in h else None, **h).strip()) for d in h["data"]: res.append_message(print_service(d)) else: q = search_hosts(terms) res = Response(channel=msg.channel, count=" (%%s/%s results)" % q["total"]) for r in q["matches"]: res.append_message(print_service(r)) return res
def cmd_listalias(msg): aliases = [a for a in list_alias(None) ] + [a for a in list_alias(msg.channel)] if len(aliases): return Response([a["alias"] for a in aliases], channel=msg.channel, title="Known aliases") return Response("There is no alias currently.", channel=msg.channel)
def cmd_isup(msg): if not len(msg.args): raise IMException("Indicate an domain name to check!") res = list() for url in msg.args[:4]: rep = isup.isup(url) if rep: res.append(Response("%s is up (response time: %ss)" % (url, rep), channel=msg.channel)) else: res.append(Response("%s is down" % (url), channel=msg.channel)) return res
def cmd_subreddit(msg): global LAST_SUBS if not len(msg.args): if msg.channel in LAST_SUBS and len(LAST_SUBS[msg.channel]) > 0: subs = [LAST_SUBS[msg.channel].pop()] else: raise IMException("Which subreddit? Need inspiration? " "type !horny or !bored") else: subs = msg.args all_res = list() for osub in subs: sub = re.match(r"^/?(?:(\w)/)?(\w+)/?$", osub) if sub is not None: if sub.group(1) is not None and sub.group(1) != "": where = sub.group(1) else: where = "r" sbr = web.getJSON("https://www.reddit.com/%s/%s/about.json" % (where, sub.group(2))) if sbr is None: raise IMException("subreddit not found") if "title" in sbr["data"]: res = Response(channel=msg.channel, nomore="No more information") res.append_message( ("[NSFW] " if sbr["data"]["over18"] else "") + sbr["data"]["url"] + " " + sbr["data"]["title"] + ": " + sbr["data"] ["public_description" if sbr["data"]["public_description"] != "" else "description"].replace("\n", " ") + " %s subscriber(s)" % sbr["data"]["subscribers"]) if sbr["data"]["public_description"] != "": res.append_message(sbr["data"]["description"].replace( "\n", " ")) all_res.append(res) else: all_res.append( Response("/%s/%s doesn't exist" % (where, sub.group(2)), channel=msg.channel)) else: all_res.append( Response("%s is not a valid subreddit" % osub, channel=msg.channel, nick=msg.frm)) return all_res
def cmd_age(msg): (matches, name) = findName(msg) if len(matches) == 1: name = matches[0] d = context.data.index[name].getDate("born") return Response( countdown_format(d, "%s va naître dans %s." % (name, "%s"), "%s a %s." % (name, "%s")), msg.channel) else: return Response( "désolé, je ne connais pas l'âge de %s." " Quand est-il né ?" % name, msg.channel, msg.frm) return True
def send_sms_to_list(msg, frm, dests, content, cur_epoch): fails = list() for u in dests: context.data.index[u]["lastuse"] = cur_epoch test = send_sms(frm, context.data.index[u]["user"], context.data.index[u]["key"], content) if test is not None: fails.append("%s: %s" % (u, test)) if len(fails) > 0: return Response( "quelque chose ne s'est pas bien passé durant l'envoi du SMS : " + ", ".join(fails), msg.channel, msg.frm) else: return Response("le SMS a bien été envoyé", msg.channel, msg.frm)
def cmd_alert(msg): loc, coords, specific = treat_coord(msg) wth = get_json_weather( coords, lang=msg.kwargs["lang"] if "lang" in msg.kwargs else "en", units=msg.kwargs["units"] if "units" in msg.kwargs else "ca") res = Response(channel=msg.channel, nomore="No more weather alert", count=" (%d more alerts)") if "alerts" in wth: for alert in wth["alerts"]: if "expires" in alert: res.append_message( "\x03\x02%s\x03\x02 (see %s expire on %s): %s" % (alert["title"], alert["uri"], format_timestamp(int(alert["expires"]), wth["timezone"], wth["offset"]), alert["description"].replace("\n", " "))) else: res.append_message("\x03\x02%s\x03\x02 (see %s): %s" % (alert["title"], alert["uri"], alert["description"].replace("\n", " "))) return res
def cmd_w3m(msg): if not len(msg.args): raise IMException("Indicate the URL to visit.") res = Response(channel=msg.channel) for line in page.render(" ".join(msg.args)).split("\n"): res.append_message(line) return res
def cmd_spell(msg): if not len(msg.args): raise IMException( "indique une orthographe approximative du mot dont tu veux vérifier l'orthographe." ) lang = msg.kwargs["lang"] if "lang" in msg.kwargs else "fr" res = Response(channel=msg.channel) for word in msg.args: try: r = check_spell(word, lang) except AspellError: raise IMException("Je n'ai pas le dictionnaire `%s' :(" % lang) if r == True: add_score(msg.frm, "correct") res.append_message("l'orthographe de `%s' est correcte" % word) elif len(r) > 0: add_score(msg.frm, "bad") res.append_message(r, title="suggestions pour `%s'" % word) else: add_score(msg.frm, "bad") res.append_message("aucune suggestion pour `%s'" % word) return res
def get_tracking_info(msg): if not len(msg.args): raise IMException("Renseignez un identifiant d'envoi.") res = Response(channel=msg.channel, count=" (%d suivis supplémentaires)") if 'tracker' in msg.kwargs: if msg.kwargs['tracker'] in TRACKING_HANDLERS: trackers = { msg.kwargs['tracker']: TRACKING_HANDLERS[msg.kwargs['tracker']] } else: raise IMException("No tracker named \x02{tracker}\x0F, please use" " one of the following: \x02{trackers}\x0F" .format(tracker=msg.kwargs['tracker'], trackers=', ' .join(TRACKING_HANDLERS.keys()))) else: trackers = TRACKING_HANDLERS for tracknum in msg.args: for name, tracker in trackers.items(): ret = tracker(tracknum) if ret: res.append_message(ret) break if not ret: res.append_message("L'identifiant \x02{id}\x0F semble incorrect," " merci de vérifier son exactitude." .format(id=tracknum)) return res
def cmd_overview(msg): if "host" not in msg.kwargs: raise IMException("please give a hostname in keywords") if not len(msg.args): raise IMException("which group would you overview?") for g in msg.args: arts = [] for grp in read_group(g, **msg.kwargs): grp["X-FromName"], grp["X-FromEmail"] = parseaddr( grp["from"] if "from" in grp else "") if grp["X-FromName"] == '': grp["X-FromName"] = grp["X-FromEmail"] arts.append( "On {date}, from \x03{0:02d}{X-FromName}\x0F \x02{subject}\x0F: \x0314{message-id}\x0F" .format( adler32(grp["X-FromEmail"].encode()) & 0xf, **{h: decode_header(i) for h, i in grp.items()})) if len(arts): yield Response(arts, channel=msg.channel, title="In \x03{0:02d}{1}\x0F".format( adler32(g[0].encode()) & 0xf, g))
def cmd_flight(msg): if not len(msg.args): raise IMException("please indicate a flight") res = Response(channel=msg.channel, nick=msg.frm, nomore="No more flights", count=" (%s more flights)") for param in msg.args: for flight in virtual_radar(param): if 'Lat' in flight and 'Long' in flight: loc = None for location in mapquest.geocode( '{Lat},{Long}'.format(**flight)): loc = location break if loc: res.append_message('\x02{0}\x0F: Position: \x02{1}\x0F, {2}'.format(flight['Call'], \ mapquest.where(loc), \ ', '.join(filter(None, flight_info(flight))))) continue res.append_message('\x02{0}\x0F: {1}'.format(flight['Call'], \ ', '.join(filter(None, flight_info(flight))))) return res
def cmd_man(msg): args = ["man"] num = None if len(msg.args) == 1: args.append(msg.args[0]) elif len(msg.args) >= 2: try: num = int(msg.args[0]) args.append("%d" % num) args.append(msg.args[1]) except ValueError: args.append(msg.args[0]) os.unsetenv("LANG") res = Response(channel=msg.channel) with subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) as proc: for line in proc.stdout.read().split(b"\n"): (line, n) = RGXP_s.subn(b'', line) res.append_message(line.decode()) if len(res.messages) <= 0: if num is not None: res.append_message("There is no entry %s in section %d." % (msg.args[0], num)) else: res.append_message("There is no man page for %s." % msg.args[0]) return res
def cmd_imdb(msg): if not len(msg.args): raise IMException("precise a movie/serie title!") title = ' '.join(msg.args) if re.match("^tt[0-9]{7}$", title) is not None: data = get_movie_by_id(imdbid=title) else: rm = re.match(r"^(.+)\s\(([0-9]{4})\)$", title) if rm is not None: data = find_movies(rm.group(1), year=rm.group(2)) else: data = find_movies(title) if not data: raise IMException("Movie/series not found") data = get_movie_by_id(data[0]["id"]) res = Response( channel=msg.channel, title="%s (%s)" % (data['Title'], data['Year']), nomore="No more information, more at http://www.imdb.com/title/%s" % data['imdbID']) res.append_message( "%s \x02genre:\x0F %s; \x02rating\x0F: %s (%s votes); \x02plot\x0F: %s" % (data['Type'], data['Genre'], data['imdbRating'], data['imdbVotes'], data['Plot'])) res.append_message("%s \x02from\x0F %s; %s" % (data['Type'], data['Country'], data['Credits'])) return res
def cmd_whois(msg): if len(msg.args) < 1: raise IMException("Provide a name") def format_response(t): srch, l = t if type(l) is Login: pic = l.get_photo() return "%s is %s (%s %s): %s%s" % ( srch, l.cn.capitalize(), l.login, l.uid, l.get_promo(), " and looks like %s" % pic if pic is not None else "") else: return l % srch res = Response(channel=msg.channel, count=" (%d more logins)", line_treat=format_response) for srch in msg.args: found = False for l in login_lookup(srch, "lookup" in msg.kwargs): found = True res.append_message((srch, l)) if not found: res.append_message((srch, "Unknown %s :(")) return res
def current_match_new_action(matches): def cmp(om, nm): return len(nm) and ( len(om) == 0 or len(nm[0]["home_team_events"]) != len(om[0]["home_team_events"]) or len(nm[0]["away_team_events"]) != len(om[0]["away_team_events"])) context.add_event( ModuleEvent(func=partial( lambda url: json.loads(urlopen(url).read().decode()), API_URL % "matches/current?by_date=DESC"), cmp=partial(cmp, matches), call=current_match_new_action, interval=30)) for match in matches: if is_valid(match): events = sort_events(match["home_team"], match["away_team"], match["home_team_events"], match["away_team_events"]) msg = "Match %s vs. %s ; score %s - %s" % ( match["home_team"]["country"], match["away_team"]["country"], match["home_team"]["goals"], match["away_team"]["goals"]) if len(events) > 0: msg += " ; à la " + txt_event(events[0]) for n in context.data.getChilds(): context.send_response(n["server"], Response(msg, channel=n["channel"]))
def cmd_github(msg): if not len(msg.args): raise IMException("indicate a repository name to search") repos = info_repos(" ".join(msg.args)) res = Response(channel=msg.channel, nomore="No more repository", count=" (%d more repo)") for repo in repos["items"]: homepage = "" if repo["homepage"] is not None: homepage = repo["homepage"] + " - " res.append_message("Repository %s: %s%s Main language: %s; %d forks; %d stars; %d watchers; %d opened_issues; view it at %s" % (repo["full_name"], homepage, repo["description"], repo["language"], repo["forks"], repo["stargazers_count"], repo["watchers_count"], repo["open_issues_count"], repo["html_url"])) return res
def add_site(url, nick, channel, server, diffType="diff"): """Add a site to watching list Argument: url -- URL to watch """ o = urlparse(getNormalizedURL(url), "http") if o.netloc == "": raise IMException("sorry, I can't watch this URL :(") alert = ModuleState("alert") alert["nick"] = nick alert["server"] = server alert["channel"] = channel alert["message"] = "{url} just changed!" if url not in DATAS.index: watch = ModuleState("watch") watch["type"] = diffType watch["url"] = url watch["time"] = 123 DATAS.addChild(watch) watch.addChild(alert) start_watching(watch) else: DATAS.index[url].addChild(alert) save() return Response(channel=channel, nick=nick, message="this site is now under my supervision.")
def cmd_github_commit(msg): if not len(msg.args): raise IMException("indicate a repository to view its commits") commit = None if re.match("^[a-fA-F0-9]+$", msg.args[0]): commit = msg.args[0] del msg.args[0] elif re.match("^[a-fA-F0-9]+$", msg.args[-1]): commit = msg.args[-1] del msg.args[-1] repo = " ".join(msg.args) count = " (%d more commits)" if commit is None else None res = Response(channel=msg.channel, nomore="No more commit", count=count) commits = info_commit(repo, commit) if commits is None: raise IMException("Repository or commit not found") for commit in commits: res.append_message("Commit %s by %s on %s: %s" % (commit["sha"][:10], commit["commit"]["author"]["name"], commit["commit"]["author"]["date"], commit["commit"]["message"].replace("\n", " "))) return res
def cmd_github_user(msg): if not len(msg.args): raise IMException("indicate a user name to search") res = Response(channel=msg.channel, nomore="No more user") user = info_user(" ".join(msg.args)) if "login" in user: if user["repos"]: kf = (" Known for: " + ", ".join([repo["name"] for repo in user["repos"]])) else: kf = "" if "name" in user: name = user["name"] else: name = user["login"] res.append_message("User %s: %d public repositories; %d public gists; %d followers; %d following; view it at %s.%s" % (name, user["public_repos"], user["public_gists"], user["followers"], user["following"], user["html_url"], kf)) else: raise IMException("User not found") return res
def cmd_github_issue(msg): if not len(msg.args): raise IMException("indicate a repository to view its issues") issue = None li = re.match("^#?([0-9]+)$", msg.args[0]) ri = re.match("^#?([0-9]+)$", msg.args[-1]) if li is not None: issue = li.group(1) del msg.args[0] elif ri is not None: issue = ri.group(1) del msg.args[-1] repo = " ".join(msg.args) count = " (%d more issues)" if issue is None else None res = Response(channel=msg.channel, nomore="No more issue", count=count) issues = info_issue(repo, issue) if issues is None: raise IMException("Repository not found") for issue in issues: res.append_message("%s%s issue #%d: \x03\x02%s\x03\x02 opened by %s on %s: %s" % (issue["state"][0].upper(), issue["state"][1:], issue["number"], issue["title"], issue["user"]["login"], issue["created_at"], issue["body"].replace("\n", " "))) return res
def cmd_unalias(msg): if not len(msg.args): raise IMException("Which alias would you want to remove?") res = list() for alias in msg.args: if alias[0] == "!" and len(alias) > 1: alias = alias[1:] if alias in context.data.getNode("aliases").index: context.data.getNode("aliases").delChild( context.data.getNode("aliases").index[alias]) res.append( Response("%s doesn't exist anymore." % alias, channel=msg.channel)) else: res.append( Response("%s is not an alias" % alias, channel=msg.channel)) return res