<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>IslandJohn.com</title>
	<atom:link href="http://www.islandjohn.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.islandjohn.com</link>
	<description></description>
	<lastBuildDate>Sat, 06 Nov 2010 00:11:28 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Simple iOS UDID Tracking Solution</title>
		<link>http://www.islandjohn.com/2010/11/04/simple-ios-udid-tracking-solution/</link>
		<comments>http://www.islandjohn.com/2010/11/04/simple-ios-udid-tracking-solution/#comments</comments>
		<pubDate>Thu, 04 Nov 2010 23:13:46 +0000</pubDate>
		<dc:creator>janos</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[iPad]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[UDID]]></category>

		<guid isPermaLink="false">http://www.islandjohn.com/?p=289</guid>
		<description><![CDATA[You may want to track your application's users' UDIDs for a myriad of reasons, such as checking user retention, update rate etc. However, since Apple has changed their terms and conditions regarding UDID collection, you cannot use a third party to gain access to them, so using an SDK like Flurry won't get you what [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify;">You may want to track your application's users' UDIDs for a myriad of reasons, such as checking user retention, update rate etc. However, since Apple has changed their terms and conditions regarding UDID collection, you cannot use a third party to gain access to them, so using an SDK like Flurry won't get you what you want. So, if you want to undertake certain marketing ventures, such PPA advertising, you'll need to collect them yourself.<br />
<span id="more-289"></span><br />
Below you'll find a simple framework that will allow you to do the collection on your own. It consists of a PHP script to place on your web server that stores submitted data in a MySQL database, the SQL statements to create the database and tables, and the Objective-C code to insert in your application to submit the data to you server. I'm sure similar things have been written thousands of times before, but I thought I'd post it in the hopes that will be useful to someone.</p>
<h3>PHP</h3>
<p style="text-align: justify;">The PHP script should be placed on your web server. If you have a dedicated host (or virtual host) for this task, you can name it <em>index.php</em> and make it the directory index. Also, if you're paranoid, you can move the more sensitive definitions to an include file located outside the web directory. And, if you're doubly paranoid, you can chose to not display the SQL error messages when something fails by modifying the error handling parts of the code.</p>
<pre>&lt;?php

error_reporting(0); # 0 for production

$host = 'localhost';
$user = 'islandjohn';
$password = 'changethis';
$db = 'islandjohn';
$header = 'X-IslandJohn-Status';

$ip = $_SERVER['REMOTE_ADDR'];
$udid = stripslashes($_GET['udid']);
$bid = stripslashes($_GET['bid']);
$version = stripslashes($_GET['version']);

if (!$ip || !$udid || !$bid || !$version) {
    header($header.' Missing parameters');
    exit();
}

$d = mysql_connect($host, $user, $password);
if (!$d) {
    header($header.': Could not connect: '.mysql_error());
    exit();
}

if (!mysql_select_db($db)) {
    header($header.': Could not select database: '.mysql_error());
    mysql_close($d);
    exit();
}

$q = sprintf('INSERT INTO `analytics` (`ip`,`udid`,`bid`,`version`) VALUES("%s","%s","%s","%s") ON DUPLICATE KEY UPDATE `timestamp`=CURRENT_TIMESTAMP(),`updates`=`updates`+1,`ip`=VALUES(`ip`)', mysql_real_escape_string($ip), mysql_real_escape_string($udid), mysql_real_escape_string($bid), mysql_real_escape_string($version));

if (!mysql_query($q)) {
    header($header.': Could not update table: '.mysql_error());
    mysql_close($d);
    exit();
}

mysql_close($d);

header($header.': OK');

?&gt;</pre>
<h3>SQL</h3>
<p style="text-align: justify;">The SQL statements below will create database and table to store the submitted data. It's setup to collect simple information only, but can be easily extended. User access setup is left as an exercise for the reader.</p>
<pre>CREATE DATABASE `islandjohn`;
CREATE TABLE `analytics` (
  `timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
  `updates` int(11) NOT NULL default '0',
  `ip` varchar(64) NOT NULL,
  `udid` varchar(64) NOT NULL,
  `bid` varchar(64) NOT NULL,
  `version` varchar(64) NOT NULL,
  UNIQUE KEY `idx_ubv` (`udid`,`bid`,`version`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;</pre>
<h3>Objective-C</h3>
<p style="text-align: justify;">The code below is used to start the HTTP connection to submit the data, and record success. My goal was to collect information only one time any given version of my application is launched, so I record a successful submission and won't submit again unless there's a version mismatch. If you want to keep track of all launches, you can modify the code accordingly.</p>
<pre>- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    if (![response isKindOfClass:[NSHTTPURLResponse class]]) {
        return;
    }

    NSHTTPURLResponse *http = (NSHTTPURLResponse *)response;
    NSMutableDictionary *headers = [NSMutableDictionary dictionaryWithDictionary:[http allHeaderFields]];
    for (NSString *key in [headers allKeys]) {
        [headers setObject:[headers objectForKey:key] forKey:[key lowercaseString]];
    }
    NSString *status = [headers objectForKey:@"x-islandjohn-status"];

    if ([status isEqualToString:@"OK"]) {
        [[NSUserDefaults standardUserDefaults] setObject:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]
                                                  forKey:@"IJAnalyticsSubmittedVersion"];
        [[NSUserDefaults standardUserDefaults] synchronize];
    }
}

- (void) submitAnalytics {
    if ([[[NSUserDefaults standardUserDefaults] objectForKey:@"IJAnalyticsSubmittedVersion"]
         isEqualToString:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]]) {
        return;
    }

    NSString * udid = (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,
                                                                          (CFStringRef)[[UIDevice currentDevice] uniqueIdentifier],
                                                                          NULL,
                                                                          (CFStringRef)@" !*'();:@&amp;=+$,/?%#[]",
                                                                          kCFStringEncodingUTF8);
    NSString * bid = (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,
                                                                         (CFStringRef)[[NSBundle mainBundle] bundleIdentifier],
                                                                         NULL,
                                                                         (CFStringRef)@" !*'();:@&amp;=+$,/?%#[]",
                                                                         kCFStringEncodingUTF8);
    NSString * version = (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,
                                                                             (CFStringRef)[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"],
                                                                             NULL,
                                                                             (CFStringRef)@" !*'();:@&amp;=+$,/?%#[]",
                                                                             kCFStringEncodingUTF8);        

    NSString *url = [NSString stringWithFormat:
                     @"http://analytics.domain.com/?udid=%@&amp;bid=%@&amp;version=%@",
                     udid,
                     bid,
                     version];
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
    NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];
}

- (void) applicationDidFinishLaunching:(UIApplication*)application {
    @try {
        [self submitAnalytics];
    }
    @catch (NSException *e) {
    }
    @finally {
    }

    // Your code continues here...
}</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.islandjohn.com/2010/11/04/simple-ios-udid-tracking-solution/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Bee Patrol for iPad and iPhone: an Action, Puzzle, and Strategy Game Combination</title>
		<link>http://www.islandjohn.com/2010/10/23/bee-patrol-an-action-puzzle-and-strategy-game-combination/</link>
		<comments>http://www.islandjohn.com/2010/10/23/bee-patrol-an-action-puzzle-and-strategy-game-combination/#comments</comments>
		<pubDate>Sat, 23 Oct 2010 04:40:40 +0000</pubDate>
		<dc:creator>janos</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[cocos2d]]></category>
		<category><![CDATA[iPad]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[OpenGL]]></category>

		<guid isPermaLink="false">http://www.islandjohn.com/?p=120</guid>
		<description><![CDATA[After my Word Quest publication, I decided to venture further into iPhone application development, and try to write something a little different. Using cocos2d, and some OpenGL, I wanted to combine line drawing games, like Flight Control and Harbor Master, with some puzzle elements and strategy components, like resource management. So I did. The concept [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify;">After my Word Quest publication, I decided to venture further into iPhone application development, and try to write something a little different. Using cocos2d, and some OpenGL, I wanted to combine line drawing games, like Flight Control and Harbor Master, with some puzzle elements and strategy components, like resource management. So I did.<br />
<span id="more-120"></span><br />
The concept is to manage a colony of bees. You are in control and draw paths for bees as they either appear on screen returning from afar, or as they sit waiting in the hive, depending on the game mode selected. The bees must return to the hive or they'll die, they age, but they can only return if they're carrying nectar. Along your path you must visit flowers to pickup nectar, and as you visit them in a sequence you pollinate ones of similar color. You have to pollinate flowers because they also age, wilt and then die. Along the way you can pass through obstacles like rain and wind that can slow your down or speed you up, and navigate to or around drone bees that give you life and spiders that kill you.</p>
<p style="text-align: justify;">The code, music and sound effects were arranged/created/written by me. Most of the art however, with the exception of some graphic design and sprites, was subcontracted out. The project overall is smaller than Word Quest, about half the amount of source code, but took substantially longer to complete, with about the same number of total hours, because of the many tedious tasks involved. It should be available soon for both iPad and iPhone.</p>
<p style="text-align: justify;">
]]></content:encoded>
			<wfw:commentRss>http://www.islandjohn.com/2010/10/23/bee-patrol-an-action-puzzle-and-strategy-game-combination/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Word Quest iPhone Application: My Introduction to Apple Development</title>
		<link>http://www.islandjohn.com/2010/02/09/word-quest-iphone-application-my-introduction-to-apple-development/</link>
		<comments>http://www.islandjohn.com/2010/02/09/word-quest-iphone-application-my-introduction-to-apple-development/#comments</comments>
		<pubDate>Tue, 09 Feb 2010 04:00:46 +0000</pubDate>
		<dc:creator>janos</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://www.islandjohn.com/wp/?p=22</guid>
		<description><![CDATA[Exactly one month ago I decided to dive into Apple's Xcode, Objective-C and their, what I now think are, lovely APIs. I thought about this adventure before, but I just never pushed myself. It was apparently a very bored evening, so what else was I going to do. I must say Objective-C seemed strange at [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify;">Exactly one month ago I decided to dive into Apple's Xcode, Objective-C and their, what I now think are, lovely APIs. I thought about this adventure before, but I just never pushed myself. It was apparently a very bored evening, so what else was I going to do. I must say Objective-C seemed strange at first, but once I went through it all, wrote a few lines of code, it seemed almost elegant. It's an extension of C, and if you think about it, you could almost implement a parser for Objective-C that would generate plain C code to do all the magic. It's a pretty abstraction layer with a mandatory runtime environment. I like it. After a few hours of playing with Xcode, it became apparent that I should just dive right in.<br />
<span id="more-22"></span><br />
I decided on a somewhat simple word search game, but with some added twists. I thought the algorithm to place the words so that you generate well-rounded puzzles was interesting, so it gave me a chance to come up with some quirky logic, and I'd have a chance to dive into their Core Graphics and Core Animation graphics APIs. It was fun. It was actually the most fun I had developing since back in high-school when I was writing demos in assembler and C. Apple's documentation and guides were excellent on most everything (I used nothing but those), and I've had no issues with the iPhone Developer Program so far. Along the way I explored Garage Band for some of the sound, used iWeb for the site, and played with Gimp for the grahpics. So, exactly one month later, with a dozen or so really late nights invested, the game is done, submitted to the App Store, and "In Review".</p>
]]></content:encoded>
			<wfw:commentRss>http://www.islandjohn.com/2010/02/09/word-quest-iphone-application-my-introduction-to-apple-development/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Snow Leopard, Canon MP620, and Airport Extreme Weirdness</title>
		<link>http://www.islandjohn.com/2009/12/02/snow-leopard-canon-mp620-and-airport-extreme-weirdness/</link>
		<comments>http://www.islandjohn.com/2009/12/02/snow-leopard-canon-mp620-and-airport-extreme-weirdness/#comments</comments>
		<pubDate>Wed, 02 Dec 2009 04:00:30 +0000</pubDate>
		<dc:creator>janos</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Airport Extreme]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[Canon]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[MP620]]></category>
		<category><![CDATA[OS X]]></category>
		<category><![CDATA[Snow Leopard]]></category>

		<guid isPermaLink="false">http://www.islandjohn.com/wp/?p=23</guid>
		<description><![CDATA[After hours of troubleshooting, a disconnected anomaly was all I could find. For months my Canon MP620 printer worked fine under Leopard and Snow Leopard. My wife's MacBook printed well wirelessly. But, one day her MacBook printing just stopped working. I went through the usual suspects: reboot machine, reboot printer, reinstall drivers, manually clean out [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify;">After hours of troubleshooting, a disconnected anomaly was all I could find. For months my Canon MP620 printer worked fine under Leopard and Snow Leopard. My wife's MacBook printed well wirelessly. But, one day her MacBook printing just stopped working. I went through the usual suspects: reboot machine, reboot printer, reinstall drivers, manually clean out drivers and reinstall etc. Nothing worked.<br />
<span id="more-23"></span><br />
I finally started tcpdump and compared the printing traffic from my MacBook Pro (which still worked correctly) and her MacBook. Both appeared to do the initial printing discovery and negotiation (mDNS) but my wife's MacBook would not get a response from the printer. After some detailed analysis the only difference was that when the printer did an ARP request for her machine's IP, it did not receive a response. What!? Her machine was fine otherwise; how can such an isolated corner-case happen? All signs pointed to the Airport Extreme base station, through which everything was connected.</p>
<p style="text-align: justify;">I thought it was time to reboot a device that, for all intents and purposes, should not have anything to do with this problem. A few minutes passed as the unit went through its cycle, and without as much as laying a finger on the MacBook, queued test jobs began streaming from the printer.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.islandjohn.com/2009/12/02/snow-leopard-canon-mp620-and-airport-extreme-weirdness/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Create a Range of Solid Colors for Desktop Backgrounds</title>
		<link>http://www.islandjohn.com/2009/11/01/create-a-range-of-solid-colors-for-desktop-backgrounds/</link>
		<comments>http://www.islandjohn.com/2009/11/01/create-a-range-of-solid-colors-for-desktop-backgrounds/#comments</comments>
		<pubDate>Sun, 01 Nov 2009 04:00:35 +0000</pubDate>
		<dc:creator>janos</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[CLI]]></category>
		<category><![CDATA[GUI]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[OS X]]></category>
		<category><![CDATA[Snow Leopard]]></category>

		<guid isPermaLink="false">http://www.islandjohn.com/wp/?p=21</guid>
		<description><![CDATA[Both Mac OS X Leopard and Snow Leopard come with a paltry set of solid colors for desktop backgrounds. This is easily remedied with ImageMagick (available for install through the MacPorts Project) and a quick hack. The script below generates all the background images for web-safe colors that should then be immediately available for use [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify;">Both Mac OS X Leopard and Snow Leopard come with a paltry set of solid colors for desktop backgrounds. This is easily remedied with ImageMagick (available for install through the MacPorts Project) and a quick hack. The script below generates all the background images for web-safe colors that should then be immediately available for use under the Solid Colors selection in the Desktop and Screen Saver System Preferences. You can copy and paste the script into Terminal, but you'll need to be a system administrator for it to succeed because it writes the images into "/Library/Desktop Pictures/Solid Colors".<br />
<span id="more-21"></span></p>
<pre style="text-align: justify;">cd /Library/Desktop\ Pictures/Solid\ Colors; for r in 00 33 66 99 cc ff; do for g in 00 33 66 99 cc ff; do for b in 00 33 66 99 cc ff; do echo Creating image for color $r$g$b; convert -background "#$r$g$b" -page 256x256 text:- "Background $r$g$b.jpg" &lt; /dev/null; done; done; done</pre>
<p style="text-align: justify;">Alternatively, since the preference pane displays the images in a five column layout, you can use the script below to create images that will be more aesthetically pleasing during selection, as they'll line up nicely according to shades:</p>
<pre style="text-align: justify;">cd /Library/Desktop\ Pictures/Solid\ Colors; for r in 00 40 80 c0 ff; do for g in 00 40 80 c0 ff; do for b in 00 40 80 c0 ff; do echo Creating image for color $r$g$b; convert -background "#$r$g$b" -page 256x256 text:- "Background $r$g$b.jpg" &lt; /dev/null; done; done; done</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.islandjohn.com/2009/11/01/create-a-range-of-solid-colors-for-desktop-backgrounds/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>File Locking and Exclusive/Synchronized Execution in a Shell</title>
		<link>http://www.islandjohn.com/2009/10/14/file-locking-and-exclusivesynchronized-execution-in-a-shell/</link>
		<comments>http://www.islandjohn.com/2009/10/14/file-locking-and-exclusivesynchronized-execution-in-a-shell/#comments</comments>
		<pubDate>Wed, 14 Oct 2009 04:00:53 +0000</pubDate>
		<dc:creator>janos</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[CLI]]></category>

		<guid isPermaLink="false">http://www.islandjohn.com/wp/?p=20</guid>
		<description><![CDATA[Many shell scripts need to execute exclusively as a singleton, or at least carry out blocks of execution that must be run exclusively. While this sounds like an easy job for things like ps and grep, or the creation and testing of a file on the file system, these quick and dirty tricks lead only [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify;">Many shell scripts need to execute exclusively as a singleton, or at least carry out blocks of execution that must be run exclusively. While this sounds like an easy job for things like ps and grep, or the creation and testing of a file on the file system, these quick and dirty tricks lead only to headaches down the line. In order to create synchronized execution in a shell, one needs some task that is guaranteed by the operating system to execute atomically and provide feedback. On Unix-based system, that shell-based command is ln.<br />
<span id="more-20"></span><br />
Below are two shell functions that provide atomic locking through the use of ln. The functions lockcreate and lockremove provide locking capabilities to allow shell processes to synchronize on a file; lockcreate can either fail if a lock cannot be obtained, wait for a specified period of time, or block indefinitely. The functions are smart enough to handle corner cases, such as a process holding a lock dying without removing the lock, but the handling of these cases are not atomic.</p>
<pre style="text-align: justify;">#!/bin/bash

# args: [lockfile=$0.lock] [lockwait=0]
# ret: 0 on success, 1 on failure, -1 on unknown
function lockcreate() {
    lockfile="$1"
    lockwait="$2"

    if [ -z "$lockfile" ]; then
        lockfile="$0.lock"
    fi

    if [ -z "$lockwait" ]; then
        lockwait=0
    fi

    lockerr=-1
    lockcount=0

    echo "$$" &gt; "$lockfile.$$"

    while [ "$lockwait" -lt 0 -o "$lockcount" -le "$lockwait" ]; do
        ln -hs "$lockfile.$$" "$lockfile"

        # the lock exists
        if [ "$?" -gt 0 ]; then
            lockpid="`cat \"$lockfile\"`"

            # the lock PID is empty (race condition?), cleanup and retry
            if [ -z "$lockpid" ]; then
                rm "$lockfile"
                continue
            else
                # the lock PID is this PID (previous same PID died), success
                if [ "$$" -eq "$lockpid" ]; then
                    $lockerr=0
                    break
                fi

                ps -p "$lockpid"

                # the lock PID is not running, cleanup and retry
                if [ "$?" -gt 0 ]; then
                    rm "$lockfile"
                    continue
                # the lock PID is running, fail or wait
                else
                    if [ "$lockwait" -eq 0 ]; then
                        rm "$lockfile.$$"
                        lockerr=1
                        break
                    fi
                fi
            fi
        # the lock was created, success
        else
            lockerr=0
            break
        fi

        # wait and retry
        sleep 1
        lockcount="`expr \"$lockcount\" + 1`"
    done

    return $lockerr
}

# args: [lockfile]
function lockremove() {
    lockfile="$1"

    if [ -z "$lockfile" ]; then
        lockfile="$0.lock"
    fi

    lockpid="`cat \"$lockfile\"`"

    if [ -z "$lockpid" ]; then
        true
    else
        if [ "$$" -eq "$lockpid" ]; then
            rm "$lockfile"
        fi
    fi

    # clean up any temporary would-be lock
    if [ -e "$lockfile.$$" ]; then
        rm "$lockfile.$$"
    fi
}</pre>
<p style="text-align: justify;">The following example creates a synchronized block that will execute exclusively. All other copies of the script will wait indefinitely for the currently executing copy to finish before executing their own block. The order in which waiting processes execute is not predictable, that is, there is no wait queue.</p>
<pre style="text-align: justify;">lockcreate /tmp/example.lock -1
echo Running...
sleep 60
echo Done.
lockremove /tmp/example.lock</pre>
<p style="text-align: justify;">The example below attempts to execute a block. If another copy of the script is already executing the synchronized block, the current script will exit.</p>
<pre style="text-align: justify;">lockcreate /tmp/example.lock
if [ $? -eq 0 ]; then
    echo Running...
    sleep 60
    echo Done.
else
    echo Another copy of this script is already running, or an error occured.
fi
lockremove /tmp/example.lock</pre>
<p style="text-align: justify;">Neither of the locking functions are quiet. If the underlying operating system commands display any output, they will show up in the script calling the functions. In order to provide a clean and quiet run, the functions' output must be redirected (something like lockcreate &gt;/dev/null 2&gt;&amp;1 works nicely).</p>
]]></content:encoded>
			<wfw:commentRss>http://www.islandjohn.com/2009/10/14/file-locking-and-exclusivesynchronized-execution-in-a-shell/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Dynamic DNS Updates with BIND and an Airport Extreme</title>
		<link>http://www.islandjohn.com/2009/10/03/dynamic-dns-updates-with-bind-and-an-airport-extreme/</link>
		<comments>http://www.islandjohn.com/2009/10/03/dynamic-dns-updates-with-bind-and-an-airport-extreme/#comments</comments>
		<pubDate>Sat, 03 Oct 2009 04:00:30 +0000</pubDate>
		<dc:creator>janos</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Airport Extreme]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[bind]]></category>
		<category><![CDATA[CLI]]></category>
		<category><![CDATA[DNS]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[OS X]]></category>

		<guid isPermaLink="false">http://www.islandjohn.com/wp/?p=19</guid>
		<description><![CDATA[My home network has an Apple Airport Extreme as the first stop from my cable modem, which of course provides dynamic addressing, and I run my own BIND DNS server on the Internet. I wanted a way to query the Airport Extreme for its external IP address and dynamically update a host entry on my [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify;">My home network has an Apple Airport Extreme as the first stop from my cable modem, which of course provides dynamic addressing, and I run my own BIND DNS server on the Internet. I wanted a way to query the Airport Extreme for its external IP address and dynamically update a host entry on my Internet DNS server so that I could access my home network while away. I used to subscribe to a service called DynDNS (there are others as well) but I prefer to be in control for this scenario. The BIND setup is easy: I just created a TSIG key and allowed the zone that contains my home network's host address to accept dynamic updates using that key. There are several examples of this on the web.<br />
<span id="more-19"></span><br />
However, the Airport Extreme provided no clear way of retrieving the external IP address. The simplest solution appeared to be using SNMP to query the device for network information and pick out the external interface. Unfortunately, the SNMP data provided by the Airport Extreme does not seem to follow specifications and the interface indices don't match up correctly between different sections. But, since the external IP must be routable, and all others on the network should not be, it was a simple matter to filter out all the non-routable addresses and keep the one that is routable. Below is the script I use to carry out the query and the update.</p>
<pre style="text-align: justify;">!/bin/sh

SERVER="ns.example.net"
ZONE="example.net"
HOST="home.example.net"
KEYNAME="key-name"
KEYSECRET="key-secret"

ROUTER="airport_extreme"
COMMUNITY="string"

OLDIP=`dig @"$SERVER" "$HOST" A +short`
NEWIP=`snmpwalk -c "$COMMUNITY" "$ROUTER" ipAdEntAddr | awk '{print $NF}' | egrep -v "^127\\.0\\.0\\." | egrep -v "^169\\.254\\." | egrep -v "^10\\." | egrep -v "^172\\.1[6-9]\\.|^172\\.2[0-9]\\.|^172\\.3[0-1]\\." | egrep -v "^192\\.168\\."`

if [ -z "$NEWIP" ]; then
        echo The commands did not return an IP address.
        exit 1
fi

if [ "$OLDIP" != "$NEWIP" ]; then
        echo Old IP address: "$OLDIP"
        echo New IP address: "$NEWIP"
        (
                echo server "$SERVER"
                echo zone "$ZONE"
                echo update delete "$HOST" A
                echo update add "$HOST" 3600 A "$NEWIP"
                echo key "$KEYNAME" "$KEYSECRET"
                echo send
        ) |\
        nsupdate -d
fi</pre>
<p style="text-align: justify;">Using regular expressions, the SNMP query commands simply egrep out all the interface addresses that could not possibly be externally facing, then the script uses nsupdate to send the information to the DNS server. I run this from a cron job every hour, and whenever there's a change of IP address, output is e-mailed to me. Although I haven't tested it, I believe the Airport Express also has SNMP capabilities and this script/setup should work just as well with that device as with the Airport Extreme.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.islandjohn.com/2009/10/03/dynamic-dns-updates-with-bind-and-an-airport-extreme/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mail.app with a Self-Signed Certificate in postfix/dovecot</title>
		<link>http://www.islandjohn.com/2009/09/16/mailapp-with-a-self-signed-certificate-in-postfixdovecot/</link>
		<comments>http://www.islandjohn.com/2009/09/16/mailapp-with-a-self-signed-certificate-in-postfixdovecot/#comments</comments>
		<pubDate>Wed, 16 Sep 2009 04:00:53 +0000</pubDate>
		<dc:creator>janos</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[Debian]]></category>
		<category><![CDATA[dovecot]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Mail]]></category>
		<category><![CDATA[OS X]]></category>
		<category><![CDATA[postfix]]></category>

		<guid isPermaLink="false">http://www.islandjohn.com/wp/?p=18</guid>
		<description><![CDATA[I thought I'd post this tidbit about getting Mail.app to work correctly with a self-signed certificate in a postfix/dovecot Linux installation; in my case under Debian Lenny. After setting this up, my Mail.app refused to connect to the outgoing server to deliver mail. In the postfix logs I would see "SSL_accept error from ...: -1" [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify;">I thought I'd post this tidbit about getting Mail.app to work correctly with a self-signed certificate in a postfix/dovecot Linux installation; in my case under Debian Lenny. After setting this up, my Mail.app refused to connect to the outgoing server to deliver mail. In the postfix logs I would see "SSL_accept error from ...: -1" messages. The problem ended up being that postfix uses the default "snakeoil" self-signed certificate, while dovecot creates its own. If the IMAP and SMTP hosts are the same as they were in my case, when you accept the dovecot certificate upon the first IMAP connection, the SMTP connection with a different certificate will fail. This is because after the accept there is now a known certificate for that host, and the new certificate presented by postfix will not match. To correct the problem, either use different hosts (host names) for IMAP and SMTP, or use the same (perhaps the "snakeoil") certificate in both, the postfix and dovecot, configurations.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.islandjohn.com/2009/09/16/mailapp-with-a-self-signed-certificate-in-postfixdovecot/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Connecting to an SQLite Database via ODBC on OS X</title>
		<link>http://www.islandjohn.com/2009/02/13/connecting-to-an-sqlite-database-via-odbc-on-os-x/</link>
		<comments>http://www.islandjohn.com/2009/02/13/connecting-to-an-sqlite-database-via-odbc-on-os-x/#comments</comments>
		<pubDate>Fri, 13 Feb 2009 04:00:30 +0000</pubDate>
		<dc:creator>janos</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[ODBC]]></category>
		<category><![CDATA[OS X]]></category>
		<category><![CDATA[SQLite]]></category>

		<guid isPermaLink="false">http://www.islandjohn.com/wp/?p=17</guid>
		<description><![CDATA[I'm working on a modifying a PHP gallery application to support tagging using SQLite as the database back-end. I've searched for a way to edit and view the database via some graphical tool, and while there are some out there, I wanted to be able to use something generic, like SQuirreL SQL or OpenOffice; thus [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify;">I'm working on a modifying a PHP gallery application to support tagging using SQLite as the database back-end. I've searched for a way to edit and view the database via some graphical tool, and while there are some out there, I wanted to be able to use something generic, like SQuirreL SQL or OpenOffice; thus the need for configuring ODBC.<br />
<span id="more-17"></span><br />
SQLite and iODBC are bundled with OS X, so all we need is an SQLite ODBC driver, and a way to configure the connection. Download the SQLite ODBC Driver (http://www.ch-werner.de/sqliteodbc/) and compile it from a Terminal as per the instructions, but first set some compiler environment variables (you may not need all, but all can't hurt) so that you get universal binaries:</p>
<pre style="text-align: justify;">export CCFLAGS='-arch ppc -arch ppc64 -arch i386 -arch x86_64 -g -Os -pipe'
export CFLAGS='-arch ppc -arch ppc64 -arch i386 -arch x86_64 -g -Os -pipe -no-cppprecomp'
export CXXFLAGS='-arch ppc -arch ppc64 -arch i386 -arch x86_64 -g -Os -pipe'
export LDFLAGS='-arch ppc -arch ppc64 -arch i386 -arch x86_64 -bind_at_load'
export MACOSX_DEPLOYMENT_TARGET=10.5</pre>
<p style="text-align: justify;">If the configuration and compilation all went well, the libraries should now be in /usr/local/lib, and we can configure the ODBC driver. Launch ODBC Administrator (located in /Applications/Utilities) then select the Drivers tab and click Add. You can enter whatever you like for the description, something like SQLite ODBC Driver, then choose or enter /usr/local/lib/libsqlite3odbc.dylib for both the Driver file and Setup file. Click Ok to complete the driver configuration.</p>
<p style="text-align: justify;">We now need to configure a database source, and for this I'll assume you already have an SQLite database file named /tmp/test.db. Select the User DSN tab, click Add and select the SQLite ODBC Driver that we just created. Then, enter whatever you like for the Data Source Name (DSN), maybe Test, and anything you want for the Description. To provide the name of the database file we need to add a field with the keyword Database and the value of /tmp/test.db. Clicking Add will provide you with a dummy Key and Value entry that you can then modify by clicking on the each cell individually. Modify Key to Database and Value to the path of the database file, in this example /tmp/test.db. Save the changes by clicking Ok and then Apply.</p>
<p style="text-align: justify;">These steps created the driver and the source for the current user. To create this setup as a system-wide configuration, unlock the ODBC Administrator before you start the configuration. Then, when creating the driver, select System for the Define as option, and create the source under the System DSN tab. The configuration will be created in /Library/ODBC instead of your user directory.</p>
<p style="text-align: justify;">To test the results, open an SQL client that supports ODBC, and you should see Test as an available data source. OpenOffice Database will let you view the data, but not modify it, but for testing purposes this should be convincing enough.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.islandjohn.com/2009/02/13/connecting-to-an-sqlite-database-via-odbc-on-os-x/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Why Does Finder Automatically Launch smbclient?</title>
		<link>http://www.islandjohn.com/2008/12/27/why-does-finder-automatically-launch-smbclient/</link>
		<comments>http://www.islandjohn.com/2008/12/27/why-does-finder-automatically-launch-smbclient/#comments</comments>
		<pubDate>Sat, 27 Dec 2008 04:00:00 +0000</pubDate>
		<dc:creator>janos</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[Finder]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[OS X]]></category>
		<category><![CDATA[smbclient]]></category>

		<guid isPermaLink="false">http://www.islandjohn.com/wp/?p=16</guid>
		<description><![CDATA[I was sitting in a hotel room using my MacBook Pro and all of sudden I received a Little Snitch alert asking me to allow smbclient to connect to some IP address. Of course, I didn't allow it, but it peaked my interested. Why the request? I started digging. Examining the smbclient process revealed that [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify;">I was sitting in a hotel room using my MacBook Pro and all of sudden I received a Little Snitch alert asking me to allow smbclient to connect to some IP address. Of course, I didn't allow it, but it peaked my interested. Why the request? I started digging.<br />
<span id="more-16"></span><br />
Examining the smbclient process revealed that it was started by Finder, but this was not a host that I ever connected to before, so it wasn't some history issue. Also, there was no host listening at that address, and that host wasn't even on this network (the host had some 192.168 address but locally I was on a 10 addressed network.) Searching through every file on the system for that IP address lead nowhere.</p>
<p style="text-align: justify;">After some head scratching, I was able to reproduce the problem by restarting Finder. Every time Finder started, I would get a warning within a few seconds; at least this was a consistent behavior. So what now? How do I see what is happening? While Activity Monitor is a good application to use for quick process snapshots, it doesn't provide enough debugging capability to see what a process may have done in the past, but dtrace does.</p>
<p style="text-align: justify;">Running "dtrace" on Finder, displaying every system call entry, showed that prior to launching smbclient another process is invoked: nmblookup. This is a good clue. If you read the man page and look at the command's options, this behavior should start to make sense. I ran "nmblookup -M -- -" and it returned none other than the questionable IP address; mystery solved: Finder appears to launch nmblookup to search for master browsers as part of normal discovery, and if it finds one, it tries to connect to it.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.islandjohn.com/2008/12/27/why-does-finder-automatically-launch-smbclient/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

