October 24, 2009

Tangent City

I blame Dave for wasting most of my day... He sent out a message saying that the URL of his site had changed. As part of that the URLs for his RSS feeds changed. I'm currently using Google Reader and wanted to update the feed URLs. I'm on a Mac and use Safari for my browsing needs. By default in Safari when you click on a link that is a feed it opens in Safari's RSS reader, not what I wanted. Off to investigate other options.

A quick Google search led me to a menu bar Google Reader tool that can also act as Safari's RSS reader. More than I wanted but a great option if I wanted to stay more on top of my RSS feeds. Not something I need to be doing.

At this point I'm vague on how I went down the path but I thought I'd create my own application to do what I wanted with an RSS feed. I really wanted to duplicate the "Add to Google" button behavior so I tracked down the documentation and then wrote a short Perl script to take an arbitrary URI and use that feature. For those interested the script is:

#!/usr/bin/perl -T

use strict;
use URI::Escape;

# verify that a URI exists to add
if (scalar(@ARGV) < 1)
{
    die "No URI passed.";
}

# untaint the path as exec is used
$ENV{"PATH"} = "";

# uri_escape_utf8() used in this context effectively untaints the data
# but given how it operates it doesn't satify Perl's untaint
# requirements. Since the PROGRAM LIST version of exec is used, a
# fairly liberal regexp can be used to untaint the uri.
my $uri = uri_escape_utf8($ARGV[0]);
if ($uri =~ /^([A-Za-z0-9\-_.!~*'()\%]*)$/)
{
    $uri = $1;
}
else
{
    die "URI is not safe : $uri\n";
}

exec("/usr/bin/open", "-a", "/Applications/Safari.app", "http://fusion.google.com/add?source=atgs&feedurl=$uri") || die "Unable to exec /usr/bin/open : $!\n";

It was only after writing the script that I realized one can't have a script act as an application on a Mac. Turns out there are two great options for packaging a script as an application. The first is DropScript and the other more fully feature one is Platypus. Turns out neither one worked for me. Despite twiddling all the knobs that I could with each program, my script never got passed the URI of the feed when I clicked on it in Safari.

Back to searching some more and I ran across a very light weight application called reader-helper that did most of what I wanted. As noted though there is a little bug in the program that causes Google Reader to freak out a little when clicking on a link. A quick scan of the program's source let me see that it would be easy to change the code to use the other URL for adding the feed and fix the Google Reader issue. Along the way I also fixed some missing URI reserved characters that should be encoded when passing a URI as a query parameter. The patch ended up being:

Index: GoogleReader.m
===================================================================
--- GoogleReader.m      (revision 8)
+++ GoogleReader.m      (working copy)
@@ -13,8 +13,8 @@

 +(void)subscribeToFeed:(NSString *)feedURL
 {
-       NSString *apiStr = @"http://www.google.com/reader/preview/*/feed/";
-       CFStringRef feedStr = CFURLCreateStringByAddingPercentEscapes(NULL, (CFStringRef)feedURL, NULL, (CFStringRef)@";/?:@&=+$,", kCFStringEncodingUTF8);
+       NSString *apiStr = @"http://fusion.google.com/add?source=atgs&feedurl=";
+       CFStringRef feedStr = CFURLCreateStringByAddingPercentEscapes(NULL, (CFStringRef)feedURL, NULL, (CFStringRef)@":/?#[]@!{{content}}amp;’()*+,;=", kCFStringEncodingUTF8);
        NSString *cmdStr = [apiStr stringByAppendingString:[NSString stringWithFormat:@"%@", feedStr]];
        NSLog(cmdStr);
        [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:cmdStr]];

My next problem was recompiling the source to incorporate my change. Thankfully all I had to do was wait for the newest XCode to download. Once I installed XCode creating a new binary was a snap. A ran into one last little issue in that Reader Helper doesn't exit after being launched. I had to manually kill the executable before my new binary was recognized.

While this wasn't how I thought I was going to spent my day it felt really good to just hack around on a little problem that was bugging me. It feels even better to have found a solution.

Tags: code hack mac