# Description: # funzioni speciali per telegram-cli # # Requires: # "fast-levenshtein": "1.0.6" # # Configuration: # Uses hubot-tg enviroment variables # # Commands # hubot chi sei - chiedi a hubot di identificarsi # hubot chi sono / cosa sai di me - mostra il tuo contatto nel registro di hubot # hubot in che gruppi sei / dove scrivi - chiedi a hubot dove chatta # hubot invita/aggiungi - chiedi ad hubot di invitare qualcuno nel gruppo attuale # hubot (mi inviti / invitami) (nel gruppo / in) - chiedi ad hubot di invitardi in un gruppo # hubot (aggiungi[mi] / crea) (il mio / [tra]i contatto/i) [telefono] - chiedi ad hubot di creare il tuo contatto # hubot banna - chiedi di bannare un utente dal gruppo attuale (solo se hubot l'ha invitato) # hubot bannalo - chiedi ad hubot di bannare l'ultimo utente ad aver scritto un messaggio dal gruppo # # Author: # Michele Guerini Rocco (rnhmjoj) # net = require 'net' lev = require 'fast-levenshtein' module.exports = (robot) -> # messages error = 'oh no: c\'è stato un errore, non so' done = ['fatto', 'ecco qui', 'ecco fatto'] success = ['provvedo subito', 'ok', 'certo', 'va bene'] unknown = ['non so chi sia', 'chi?', 'mai sentito', 'sicuro? non lo trovo'] failed = ['eh, mi piacerebbe molto ma non posso', 'i have no powers here', 'nope, non l\'ho invitato io', 'non sono admin qui, sorry'] banned = [', ora non sarai più un problema', ' terminato', ' non farti più vedere', ', questa è la tua fine' ' sparito per sempre'] # find closest match with levenshtein metric find_closest = (target, list) -> dists = [].concat.apply [], ( for str in list for word in [str].concat str.split ' ' [(lev.get target, word), str] ) [dist, name] = dists.reduce (x, y) -> if x[0] < y[0] then x else y return if dist < 4 then name else null # format a name as telegram-cli likes it norm = (x) -> x.replace /\ /g, '_' # return a list of every match for a regex match_all = (regex, str) -> matches = [] str.replace regex, -> arr = [].slice.call arguments, 0 extras = arr.splice -2 arr.index = extras[0] arr.input = extras[1] matches.push arr matches # directly run a command in telegram-cli and return its output # (a list of strings) run_command = (command, callback) -> client = net.connect robot.adapter.port, robot.adapter.host, -> client.write command+'\n' client.setEncoding 'utf8' client.on 'data', (reply) -> if callback? res = (reply.split '\n')[1..-3] [..., err] = res[0].split ' ' callback res, err client.end() # return an object with the known chat information chat_info = (name, callback) -> run_command "chat_info #{norm name}", (data) -> match = data[0].match /// Chat\ (\w+(\ ?\w+)*) # chat name \ \(id\ (\d+)\) # chat id /// chat = name: match[1] id: 'chat#'+match[3] members: data[1..].map (i) -> (i.split ' invited')[0].replace /\t/g, '' robot.logger.info 'parsed chat data: ' + JSON.stringify chat, null, 2 callback chat # return an object with the known user information user_info = (name, callback) -> run_command "user_info #{norm name}", (data) -> match = (data.join '\n').match /// User\ (\w+(\ ?\w+)*) # contact name (\ @(\w+))? # telegram username (\ \(\#(\d+)\))? # telegram id [\s\S]+phone:\ (\d+)? # phone number /// user = name: match[1] username: match[4] id: 'user#'+match[6] phone: match[7] robot.logger.info 'parsed user data: ' + JSON.stringify user, null, 2 callback user # get hubot telegram profile information robot_info = (callback) -> run_command 'get_self', (data) -> match = (data.join '\n').match /// User\ (\w+(\ ?\w+)*) # contact name (\ @(\w+))? # telegram username (\ \(\#(\d+)\))? # telegram id [\s\S]+phone:\ (\d+)? # phone number /// user = name: match[1] username: match[4] id: 'user#'+match[6] phone: match[7] robot.logger.info 'parsed robot data: ' + JSON.stringify user, null, 2 callback user # return the list of active chat groups chat_list = (callback) -> run_command 'dialog_list', (list) -> chats = list.filter (item) -> not item.lastIndexOf 'Chat', 0 chats = chats.map (chat) -> (chat.match /Chat (.+):/)[1] robot.logger.info 'parsed bot chats list: ' + JSON.stringify chats, null, 2 callback chats # return the list of contacts (names only) contact_list = (callback) -> run_command 'contact_list', callback # add a user to the contact list add_contact = (name, phone, callback) -> robot.logger.info "create contact for user #{name}" user_info name, (user) -> [first, last...] = user.name.split ' ' phone = phone or user.phone if not phone? return callback 'serve per forza il tuo numero' run_command "add_contact #{phone} '#{first}' '#{last.join ' '}'", (reply) -> robot.logger.info 'result: ' + reply reply = reply[0].split ' ' if reply[0] is 'FAIL:' return callback reply[1..] callback() # get the messages history for a chat group get_history = (chat, size, callback) -> regex = /\[(.+)\] (.+) [>«»]+ ((?:(?!\n(\[|\d))[\s\S])+)/g parse_line = (x) -> date: x[1] peer: x[2].replace(chat, '').trim() text: x[3].trim().replace '\n', ' ' run_command "history #{norm chat} #{size}", (lines) -> callback ((match_all regex, lines.join '\n').map parse_line) # ban user from a group chat delete_user = (user, chat, res) -> run_command "chat_del_user #{chat.id} #{user.id}", (reply, err) -> robot.logger.info "delete user #{user.name} from chat #{chat.name}" robot.logger.info 'result: ' + reply[0] if err is 'SUCCESS' robot.logger.info 'user deleted' res.send user.name + res.random banned else if err is 'CHAT_ADMIN_REQUIRED' robot.logger.warning 'cannot delete user: not authorized' res.send res.random failed else robot.logger.error 'error:\n' + reply.join '\n' res.send error # add user to a group chat add_user = (user, chat, res) -> run_command "chat_add_user #{chat.id} #{user.id}", (reply, err) -> robot.logger.info "add user #{user.name} to chat #{chat.name}" robot.logger.info 'result: ' + reply[0] if err is 'SUCCESS' robot.messageRoom chat.id, res.random done else if err is 'USER_NOT_MUTUAL_CONTACT' robot.logger.warning 'cannot add user: not authorized' res.send 'ah, non posso: ho bisogno del contatto' else if err is 'USER_ALREADY_PARTICIPANT' robot.logger.warning 'cannot add user: user already present' res.send 'ma è già qui!' else if err is 'CHAT_ADMIN_REQUIRED' robot.logger.warning 'cannot add user: not authorized' res.send res.random failed else robot.logger.error 'error:\n' + reply.join '\n' res.send error robot.respond /chi sei/, (res) -> robot_info (user) -> username = if user.username? then " noto anche come #{user.username}" else '' phone = if user.phone? then " chiamatemi al #{user.phone}. " else '. ' id = "il mio id di telegram è #{user.id}" res.send "sono #{user.name}#{username},#{phone}#{id}" robot.respond /(cosa sai di me|chi sono)/i, (res) -> user_info res.message.user.name, (user) -> username = if user.username? then " ma ti chiamano anche #{user.username}" else '' phone = if user.phone? then " so il tuo numero: #{user.phone} e " else ' ' id = "il tuo id di telegram è #{user.id}" res.send "so che sei #{user.name}#{username},#{phone}#{id}" robot.respond /(in che gruppi sei| dove scrivi)/, (res) -> intro = ['scrivo in questi gruppi', 'chatto qui', 'sono attivo in'] chat_list (list) -> res.send (res.random intro) + ':\n' + (list.map (i) -> '* '+i).join '\n' robot.respond /(aggiungi(mi)?|crea) ((trai? (i )?contatti)|(il mio contatto))( (\d+))?/, (res) -> add_contact res.message.user.name, res.match[8], (err) -> if err? res.send "c'è un problema: " + err else res.send "fatto!" robot.respond /(invita|aggiungi) (.+)/, (res) -> name = res.match[2] id = res.message.room if id.match /^user/ return res.send 'non è un gruppo questo' contact_list (contacts) -> name = find_closest(name, contacts) if not name? return res.send res.random unknown res.send res.random success user_info name, (user) -> chat_info id, (chat) -> add_user user, chat, res robot.respond /(mi )?invit(i|ami) (in|nel gruppo) ([^?]+)\??/, (res) -> denied = ['BZBZ ADMIN-NOT-DETECTED', 'BZBZ IS-NOT-AUTHORIZED', 'BZBZ ACCESS-DENIED'] failed = ['ahahah NO', 'mai sentito questo', 'invita anche me magari', 'che?'] user = res.message.user name = res.match[4] admin_id = process.env['ADMIN_ROOM'] chat_list (list) -> if not (name in list) return res.send res.random failed chat_info name, (chat) -> if chat.id is admin_id return res.send res.random denied if user.name in chat.members return res.send 'ma sei già nel gruppo... [facepalm]' res.send res.random success add_user user, chat, res robot.respond /banna(l(o|a)| (.+))/, (res) -> if res.message.room.match /^user/ return res.send 'non è un gruppo questo' chat_info res.message.room, (chat) -> get_history chat.name, 2, (history) -> robot_info (self) -> target = res.match[3] if not target? name = history[0].peer else name = find_closest(target, chat.members) if not name? return res.send res.random unknown if name in [res.message.user.name, self.name] return res.send 'ma sei scemo o cosa?' user_info name, (user) -> delete_user user, chat, res