if its too loud, turn it down

Thursday, October 15, 2009

Use Perl and Expect to auto-connect, and maintain connection, to a proxy

There are a number of reason to use a proxy, security and privacy being the two biggest for me. I use Cotse.net and am very happy with it. There is one downside to Cotse (and alot of similar services I suppose) is that you must manually connect to the proxy server, using something like SSH Tunnel Manager. Kind of a pain.

So I wrote a script that manages the connection using perl and expect. It runs as a cronjob to always make sure you're connected to the proxy when an internet connection is available.

Installation
  1. Step 1: Install the Expect.pm perl module. As root, type this:
    # perl -MCPAN -e 'install Expect'
    
  2. Step 2: Edit this script and put in your /Users/user/bin/ directory as "proxy.pl".
    # check if we are connected to the proxy.  If not, connect.
    my $pid = &checkAlive($command);
    if (!$pid) {
    
     # check if we even have internet before trying to connect to proxy
     my $result = &checkInternet($ext_host,$timeout);
     if ($result > 0) {
      print "Not connected. Connecting to $command\n";
      &connect($password,$command,$timeout);
     } else {
      print "No internet available.\n";
     }
     
    } else {
     # we do have internet, and are connected toi proxy.
     print "connected to $command\n";
    }
    
    sub connect {
     # connect to the proxy and login using expect
     
     my ($password,$command,$timeout) = @_;
     
     # Create the Expect object
     my $exp = Expect->spawn($command) or die "Cannot spawn ssh command\n";
     $exp->expect($timeout,
      ["Password Authentication"],
      ["Are you sure you want to continue connecting", sub {my $self = shift; $self->send("yes\n");}]
      );
     # answer the password
     $exp->expect($timeout,
      [ qr/Password:/ => sub { my $exp = shift; $exp->send("$password\n"); exp_continue; } ],
      [ qr/Password:/ => sub { my $exp = shift; $exp->send("$password\n"); } ], 
      );
     # wait forever for nothing...basically, stay connected
     $exp->expect(undef);
     
    } # end sub connect
    
    sub checkInternet {
     # check if the internet is up by pinging external host
     # sends back packets received, so if the return val
     # is > 0 then we have internet
    
     my ($host,$timeout) = @_;
     my $packets = 0;
     
     my $pingcmd = "/sbin/ping -q -t $timeout -c 1 $ext_host";
     #print "checking for running program with $pingcmd\n";
     my @raw = `$pingcmd`;
     chomp(@raw);
     foreach my $line (@raw) {
      if ($line =~ /([0-9]{0,2}) packets received/) {
       $packets = $1;
      }
     } # end foreach
     return ($packets);
     
    } # end sub checkInternet
    
    sub checkAlive {
     # gets the PID of the process that matches a SINGLE criteria 
    
     my ($text) = shift;
     my $return_pid = "";
     
     my $pidgetter = "/bin/ps ax -o pid,command | grep '$text' | grep -v 'grep' | grep -v 'sh -c'";
     #print "checking for running program with $pidgetter\n";
     my @raw_pids = `$pidgetter`;
     chomp(@raw_pids);
     
     foreach my $raw_pid (@raw_pids) {
      $raw_pid =~ s/^\s+//;
      $raw_pid =~ /^(\d+)\s/;
      $raw_pid = $1;
      my $pid = stripNonNumber($raw_pid);
      my $exists = kill("0",$pid);
      if ($exists) {
       my $message = "checking for any program operating on $text. I found one with pid ${pid}. ";
       $return_pid = $pid
      }
     } # end foreach
     
     return ($return_pid);
    
    } # end sub checkAlive
    
    sub stripNonNumber {
    
     my($text) = shift;
     $text =~ s/([^0-9])//g;
     return ($text);
    
    } # end sub strip non number
    
    Then type this:
    cd ~/bin ; chmod 755 proxy.pl;
    
  3. Step 3: Add to cron. Type
    crontab -e
    . Add this line (you will need to edit where it says "user"):
    * * * * * /Users/user/bin/proxy.pl  > /dev/null 2>&1
    

Sunday, October 11, 2009

Use Thunderbird Extension "Send Later" (or "at") to email requests to time-shifted programs

OK, here's a tip you're unlikely to use. See if you fit these criteria...
  • You time-shift internet radio programs.
  • You sometimes want to communicate with the host/dj. For example, to make a music request
  • The program has a non-show-specific email address. For example, dj *at* kexp.org (for making requests to the current DJ).
  • You use Mozilla Thunderbird as your e-mail client.
  • You leave your computer on all the time, with your e-mail client open.
...still with me? I've got a solution for you! There's a great extension for Thunderbird called "Send Later".

Basically, it allows you to schedule emails to send at precise date/time. Here's what you do:
  1. Right-click this link and "Save link as" and save it to your desktop.
  2. In Tunderbird, go Tools -> Add-ons and click the "Install..." button. Choose the .xpi file you saved to your desktop. You will need to re-start Thunderbird.
  3. Once installed, compose your e-mail message as you would any e-mail. Instead of sending, choose File -> Send Later. That will bring up this dialog: Send Later Dialog
  4. Schedule your send using the date/time menus at the top. Then click "Send Later at specified time". I'd disregard all other options.
Then, listen to your time-shifted program for your request! If you need to edit the e-mail before the schedule send time, look for it in your "Drafts" folder. Just remember to choose File -> Send Later again instead of clicking "send". WARNING as of Send Later version 1.2.0.0 there is a strange, annoying bug that affects replying to or forwarding messages that have large attachments. Took me ages to figure out that the Send Later extension was causing it. Not a deal-breaker, but the following option may be better...

OR, be an ultra-nerd and use the "at" command...

For those nerdily inured to Mac OS X's UNIX features, you can accomplish the same feat as outlined above using "at".

First, you need to enable the
atrun
utility. It runs commands scheduled with
at
, but is disabled by default.
su
to root and run this command:
launchctl load -w /System/Library/LaunchDaemons/com.apple.atrun.plist
And if you haven't configured postfix to send outgoing mails, you'll need to do that. Check out this great tip on how to set up postfix to relay through GMail.

Alright, so to schedule an email to be sent, open up a terminal and first type the date/time (in POSIX format) you want it to be sent like this:
$ at -t 200910112232
You will then enter input mode. Enter your commands here like this:
mail -s "Music Request" [ENTER TO EMAIL HERE]
Dear DJ,
Last night you saved my life.  Can you
please play, "Crazy Horses" by The
Osmonds?  Thanks so much!
Love,
Me
Then hit enter once (blank line), then CTRL-d to exit input mode. Your mail is now scheduled! To see scheduled jobs, enter the 'atq' command.