Skip to content

Instantly share code, notes, and snippets.

@jnewland
Created February 6, 2023 00:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jnewland/f661c6b87c1d3f62413b382cd4d14dbd to your computer and use it in GitHub Desktop.
Save jnewland/f661c6b87c1d3f62413b382cd4d14dbd to your computer and use it in GitHub Desktop.
From May of 2008, for historical purposes: a Twitter bot that allowed sharing your location on Fire Eagle (RIP) via DMs
# Tiny Twitter Bot.
#
require 'rubygems'
require 'xmpp4r-simple'
require 'active_record'
require 'fireeagle'
require 'kconv'
require 'shorturl'
require 'uri'
DEBUG = true
class Invite < ActiveRecord::Base
end
class User < ActiveRecord::Base
attr_accessor :fireeagle
def init_fireeagle(app_id, consumer_key, consumer_secret)
if self.authorized?
@fireeagle = FireEagle::Client.new(
:consumer_key => consumer_key,
:consumer_secret => consumer_secret,
:app_id => app_id,
:access_token => self.access_token,
:access_token_secret => self.access_token_secret)
elsif self.has_request_token?
@fireeagle = FireEagle::Client.new(
:consumer_key => consumer_key,
:consumer_secret => consumer_secret,
:app_id => app_id,
:request_token => self.request_token,
:request_token_secret => self.request_token_secret)
else
@fireeagle = FireEagle::Client.new(
:consumer_key => consumer_key,
:consumer_secret => consumer_secret,
:app_id => app_id)
end
end
def has_request_token?
!self.request_token.blank? && !self.request_token_secret.blank?
end
def authorized?
!self.access_token.blank? && !self.access_token_secret.blank?
end
def get_request_token
token = self.fireeagle.get_request_token(true)
self.update_attributes(:request_token => token.token, :request_token_secret => token.secret, :access_token => nil, :access_token_secret => nil)
return token.token
end
def authorization_url
return nil unless self.has_request_token?
self.fireeagle.authorization_url
end
def authorize
return false unless self.has_request_token?
begin
token = self.fireeagle.convert_to_access_token
self.update_attributes(:request_token => nil, :request_token_secret => nil, :access_token => token.token, :access_token_secret => token.secret)
return true
rescue
return false
end
end
def update_location(q)
return false unless self.authorized?
self.fireeagle.update(:q => q).success?
end
def location
return false unless self.authorized?
begin
response = self.fireeagle.user
return response.best_guess.name
rescue
return nil
end
end
def to_s
self.username
end
end
class DangerDay
attr_accessor :client, :app_id, :consumer_key, :consumer_secret, :num_checks, :user, :pass
def initialize(user, pass, app_id, consumer_key, consumer_secret)
Jabber::debug = ENV['DEBUG'] || false
@user, @pass = user, pass
jabber_login
@app_id = app_id
@consumer_key = consumer_key
@consumer_secret = consumer_secret
@num_checks = 0
end
def jabber_login
@client = Jabber::Simple.new(@user, @pass)
end
def run
while (true) do
@num_checks += 1
jabber_login if ((@num_checks % 1000) == 0)
sleep(10)
puts "checking for new messages..." if DEBUG
@client.received_messages do |message|
puts "Received: " + Time.now.to_s if DEBUG
puts message.from if DEBUG
puts message.body if DEBUG
puts "-"*80 if DEBUG
unless message.type == :error
if message.from == "twitter@twitter.com"
if message.body =~ /Direct from (.*):/
sender = $1
body = message.body.split(/\r?\n/)[1].strip
self.process_direct_message(sender, body)
# if direct
elsif message.body =~ /(.*): .* L:(.*)/
sender = $1
location = $2
self.process_twittervision_update(sender, location)
end
elsif message.from == "jnewland@gmail.com"
if message.body =~ /ping/
self.jabber_message("jnewland@gmail.com", "pong #{Time.now}")
end
end # if from twitter
end # unless error
end # callback
end
end
def process_twittervision_update(sender, location)
puts "Got a Twittervision-style update!" if DEBUG
#remove the label from the message if one is provided
loc_array = location.split("=")
location = loc_array[1] if loc_array.size > 1
# find the user
user = User.find_by_username(sender)
if user
user.init_fireeagle(app_id, consumer_key, consumer_secret)
user.update_location(location) if user.authorized?
end
end
def process_direct_message(sender, body)
puts "Got a Direct Message!" if DEBUG
# find the user
user = User.find_or_create_by_username(sender)
#connect to fireeagle
user.init_fireeagle(app_id, consumer_key, consumer_secret)
begin
if body =~ /^auth/
token = user.get_request_token
self.direct_message(sender, "ahoy, #{sender}! please visit #{user.authorization_url} to authorize firebot")
self.direct_message(sender, "once that's done, update your location like this: 'd firebot u Atlanta, GA'. Disclaimer: http://xrl.us/firebotdisclaimer")
elsif body =~ /^u (.*)/
location = $1
if user.authorized? || user.authorize
if user.update_location(location)
self.direct_message(sender,"updated your location to #{location}")
else
self.direct_message(sender,"that didn't work out. please try again later")
end
else
self.direct_message(sender, "you're not authorized yet. 'd firebot auth' to get started")
end
elsif body =~ /^q (.*)/
username = $1
queried_user = User.find_by_username(username)
if !queried_user.blank? && queried_user.authorized?
queried_user.init_fireeagle(app_id, consumer_key, consumer_secret)
location = queried_user.location
if !location.blank?
#TODO fix map link. stuff after spaces are being cut off
map_link = self.google_maps(URI.escape(location.gsub(',',' ')))
self.direct_message(sender, "last saw #{username} in #{location} (#{map_link})")
else
self.direct_message(sender, "we couldn't find #{username}. sorry!")
end
else
self.direct_message(sender, "#{username} isn't setup with firebot. why don't you ask them to follow us?")
end
elsif body =~ /^invite/
invite = Invite.find_by_username(nil)
if invite.nil?
self.direct_message(sender, "sorry, I'm out of invites!")
else
invite.update_attributes!(:username => sender)
self.direct_message(sender, "http://fireeagle.com/ticket/" + invite.url)
end
elsif body =~ /^help/ || body =~ /^hi/
self.direct_message(sender, "commands: \n'auth' to setup, \n'u Atlanta, Ga' to set location, \n'q username' to query another users location")
else
self.direct_message(sender, "firebot didn't understand your request: 'd firebot help' for instructions")
puts body.inspect
end # if body
rescue Exception => e
self.direct_message('jnewland', e.to_s + e.backtrace.join("\n"))
end
end
def direct_message(to, body)
xxx = Kconv.toutf8("d #{to} #{body}")
self.jabber_message("twitter@twitter.com", xxx)
end
def jabber_message(to, body)
puts "Sending: " + Time.now.to_s if DEBUG
puts to if DEBUG
puts body if DEBUG
puts "-"*80 if DEBUG
@client.deliver(to, body)
end
def google_maps(q)
"http://maps.google.com/maps?q=#{q}"
end
end # DangerDay
if $0 == __FILE__
user = ARGV[0]
pass = ARGV[1]
sqlite = ARGV[2]
app_id = ARGV[3]
consumer_key = ARGV[4]
consumer_secret = ARGV[5]
ActiveRecord::Base.logger = Logger.new(STDOUT)
ActiveRecord::Base.colorize_logging = false
ActiveRecord::Base.establish_connection(
:adapter => "sqlite3",
:dbfile => sqlite
)
if ARGV[0] == 'init'
ActiveRecord::Schema.define do
create_table :users do |table|
table.column :username, :string
table.column :request_token, :string
table.column :request_token_secret, :string
table.column :access_token, :string
table.column :access_token_secret, :string
end
add_index(:users, :username)
create_table :invites do |table|
table.column :username, :string
table.column :url, :string
end
end
elsif ARGV[0] == 'invites'
puts "Importing invites..."
open(ARGV[1]).read.split("\n").each do |invite|
puts invite
Invite.create(:url => invite)
end
puts "Done!"
else
puts "Connecting..."
bot = DangerDay.new(user, pass, app_id, consumer_key, consumer_secret)
puts "Connected!"
puts "Waiting for messages..."
bot.run
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment