Dialing with the Address Book

I have this thing about dialing phones that goes back 15-20 years. Back then, I worked at a place that kept track of phone calls so clients could be charged for them. You’d have to dial 9, then a 5-digit (or was it 6-digit?) project number—which is how the phone system assigned the charge—then 1 and the area code if necessary, then the number. That makes 17 (or was it 18?) digits for a long distance call. I was using a calculator a lot in those days, and seemed to be unable to get my fingers out of calculator mode when I shifted to the phone. The top and bottom rows of number keys on a phone are the opposite of the top and bottom rows on a calculator, and this was an insurmountable obstacle for me. My most common mistakes were what you’d expect: transposing 1s and 7s, 2s and 8s, and 3s and 9s. This was maddening, especially when I’d get within a few digits of the end of the number and then watch helplessly as my finger hit the wrong key. My coworkers soon learned that a stream of profanity coming from my office meant that I was making a call.

But since I was using HyperCard to manage my contacts, I was able to avoid most dialing entirely. HyperTalk had this wonderful dial function that would either emit DTMF tones or send out the appropriate Hayes commands to the modem. I added a “project number” field to my HyperCard rolodex stack and made up a little function/method/whatever that figured out all the digits that needed to be dialed and then did it. Spectacular!

I now work at a place with a much simpler phone system, but I still like the idea of having my computer do the dialing for me. It keeps the phone numbers for me, it can be connected to a phone line, it should go ahead and do the dialing.

When I came back to the Macintosh after several years of Linux use, HyperCard was gone, and the Address Book wouldn’t dial through the modem (yes, it will dial through many cell phones, but I don’t want to make all my business calls through my cell phone). I tried a few of the dialer programs available and eventually settled on Jon’s Phone Tool. JPT is a fine program, it’s AppleScriptable, it has a Quicksilver plugin, and it adds modem dialing to the Address Book. But it’s also uses what I consider to be far too much memory for a phone dialer—it was always near the top of the Activity Monitor’s list when I sorted applications by Real Memory. So even though I had a program that did what I wanted, I kept looking for something better.

When I found the dialModemOSAX scripting addition, written by Javier Díaz Reinoso, I knew I had what I wanted. It provides just three commands: initModem, dial modem, and hang up. But those are exactly the commands I need. The next couple of posts will describe how I use it.

The OSAX addition that comes with the download was compiled for PowerPC machines. It may well work on Intel Macs, but I didn’t try it. Because Diaz provides the source code with the download, I opened it in Xcode and recompiled it for my Intel iMac. The project file is in an older format, but Xcode updated it and recompiled with no problem.

I then installed the new OSAX file in ~/Library/Scripting Additions. If your computer has two or more users, you’ll have to put it in /Library/Scripting Additions so both have access to it. The scripting addition comes with a sample AppleScript, written by Cecil Esquivel, that adds the ability to dial through the modem to Address Book. The sample script is more appropriate for non-US users than to people here in the States, so I’ve made several modifications. I call my version ABDial.scpt, and it looks like this:

(* Requires DialModemOSAX from Javier Díaz Reinoso 
Javier Diaz-Reinoso <javier_diaz_r@mac.com>
Significant changes to original script
by Dr. Drang <drdrang@gmail.com>
property areaCode : "630"
property longDistance : "1"
property myModem : "/dev/cu.usbmodem"

-- change all letters to digits, strip punctuation,
-- and standardize pauses to ~
on translateNumber(num)
  set pipeline to "echo " & quoted form of num & ¬
    " | tr 'a-z' 'A-Z'" & ¬
    " | tr 'A-Z' '22233344455566677778889999'" & ¬
    " | tr ',' '~'" & ¬
    " | sed 's/[^0-9~]//g'"
  return do shell script pipeline
end translateNumber

-- return the numbers you actually dial
on makeDialable(num)
  set tnum to translateNumber(num)
  -- strip prefix and area code from local numbers
  if length of tnum is 11 ¬
    and characters 1 thru 4 of tnum as string ¬
    is (longDistance & areaCode) then
    set tnum to characters 5 thru 11 of tnum as string
  end if
  -- handle all 10-digit numbers
  if length of tnum is 10 then
    -- strip area code from local numbers
    if characters 1 thru 3 of tnum as string is areaCode then
      set tnum to characters 4 thru 10 of tnum as string
      -- add 1 to long distance numbers
      set tnum to longDistance & tnum
    end if
  end if
  return tnum
end makeDialable

using terms from application "Address Book"
  on action property
    return "phone"
  end action property

  on action title for aPerson with aPhone
    set thephonenum to (value of aPhone) as string
    set thephonenum to makeDialable(thephonenum)
    return "Dial  " & thephonenum & " with modem"
  end action title

  on should enable action for aPerson with aPhone
    return true
  end should enable action

  on perform action for aPerson with aPhone
      do shell script "ps acx | grep 'iTunes$'"
      tell application "iTunes" to pause
    end try
    set thephonenum to (value of aPhone) as string
    set thephonenum to makeDialable(thephonenum)
    initModem myModem with "^MAT&F1E0S7=45S0=0L2^M"
    --was "~^M~AT&F1E0S7=45S0=0L2^M"
    dial modem "ATDT" & thephonenum
    delay 3
    hang up
  end perform action
end using terms from

The path to the modem device file is stored in the myModem property. My iMac has an external Apple USB modem, and the device file is /dev/cu.usbmodem. An internal modem would be /dev/cu.modem.

The translateNumber function uses a Unix pipeline consisting of tr and sed commands to change letters to numbers and strip out most punctuation. Tildes are retained, as dialModemOSAX uses them to indicate 1-second pauses. Because I’m more used to using commas to indicate pauses, one of the commands in the pipeline turns commas into tildes.

The makeDialable function first calls translateNumber to get an all-digits (or all-digits-and-tildes) number, then starts picking the number apart to see what needs to be dialed. Basically, it adds 1 to the front of long distance numbers and strips the area code from local numbers.

The rest of the script follows the rules for making an addition to the phone number popup menus in Address Book. The name of the menu item is created in the action title function, and the actual dialing is done in the perform action function. Three things should be noted in the perform action function:

The script is installed in ~/Library/Address Book Plug-Ins, and the new command is in the popup menu that activates when you click on the description field next to a phone number.

One last note: In the old days, modems had two telephone jacks: one was connected to the jack in the wall, and the other could be connected to your phone. Today, my modem has a single jack, and I use a tee connector to hook both it and my phone to the jack in the wall.