@ -6,6 +6,7 @@ require 'telegram/bot'
require 'pp'
require 'time'
require_relative 'commands.rb'
#require_relative 'callbacks.rb'
require_relative 'colors.rb'
def timestamp
@ -16,18 +17,38 @@ end
@conf = YAML . load_file ( " bot_config.yaml " )
@botname = @conf [ 'botname' ]
@tmpdir = @conf [ 'tmpdir' ]
token = @conf [ 'token' ]
@ token = @conf [ 'token' ]
telnet = @conf [ 'telnet' ]
admin = @conf [ 'admin' ]
@auth_chat = @conf [ 'authorized_chats' ]
@allowed_sources = @conf [ 'allowed_sources' ]
@ip_provider = " ip.skyfall.tech "
#@gif_url_prefix = "https://img.skyfalltech.net/togra/"
@gif_url_prefix = @conf [ 'gif_url_prefix' ]
@voice_chat_enabled = @conf [ 'voice_chat_enabled' ]
@vchat_info = @conf [ 'voice_chat_info' ]
### Begin sanity check ###
STDOUT . sync = true
errcount = 0
puts " Checking if environment is sane... \n \n "
print " Checking system utilities ............... "
### if !system("which nmap 2>&1 >/dev/null")
### print "FAIL!\n\n".red.bold
### puts "nmap".yellow.bold + " not found. This utility requires the 'nmap' command (for testing connectivity to temperature probes)"
### puts "THIS IS REQUIRED!".red.bold + " Bot initialization failed; exiting..."
### exit(1)
### elsif !system("which curl 2>&1 >/dev/null")
if ! system ( " which curl 2>&1 >/dev/null " )
print " FAIL! \n \n " . red . bold
puts " curl " . yellow . bold + " not found. This utility requires the 'curl' command (for providing IP information to users upon request) "
puts " THIS IS REQUIRED! " . red . bold + " Bot initialization failed; exiting... "
exit ( 1 )
else
print " OK \n " . green . bold
end
print " Checking bot token ...................... "
if token . nil?
if @ token. nil?
print " FAIL! \n \n " . red . bold
puts " No bot token defined in bot_config.yaml! \n " + " THIS IS REQUIRED! " . red . bold + " Bot initialization failed; exiting... "
exit ( 1 )
@ -108,6 +129,29 @@ if @auth_chat.nil?
else
print " OK \n " . green . bold
end
print " Checking GIF URL prefix ................. "
if @gif_url_prefix . nil?
errcount += 1
print " FAIL! \n \n " . red . bold
puts " Error( #{ errcount . to_s } ): No GIF URL prefix provided in bot_config.yaml. \n This is required only for a couple of Easter egg features. " +
" Using the Skyfall/Togra GIF prefix instead. Continuing. \n \n "
@gif_url_prefix = " https://img.skyfalltech.net/togra/ "
else
print " OK \n " . green . bold
end
if @voice_chat_enabled == " true "
print " Checking voice chat info ................ "
if @vchat_info . nil?
errcount += 1
print " FAIL! \n \n " . red . bold
puts " Error( #{ errcount . to_s } ): Voice chat features are enabled, but no voice chat application info is configured in bot_config.yaml! \n " +
" THIS SHOULD BE ADDRESSED. Some functions may fail, but the core functionality should be unaffected. Continuing. \n \n "
else
print " OK \n " . green . bold
end
end
puts " Errors found: #{ errcount . to_s } \n \n "
if errcount > 0
print " Environment is grinning and holding a spatula. Please review your configuration. \n \n " . red . bold
@ -121,8 +165,10 @@ puts "Empyrion Host: #{telnet['host']}"
puts " Empyrion Telnet Port: #{ telnet [ 'port' ] } "
puts " Authorized administrator IDs: #{ admin } "
puts " Authorized chat IDs: #{ @auth_chat } "
puts " Bot token: #{ token} "
puts " Bot token: #{ @ token} "
puts " Temporary direcotry: #{ @tmpdir } "
puts " IP Provider: #{ @ip_provider } "
puts " GIF URL Prefix: #{ @gif_url_prefix } "
puts " Start time: " + timestamp + " \n \n \n \n "
STDOUT . flush
@ -136,10 +182,109 @@ STDOUT.flush
# reply = `./srvstop`
#end
def ack_callback ( message , display_message = true )
#Delete message and notify user that we got the request
begin
Telegram :: Bot :: Client . run ( @token ) do | bot |
if display_message == true
bot . api . editMessageText ( chat_id : message . message . chat . id , message_id : message . message . message_id , text : " Request received. Please wait... " , reply_markup : " " ) #Removes buttons. Changes text
bot . api . answerCallbackQuery ( callback_query_id : message . id , show_alert : false , text : " Request received. Please wait... " ) #Sends a pop-up notification
else
bot . api . deleteMessage ( chat_id : message . message . chat . id , message_id : message . message . message_id ) #Deletes message and buttons
end
end
rescue
puts " Error handling callback query. Error: " + $! . message
end
STDOUT . flush
end
def delete_message ( message )
#Deletes a message referred to by message_id
begin
Telegram :: Bot :: Client . run ( @token ) do | bot |
bot . api . deleteMessage ( chat_id : message . message . chat . id , message_id : message . message . message_id ) #Deletes message and buttons
end
rescue
puts " Error deleting message. Error: " + $! . message
end
STDOUT . flush
end
def delete_confirmation ( message )
#Deletes a message referred to by message_id
begin
Telegram :: Bot :: Client . run ( @token ) do | bot |
bot . api . deleteMessage ( chat_id : message . chat . id , message_id : message . message_id )
end
rescue
puts " Error deleting message. Error: " + $! . message
end
STDOUT . flush
end
def send_message ( chatid , message_text , imageurl = nil )
if imageurl != nil
#Send message with text as html link to image
print timestamp + " : Sending ............ "
STDOUT . flush
message = Telegram :: Bot :: Client . run ( @token ) { | bot | message = bot . api . send_message ( chat_id : chatid , text : " #{ message_text } <a href= \" #{ imageurl } \" >.</a> " , parse_mode : " HTML " ) }
print " OK \n " . green . bold
STDOUT . flush
puts " Sent: #{ message_text . inspect } \n \n "
STDOUT . flush
#puts timestamp + ": Sent: #{message_text.inspect}\n\n"
return message
else
#Send a plain-text message
print timestamp + " : Sending ............ "
STDOUT . flush
message = Telegram :: Bot :: Client . run ( @token ) { | bot | bot . api . send_message ( chat_id : chatid , text : message_text ) }
print " OK \n " . green . bold
puts " Sent: #{ message_text . inspect } \n \n "
STDOUT . flush
#puts message
#message = message["results"]
#puts message
return message
end
end
def send_gif ( chatid , cmd )
#message = Telegram::Bot::Client.run(@token) {|bot| message = bot.api.send_message(chat_id: chatid, text: "#{message_text}<a href=\"#{imageurl}\">.</a>", parse_mode: "HTML") }
gif_url = " #{ @gif_url_prefix } #{ cmd } .gif "
print timestamp + " : Sending ............ "
message = Telegram :: Bot :: Client . run ( @token ) { | bot | message = bot . api . sendVideo ( chat_id : chatid , video : gif_url ) }
print " OK \n " . green . bold
puts " Sent GIF: #{ gif_url } \n \n "
STDOUT . flush
return message
end
def send_message_markdown ( chatid , message_text )
#Send a plain-text message
Telegram :: Bot :: Client . run ( @token ) { | bot | bot . api . send_message ( chat_id : chatid , text : " ``` #{ message_text } ``` " , parse_mode : 'Markdown' ) }
puts timestamp + " : Sent: #{ message_text . inspect } \n \n "
STDOUT . flush
end
def send_question ( chatid , question_text , answers = [ ] )
if ! answers . empty? then
begin
keyboard = Telegram :: Bot :: Types :: InlineKeyboardMarkup . new ( inline_keyboard : answers )
Telegram :: Bot :: Client . run ( @token ) { | bot | bot . api . send_message ( chat_id : chatid , text : question_text , reply_markup : keyboard ) }
rescue
puts timestamp + " : " + " ERROR " . red . bold + " : " + $! . message
end
else
puts timestamp + " send_question called without any possible answers provided "
end
STDOUT . flush
end
def handle_message ( message )
if ! message . reply_to_message . nil? then
#drop message. Someone's replying to a message
#sent by our bot
#drop message. Someone's replying to a message sent by our bot
message . text = nil
return
end
@ -154,100 +299,173 @@ def handle_message(message)
return #so that we don't try to process this as a command (below)
end
# Format sender name
if ! message . from . username . nil?
message . from . username = " @ " + message . from . username
elsif ! message . from . first_name . nil?
message . from . username = message . from . first_name
end
# ## # Format sender name
### if ! message.from.username. nil?
### #message.from.username = "@" + message.from. username
### elsif ! message.from.first_name. nil?
### message.from.username = message.from. first_name
### end
#Format command
command = message . text . split ( " " ) [ 0 ] . split ( " @ " ) [ 0 ] . downcase #Strip command from arguments and @tags
#command = message.text
reply = 'Empty String'
#conf = YAML.load_file("bot_config.yaml")
telnet = @conf [ 'telnet' ]
adm = @conf [ 'admin' ]
puts Time . now . strftime ( " %F %H:%M:%S " ) . yellow + " : Received command from " + " #{ message . from . username } " . cyan . bold + " [ " + " #{ message . from . id } " . cyan + " ]: " + " #{ command } " . magenta . bold
case command
when '/start'
reply = " Introduction: I am #{ @botname } , and I am here to make life easier for meatbag admins like you. Currently I can retrieve information " +
" from an Empyrion server as well as kill the server process. I also have some pretty sweet dance moves. \n \n " +
" Commands available: \n /start (Shows this message) \n /srvstart (Currently non-functional) \n /srvstop \n /status \n /whoami or /chatinfo \n /whereareyou or /location \n \n " +
" Check again later to see if any new functions have been added, or use /patchnotes to learn about recent updates. \n " +
" You can also view the source code at the following location: \n https://git.skyfall.tech/skyfall/empyrion-bot "
if message_from_admin? ( message , adm )
msg_from_admin = true
end
if is_chat_authorized? ( message , @auth_chat )
chat_authorized = true
end
if ! msg_from_admin && ! chat_authorized
if message . from . id == message . chat . id
reply = reply + " \n \n WARNING: I am not authorized to work with you directly. My functionality is limited. "
when '/start' , '/help'
process_command_start ( message , command , adm )
when '/chat' , '/voice' , '/mumble' , '/teamspeak' , '/discord' , '/vox' , '/voicechat'
if @voice_chat_enabled == " true "
process_command_voicechat ( message , command , adm )
else
reply = reply + " \n \n WARNING: I am not authorized to participate with this group. My functionality is limited. "
end
elsif msg_from_admin && ! chat_authorized
reply = reply + " \n \n WARNING: Although you are my master, I have not been authorized to participate in this group. My functionality is limited. "
send_message ( message . chat . id , " Refusal: My master has disabled this feature. Perhaps voice chat service does not exist for this group? " )
end
when '/srvstart'
reply = process_command_srvstart ( message , command , adm )
send_message ( message . chat . id , reply )
when '/srvstop'
reply = process_command_srvstop ( message , command , adm )
when '/status'
send_message ( message . chat . id , reply )
when '/status' , '/stat' , '/stats' , '/list' , '/check'
reply = process_command_srvstatus ( message , command , adm )
if command == '/check'
reply = " Hi Matt, here's the /status. \n \n " + reply
end
send_message ( message . chat . id , reply )
when '/patch' , '/patchnotes'
reply = process_command_patchnotes ( message , command , adm )
send_message ( message . chat . id , reply )
when '/location' , '/whereareyou'
if message_from_admin? ( message , adm ) || is_chat_authorized? ( message , @auth_chat )
reply = " I am currently located at: \n \n Host: #{ ` head -n1 /etc/hostname ` } ExtIP: #{ ` curl icanhazip.com 2>/dev/null` } "
reply = " I am currently located at: \n \n Host: #{ ` head -n1 /etc/hostname ` } ExtIP: #{ ` curl #{ @ip_provider } 2>/dev/null` } "
else
reply = " Refusal: I am not authorized to provide this information here. "
end
send_message ( message . chat . id , reply )
when '/whoami' , '/chatinfo'
#reply = "Answer: You are a meatbag named #{message.from.username}\n\nUser ID: #{message.from.id}\n\nChat ID: #{message.chat.id}"
reply = " User ID: #{ message . from . id } \n Chat ID: #{ message . chat . id } "
if command == '/whoami'
reply = " Answer: You are a meatbag named #{ message . from . username } \n \n " + reply
end
if command == '/chatinfo'
reply = reply + " \n \n Interjection: If you were intending to find information about how to connect to voice chat, try using the /voice command instead. "
end
send_message ( message . chat . id , reply )
when '/pp' , '/debug'
pp message
reply = " Confirmation: Message debug information sent to console. "
send_message( message . chat . id , " Confirmation: Message debug information sent to console. " )
when '/dance'
if is_chat_authorized? ( message , @auth_chat ) || message_from_admin? ( message , adm )
reply = " dance "
send_gif( message . chat . id , 'dance' )
else
reply = " Refusal: I am not authorized to bust a move in this location. "
send_message( message . chat . id , " Refusal: I am not authorized to bust a move in this location. " )
end
when '/flex' , '/unclemike'
if is_chat_authorized? ( message , @auth_chat ) || message_from_admin? ( message , adm )
reply = " flex "
send_gif( message . chat . id , 'flex' )
else
reply = " Refusal: I am not authorized to bring the gun show to this location. "
send_message( message . chat . id , " Refusal: I am not authorized to bring the gun show to this location. " )
end
else
reply = " Mockery: My name is #{ message . from . username } , I am a meatbag, and I think #{ command } is a valid command. "
send_message( message . chat . id , " Mockery: My name is #{ message . from . username } , I am a meatbag, and I think #{ command } is a valid command. " )
end
rescue = > e
handle_exception ( e , message , true )
# Verbose output:
puts timestamp + " : Sending #{ reply . inspect } \n \n "
#print timestamp + ": Sending #{reply.inspect} ..... "
STDOUT . flush
#puts "End of case"
return reply
end
Telegram :: Bot :: Client . run ( token ) do | bot |
### def handle_callback_query(message)
### #callbacks that start with a "!" ("!DMS|tt123456") can ONLY be submitted
### #by an admin. Ignore if normal user presses
###
### #Get "DLM" from "DLM|abc123"
### command = message.data.split("|")[0].upcase
###
### if command.start_with?('!') then
### #verify an admin pressed this button
### if ! message_from_admin?(message)
### Telegram::Bot::Client.run(@token) {|bot| bot.api.answerCallbackQuery(callback_query_id: message.id, show_alert: false, text: "Requires admin approval")}
### return
### end
### command = command.split("!")[1]
### elsif command.start_with?('#') then
### #is this an ignored command
### return
### end
###
### ack_callback(message) #Change the selection message to "Request received..."
###
### case command
### when "ZONE" #Get temp info from location
### process_callback_zone(message)
### end
###
### delete_message(message) #Delete the "Request received..." message
### rescue => e
### handle_exception(e, message, true)
### end
def handle_exception ( e , message , notify_users )
puts " = " * 60
puts " EXCEPTION OCCURRED! " . red . bold
puts " = " * 60
puts " PRINTING INSPECT... " . yellow . bold
puts e . inspect
puts " = " * 60
puts " PRINTING BACKTRACE... " . yellow . bold
puts e . backtrace
puts " = " * 60
STDOUT . flush
if notify_users == true then
#is this a callback query or a message
case message
when Telegram :: Bot :: Types :: Message
send_message ( message . chat . id , " I have run into an issue while processing a command. \n \n Please notify an administrator. " )
when Telegram :: Bot :: Types :: CallbackQuery
send_message ( message . message . chat . id , " I have run into an issue while processing a request. \n \n Please notify an administrator. " )
end
end
end
Telegram :: Bot :: Client . run ( @token ) do | bot |
bot . listen do | message |
#pp message
validation = validate_incoming_data ( message )
#puts "DEBUG: #{validation}"
if validation
reply = handle_message ( message )
if reply == " dance " || reply == " flex "
bot . api . sendVideo ( chat_id : message . chat . id , video : " https://img.skyfalltech.net/togra/ #{ reply } .gif " )
elsif ! message . text . nil?
bot . api . send_message ( chat_id : message . chat . id , text : " #{ reply } " )
#Change message.from.username to something we can call the user. This makes referring to the user in replies much easier.
if ! message . from . username . nil? #Username -> @Username
message . from . username = " @ " + message . from . username
elsif ! message . from . first_name . nil? #Username -> John
message . from . username = message . from . first_name
end
#reply = handle_message(message)
#print timestamp + ": Sending ............ "
if ! message . text . nil?
#if reply == "dance" || reply == "flex"
# bot.api.sendVideo(chat_id: message.chat.id, video: "https://img.skyfalltech.net/togra/#{reply}.gif")
#else
## bot.api.send_message(chat_id: message.chat.id, text: "#{reply}")
## print "OK\n".green.bold
## puts "Sent: #{reply.inspect}\n\n"
case message
when Telegram :: Bot :: Types :: Message
handle_message ( message ) #entrypoint for all messages
when Telegram :: Bot :: Types :: CallbackQuery
handle_callback_query ( message ) #entrypoint for all callback queries
end
else
print 'FAIL' . red . bold
print " (Message is NULL) \n \n "
end
STDOUT . flush
else