Brad Dominy

Selected Work

The following are projects I have written and designed, most of which are based on Cocoa for MacOSX. I have also written AppleScripts and used other languages like Python, PHP, Perl, C, and Java.


We use Cisco IP phones which respond to xml commands, including one to initiate a dial, so I created Dial to better integrate the phones with our daily work flow. Bill back is a tough area, mostly because of users not taking the time to enter in the proper information. While our phone system had the capacity to do bill back, no one ever took the time to enter in a long string of digits in the proper format in order to charge a call to a client. Dial makes this process easy. It remembers the most recently used matter numbers and associates the last matter number used when dialing a phone number to automatically populate the matter number field. When you dial, it takes care of everything for you. Additionally, it maintains a call log so an attorney can review what calls they made recently if they need help accounting for their hours.

All names and personal info in the above images have been changed to protect the innocent

Dial works with the Address Book to show who's number is being dialed. As you put in a number, it searches for a match and if it finds one, it will show their picture and job information. Speed dial numbers let you keep numbers you need all the time handy and can be dialed quickly with just a double click. Adding a speed dial number is handled by dragging and dropping vCards onto Dial. Phone numbers can be entered directly or they can come in from any application that uses Services. So, if there is a phone number on a web page, you can just select it and using Services it will automatically launch Dial and enter it into the phone number field. This also works from other applications like Address Book, iCal, TextEdit, iChat, Mail, etc.

Contractions Tracker

We attended birthing classes before our daughter was born and they gave us a little workbook with instructions on how to track contractions so that we would know when it was time to head for the hospital. Labor can take a while though, so in order to help me pass the time I wrote this application. I promise I was not sitting by writing code while my wife was in pain. She was actually pretty comfortable and never exceeding a 4 on the intensity scale.

This application is a great example of how CoreData can make things easy. Most of the hard work of handling data is done for me and all I needed to worry about was the logic of the app. On top of that, bindings lets you display your data in a straightforward way. Overall, I think I spent about 2 hours writing this application and then used it for about 6 hours before my wife's water broke.


Our VOIP system works with Cisco IP phones to illuminate a Message Waiting Indicator (MWI) light on the phones whenever a user has a new voicemail. It also allows for the delivery of those voicemails as wav attachments in emails. The only problem was that the system did not know when voicemails had been read and the Message Waiting Indicator (MWI) remained on all the time. This proved to be a distraction for people as they never could trust whether the light meant they really had new voicemail or not.

LightSwitch is a mail bundle which listens for the changing of the message read flag on delivered voicemails and then toggles the MWI light on or off to match. It is deceptively simple. First, mail bundles are not officially allowed by Apple and using them is an at your own risk proposition. However, gaining access to the guts of the Mail app was necessary in order to tie into the system. Second, our VOIP system let you toggle the MWI but only with a telnet session. Finally, the requirements were that it work in the background with zero setup, so it was a pretty tall order.

LightSwitch uses the account information for the voicemail IMAP account to lookup from LDAP a user's phone extension. It uses a technique called "swizzling" to replace a method with one of it's own in the objective-c runtime. This lets you listen in to the signals Mail normally sends internally, including the one when a message read flag is updated. Whenever a voicemail message is read, LightSwitch checks to see how many unread messages there are and if there are none, it starts a telnet session to our VOIP system to turn the MWI light off for that user's extension. It can also turn the light on if you mark a voicemail as unread. It all happens within a couple of seconds so user's are no longer worried about the system getting out of sync.

It installs by just being dropped into a user's Library/Mail/Bundles folder and by updating Mail's preferences to allow for bundles. Lately, Apple has been adding a couple of extra layers of protection to make sure that mail bundles are compatible, so while they are still not officially sanctioned, it looks like they are going to tolerate them for the foreseeable future.


Having up to date contact information for employees is essential for any large company. Apple has focused on Microsoft's Active Directory and their own Open Directory as a solution for this, but, in our case, these were not options. We also wanted to have more control over how the information was presented with custom labels and to show relationships between employees like having an attorney's secretary listed on their card. To bridge this gap, I created ABSync - essentially a one way sync client.

The first challenge was to clean up our LDAP server and bring it into compliance with Apple's LDAP schema. Our employee list had been designed to be accessed via a browser on our intranet. This meant a lot of the information was spread out in different databases with different owners, and the data was accessed directly thru cgis. We had a LDAP server as a part of our email server, but it had never been utilized for much more than holding email addresses. Once we loaded the Apple LDAP schema, we were able to begin populating it with data from all those different sources, including phone numbers, addresses, map information, photos, dates, and relationships.

All names and personal info in the above images have been changed to protect the innocent

The second challenge was to bring that information into Address Book. In our environment, we needed a way to let people sync this information when they are working on our internal network. It had to be relatively quick and work in the background and be pretty much bullet proof as losing contact information to an attorney is a serious offense. Sync Services is a framework that lets you build a sync client and handles a lot of the heavy lifting normally associated with syncing data. You register for various types of sync data, including contact information, and when the client connects, the sync server tells the client what kind of sync to perform and handles passing whatever data has changed since the last sync.

ABSync is a command line application that acts as a one way Sync Services client since the source of our data is read only. ABSync talks to our LDAP server to determine what changes have been made on the server and then generates the appropriate sync changes. I had to run the sync as part of a cycle where any changes made to an employees card was first accepted, and then in a follow up sync returned to the state on the LDAP server. It is not exactly what the Sync Services engineers had in mind, but it actually works pretty well.

The result is an Address Book with an "Office List" group that always contains a list of our active employees. If you make any changes to the data we control (i.e. modifies or deletes of the group, group membership, or information on an employee's card) it is automatically reverted. Any additional information you add like notes is not affected.


Our IT department has a large wall mounted monitor that we use to keep tabs on various systems. Kiosk is a screen saver that uses plugins to generate views which are then displayed randomly or in round robin fashion. It uses some nice cross fade effects and lets you define how long each view is shown. Views are dynamically generated so they can be continuously updated with fresh information throughout the day.

We have plugins that show network status, the status or backup, and our department's calendar. It is a good way to alert people of a problem as anyone passing by may see an issue and can bring it to the right person's attention. It is also very stable and has run for well over a year without any intervention.


A difficult task within any organization is the backing up of client machines. We have over 300 macs which need daily backups, so I created Backup to address this problem. Essentially, it is a front end to rsync, but it handles the scheduling, authenticating, selection of items to backup, and reporting in a way that a simple script could not.

The Backup System Preference sets which folders in a user's home directory get backed up and when the daily backup occurs. The destination is any server on which the user has an ssh account, which in our environment is a XServe for their floor or office. The Advanced button brings down a panel which lets you configure login information for the destination server, options passed to rsync or other unix tools, exclusions, message formats, and logging. The user's password is stored in the user's KeyChain to provide protection. It also provides realtime viewing of the backup log file while a backup is running and displays status messages to the user letting them know when the last successful backup occurred or if there were any errors.

The command line tool lives inside the Backup System Preference so the whole thing can be installed by just dragging and dropping. The command line tool uses the expect command to pass along the user's password fetched from their KeyChain and to add the server to the client machine's known_host file. This avoids having to use public key authentication between the client machines and the servers. The command line tool monitors the output from the rsync process and collects information that is sent to a Backup Status Server when the backup completes. Backup log files are automatically rotated and additional messages are logged to the system log.

Overall, Backup allows for easy setup with not much more than a server, username and password, but it allows for lots of customization and provides feedback to both the user and to the central support personnel.

Backup Status Server

Backup Status Server creates a central place to log the status of over 300 user's backups using my Backup system. It is basically a web server that listens for http requests and processes input as if from an html form. Each backup client sends along information like user information, backup destination, client information, backup size, duration, etc. The Backup Status Server uses CoreData to manage all of that data. When a report is made, a new user is automatically created if not found, so registering a user is very simple - just run a backup! From then on a record of each backup made for that user will be kept.

All names and personal info in the above images have been changed to protect the innocent

An important aspect of backup is detecting when a backup is not working. Backup Status Server checks nightly to see if any of the registered users have not reported in. If they have not been seen in 1 day, they are listed as overdue. If they have not been seen in more than 5 days, they are listed as missing. This creates a nice filter for the support personnel as they will only see support requests generated for backups with errors or those that are missing, and it is easy to determine whether there is a real problem or if the user is just out of the office. There are also settings to change what port the server uses and to adjust how long to keep backup records.

The Backup Status Server also responds to requests from a normal web browser. It will generate a table of all the current backups and their status or you can look at a specific user's backup history. I use this function to generate a graphical representation of the state of backup for our users which is displayed on a wall mounted monitor in our IT department as part of my Kiosk project.


Before moving to iPhones, we used Treos with the SprintPCS network as our mobile phone platform. One feature of the Treos was tethering to a laptop to give network access while out of the office. The only problem was that the connection would time out quickly and have to be re-established taking several minutes each time. Our CIO got so fed up with this annoying problem that he asked me to come up with a solution.

So, I wrote pppalive which uses the SystemConfiguration framework to monitor the state of ppp connections. When connected to SprintPCS it would either send out a ICMP ping packet or request a web page from our corporate website, which gave us the added benefit of monitoring usage. We used launchd to keep the pppalive process running automatically. Best of all, there was no interaction needed for it to work so all a user had to do was start their connection and it would continue for as long as they wanted.

Chapman PDE

Law firms go thru lots of paper which costs a small fortune every year. I was asked to write a Printer Dialog Extension for the MacOSX printing system to let users specify a matter number that would be passed to our high volume printers and then processed by the billing department to help recoup printing costs. It works by registering a view to be displayed in the print dialog. The view has a simple combo box for entering a matter number, but it also uses the low level preferences system to store the most recent matter numbers. When a matter number is entered, it is passed to the CUPS system in a print ticket where another custom filter, written in C, extracts the matter number and then injects it into the raw postscript.

Our high volume printers would process the print jobs and the inserted postscript with the matter number would cause the printer to log that print job along with other information like number of pages printed, document name, and requesting user to a log file. The billing department would then fetch those print logs and process them for billing nightly. I also wrote the scripts for fetching the printer log files.

This was a pretty good solution and allowed the law firm to recoup quite a bit.

About me

Brad Dominy


By Language

By Frameworks