#!/usr/bin/perl # # Date: Fri Jan 29 12:02:54 CST 2010 # # I, Josh Odom, am responsible for this atrocity. # # This script connects to omegle, and forces the stranger to # talk to megahal... then it records the resulting conversation # for all to see. # # Credit where credit is due: I learned of the omegle structure from # this forum post: http://forums.hackthissite.org/viewtopic.php?f=37&t=3783 # Thanks, thedotmaster! # use strict; use JSON; # events are passed in JSON # these are to support post requests use HTTP::Request::Common qw(POST); use LWP::UserAgent; # for sewing... use threads; use threads::shared; # to connect to our friend, megahal! use AI::MegaHAL; # declaration my $ua; my $pending_messages :shared; my $omegle_id :shared; my $log_fh; my $polling_thread; my $megahal; my $log_filename; my $last_message; my $last_last_message; my $ticks_since_lmr; my $event; my $disconnected; my $base_address; my $start_address; my $events_address; my $typing_address; my $send_address; my $disconnect_address; # initialization $ua = LWP::UserAgent->new; $pending_messages = ""; $omegle_id = ""; $megahal = new AI::MegaHAL( Path => "./megahal_data/", AutoSave => 1 ); $last_message = ""; $last_last_message = ""; $base_address = "http://omegle.com/"; $start_address = $base_address . "start"; $events_address = $base_address . "events"; $typing_address = $base_address . "typing"; $send_address = $base_address . "send"; $disconnect_address = $base_address . "disconnect"; # main # turn on autoflush $|++; $polling_thread = threads->create(\&event_polling_thread); while(1) { omegle_start(); $ticks_since_lmr = 0; $last_last_message = ""; $disconnected = 0; log_new(); while($disconnected != 1) { $last_message = ""; # critical section { lock($pending_messages); if ($omegle_id eq "") { log_write("Stranger Disconnected"); $disconnected = 1; } else { $last_message = $pending_messages; } $pending_messages = ""; } chomp($last_message); if ($last_message ne "") { log_write("Stranger: " . $last_message); my $read_time; my $type_time; my $response; # compute read time $read_time = length($last_message)/20; if ($read_time > 6) { $read_time = 6; } sleep $read_time; # formulate a response; this is factored into the sleep time... $response = hal_reply($last_message); # compute type time $type_time = length($response)/10; if ($type_time > 10) { $type_time = 10; } omegle_toggle_typing(); sleep $type_time; omegle_send($response); $ticks_since_lmr = 0; $last_last_message = $last_message; } elsif ($disconnected != 1) { # if no message was sent, tick away $ticks_since_lmr += 1; if ($ticks_since_lmr == 31) { if ($last_last_message eq "") { omegle_disconnect(); $disconnected = 1; } else { my $type_time; my $response; # formulate a response; this is factored into the sleep time... $response = hal_reply($last_last_message); # compute type time $type_time = length($response)/10; if ($type_time > 10) { $type_time = 10; } omegle_toggle_typing(); sleep $type_time; omegle_send($response); } } if ($ticks_since_lmr == 61) { omegle_disconnect(); $disconnected = 1; } } sleep 1; } log_close(); if (-e "../exit_gracefully") { exit; } sleep 15; } # initiates a connection sub omegle_start { my $request; my $id; $request = POST $start_address; $id = $ua->request($request)->decoded_content; $id = substr $id, 1, 6; # critical section { lock($pending_messages); $omegle_id = $id; } } # blocking; polls for new events and returns as a list (possibly empty) sub omegle_poll_event_list { my $request; my $event_list_string; my $event_list; $request = POST $events_address, [ id => $omegle_id ]; $event_list_string = $ua->request($request)->decoded_content; if ($event_list_string ne "null") { $event_list = from_json($event_list_string); } else { $event_list = []; } return $event_list; } # tells omegle that we've changed typing state sub omegle_toggle_typing { my $request; $request = POST $typing_address, [ id => $omegle_id ]; $ua->request($request)->decoded_content; } # sends a message sub omegle_send { my $request; my $message; ($message) = @_; log_write("Hal: " . $message); $request = POST $send_address, [ msg => $message, id => $omegle_id ]; $ua->request($request)->decoded_content; } # if they were boring us sub omegle_disconnect { my $request; $request = POST $disconnect_address, [ id => $omegle_id ]; $ua->request($request)->decoded_content; log_write("Hal disconnected"); # critical section { lock($pending_messages); $omegle_id = ""; } } sub get_timestamp { # confusing enough? it works my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time); return sprintf "%4d-%02d-%02d_%02d_%02d_%02d", $year+1900,$mon+1,$mday,$hour,$min,$sec; } # opens a new log sub log_new { my $timestamp; $timestamp = get_timestamp(); $log_filename = "/mnt/share/www/omegle_hal/" . $timestamp . ".log"; #$log_filename = $timestamp . ".log"; print "### Opening log " . $log_filename . " for writing\n"; open($log_fh, ">", $log_filename) or die; } sub log_write { my $message; ($message) = @_; $message = $message . "\n"; print $message; print $log_fh $message; } sub log_close { print "### Closing log " . $log_filename . "\n"; close($log_fh); } # unused sub hal_greeting { return lc($megahal->initial_greeting()); } sub hal_reply { my $input; ($input) = @_; return ucfirst($megahal->do_reply($input)); } sub event_polling_thread { my $id; my $event_list = []; while(1) { $event_list = []; if ( $id ne "" ) { $event_list = omegle_poll_event_list(); } # critical section { lock($pending_messages); foreach $event (@{$event_list}) { if ( @{$event}[0] eq "strangerDisconnected") { $omegle_id = ""; } if ( @{$event}[0] eq "gotMessage" ) { my $temp_message; $temp_message = @{$event}[1]; $pending_messages = $pending_messages . $temp_message . "\n"; } } $id = $omegle_id; } sleep 1; } }