Well, that was quick. A few of the people waiting for Tiger compatibility were sorely disappointed by iCAR 0.8. Instead of crashing when a message was received, iChat (with iCAR installed) became entirely non-functional at startup. The buddy list would not appear, menu items would do nothing, and, perhaps most worryingly, the application menu (the one titled “iChat”) would not even appear.

This happened, however, to a minority of users. iCAR worked perfectly under fresh installations of Mac OS X and iChat, but failed because of some vestige of the previous installation.

Hm, I said to myself, stroking my jutting chin dramatically and narrowing my aging eyes. This sounds eerily familiar.

The help of faithful user Shamir came to my rescue in this singular case. Using copies of his iChat preference property list and an inductive technique that I’ve come to call “change a working installation into a broken installation in little increments until it becomes broken itself”, I identified the offending entry in some users’ com.apple.iChat.plist.

Although I pretended to be startled and even a bit alarmed for the benefit of the swarm of reporters I had by then attracted, I had had a nagging suspicion, almost an intuitive certainty, all along that I would find the root of my troubles in NSToolbar Configuration NSPreferences.

Aside from that it exposed my striking similarity to certain Doylian (which I am certain is the incorrect word) characters, the problem is actually rather interesting and might crop up again for me or someone else, so I’ve decided to write it up here.

Under Panther, a strange problem cropped up that, for some users, would cause the iCAR “Auto-Reply” preference pane to be missing from iChat’s “Preferences” window. Many sleepless nights pointed me toward a strange default in the iChat preference property list of some users:

<key>NSToolbar Configuration NSPreferences</key>
<dict>
    <key>TB Display Mode</key>
    <integer>1</integer>
    <key>TB Icon Size Mode</key>
    <integer>1</integer>
    <key>TB Is Shown</key>
    <integer>1</integer>
    <key>TB Item Identifiers</key>
    <array>
        <string>General</string>
        <string>Accounts</string>
        <string>Messages</string>
        <string>Alerts</string>
        <string>Privacy</string>
        <string>Video</string>
    </array>
    <key>TB Size Mode</key>
    <integer>1</integer>
</dict>

(How or when this preference was created still eludes me.)

In particular, the TB Item Identifiers array was to blame. It defined which preference panes would be displayed in the iChat preferences toolbar. “Auto-Reply”, of course, is not on the list. So, without even consulting NSPreferences, the NSToolbar instance would refuse to display the button that could display a quite dormant iCAR preference pane.

Diabolical.

My solution to this was to hijack the standardUserDefaults class method of NSUserDefaults using poseAsClass:. Whenever anything requested access to the preferences of iChat, iCAR would fetch the standard instance, remove the TB Item Identifiers entry, and pass it along as if it were an accurate reflection of the property list stored on disk.

Equally, if not more, diabolical.

This came around to bite me when users who upgraded to Tiger still had this preference. Something changed in the handling of NSUserDefaults and it was not my or iCAR’s place to tinkering around at its lowest levels. Essentially, I ended up returning a useless value whenever anything needed the standardUserDefaults, which wreaked all manner of unseemly havoc on the running instance of iChat.

Fortunately, it looks like Tiger entirely ignores the TB Item Identifiers entry when dealing with NSPreferences. The old bug suddenly vanished, so the fix for the new bug becomes the happy ending of this tale: I just deleted the two files that implemented the NSUserDefaults hack.

Please excuse the inexcusable gibberish above. I did not intend to put you through it. It might be said that it just poured out.

Regardless, iCAR 0.8.1 — which was fixed only by deleting code — is very available. Binary, source.

I have at long last gotten off my lazy tuchis and updated iCAR to be compatible with Tiger and iChat 3.0. I would like to take this opportunity to apologize publicly to the world as a whole for taking as long as I did. Please do not eat my brains.

obsolescence strikes

Of most pressing note, of course, is that iCAR has suddenly become much less useful. iChat 3.0 now incorporates rudimentary auto-reply functionality. In some respects, you might say that iCAR has gone the way of the Watson, but in truth, this story is not nearly as dramatic as Watson’s or Konfabulator’s. There is, namely, zero lost revenue here. I have decided, however quixotically, that I will continue to maintain and add features to iCAR despite its semi-uselessness because it can do some pretty neat stuff and also out of pride.

Changes

Essentially, release 0.8 of iCAR really only does one thing: it is the Tiger version of iCAR. Under the hood, however, some positively riveting things happened to the code:

  • The preference pane was widened to match iChat 3’s panes.
  • iChat.h was updated to match iChat 3 and the new InstantMessage.framework.
  • I refactored message-capturing to match iChat 3’s new structure.
    • Instead of IMService, I now interface with the new Service class.
    • Chats are no longer automatically accepted because they don’t have to be (see “Observations”, below).
    • I removed unnecessary mechanism for delaying past chat acceptance (again, see “Observations”).
  • Another unneccesary mechanism, this one for accessing status, was removed (the curious, repetitive, and truly nerdy would benefit from another glance below at “Observations”).

Observations

  • iChat 3 removes a long-standing annoyance. Previous versions could not send messages if chats were not yet accepted (or, even more infuriatingly, if they were in the process of animating their acceptance). This means that replies are now sent faster, iCAR’s code is much less complex and much prettier, and the software will probably break for fewer people.
  • All of the IMService code I patched was apparently moved into the Service class (even the method signatures I hijack are identical). IMService still exists, but it seems to be greatly simplified, presumably because InstantMessage.framework is now a public framework. It provides a nominal interface for interacting with the status values and messages of iChat (really, iChatAgent.app, the protocol daemon). I initially had trouble patching Service using poseAsClass:, so I eventually elected to use the method swizzling technique well-documented by Mike Solomon of PithHelmet (Greasemonkey for Safari, sort of) fame.
  • I don’t know if this appeared in IMService at any point in the past, but Service has the class methods +myStatus and +myStatusMessage for obtaining global settings about status. Previously, I was hacking a method into the buddy list window controller to get the status. With iCAR 0.8, I had the satisfaction of deleting that pair of files.

Questions

Because iChat 3.0 incorporates basic auto-reply functionality, a iCAR is having a bit of an identity crisis. I’m fairly certain it should stick around, but I am wondering a bit about its role.

  • Should it still be called the iChat Auto-Reply? It’s definitely no longer the
  • I should probably stop calling it a “simple” auto-reply feature. (Apologies; that was actually not a question.)
  • Should the preference pane and “Enable…” check box continue to use the name “auto-reply”? Now that there are two auto-reply functions in iChat (with iCAR installed), perhaps the term is too generic.

The future

It seems that I will never be short of new features to implement into the next next version of iCAR.

  • Demand has increased recently for iCAR to play nicer with the style settings in iChat. That will be Real Soon Now.
  • Also sorely lacking is the passage of variables to AppleScripts (variables are currently only passed to shell scripts using environment variables). This needs to happen right-quick.
  • Does iChat’s built-in auto-reply functionality set the “this is an auto-reply” flag when it sends its message to the AIM server? If so, can I hijack that in the name of nearly-worthless iCAR progress?

Get it/got it/good

Hurry up and download. Or perhaps you’d like the source.

Because I’m beginning to work on iCAR again (finally), I was inspired to go looking for alternative ways to load its code into iChat (it currently uses SIMBL, which is excellent, but I’d prefer not to have to install anything more than the iCAR bundle and it seems like there would be a simple interface for this sort of thing).

I encountered the following options during my research.

  • Unsanity’s Application Enhancer (APE), the best-marketed and most popular method. Daemon-based (aped). Makes me irrationally nervous in general. The SDK has a wildly restrictive license: “The Application Enhancer license is not compatible with GNU style licenses (GPL/LGPL).”
  • Zaius, a free (Mozilla Public License) alternative to APE, also daemon-based. Attractive, but I’m not entirely in favor of asking users to install interfaces like this.
  • Input Managers, manifested as the magical Library folder where bundles get loaded into every application. Intended to be for implementations of NSInputManager, but has no restriction on what code can be executed. According to Mike Solomon (author of SIMBL and PithHelmet), these bundles can have troubles selecting the application to load into.
    • SIMBL (the aptly named Simple Input Manager Bundle Loader) is Mike Solomon’s solution to instabilities with the Input Managers method. It handles the verification of application identifiers and loads bundles selectively. Yet another required external installation, but resides in only one relatively innocuous directory and doesn’t require a logout or reboot.
  • Ed Wynne’s libpatch, an aging system for dynamically loading code into Cocoa applications. Breaks more and more with each release of the OS. Virtually nonexistent these days.
  • Mach calls, including the methods in mach_inject and mach_override, which are best explained in a paper by Jonathan Rentzsch. These require that a running process invoke the calls to the kernel, which means one would need to write a daemon to monitor launches of target applications if one’s override has no external, executable component.

Thus, it seems that I’ll stick with SIMBL until Apple does something drastic. My only real problem with this is that I’ll need to continue distributing two files in my iCAR downloads, but that really isn’t too much of an inconvenience. We have nothing in our pockets. We continue.

Well, we thought we had gotten them out, but history and logic should have shown us that bugs never die completely.

Several gracious iCAR 0.6 users have pointed out that it still displays a crashing bug in some cases when a new-message window needs to be opened. This bug varied hugely in intensity between people with seemingly similar setups.

Dutiful user Seth narrowed this down a great degree — it appears that these crashes manifested only when he had turned on spoken notifications of new messages.

This jives well with some earlier discoveries I’d made when the iChat AV beta first displayed this particular kind of bug, prompting a complete reorganization of part of iCAR. It appears that iChat really doesn’t like to send messages before a “chat” (which is really just an exchange of messages) has been accepted. I haven’t been able to be any more specific than that, mostly because of the mystery inherent in writing patches for closed-source apps.

The previous solution to this problem had been a miniscule delay between receipt of an incoming message and sending of an outgoing one. I think the course of action at this point, though, may be to attempt to find a trigger within iChat that will indicate when a reply can be safely sent.

It is at this point in this entry that I begin to wonder why in the world I am blogging this. Oh, world.

In any case, that’s where I am in iCAR 0.7’s development, and that’s where I’ll remain until the proverbial bovines return to their place of domicile.

So, I’ve gotten off my lazy tochis and released what I’d like to call the most anticipated release in the history of iCAR. (For those unfortunate souls not in the know, iCAR is the iChat Auto-Reply.) This history is admittedly short, but I do not lie when I say that I’ve received more dismayed/inquiring/angry emails and support requests regarding iCAR’s Panther compatibility than any other single bug in the history of my public programming experience.

It would be good to note that this release not been tested for an instant under Jaguar with the iChat AV beta. Beyond this uncertainty, I have substantial reason to believe that it will in fact not work under Jaguar. It will most definitely not work with iChat 1.0 (don’t even try). For the AV beta on Jaguar, use 0.5; for iChat 1.0, use 0.4.

The changes, then:

  • AppleScript and Unix errors are reported more visibly
  • AppleScript path and Unix command retain values more effectively
  • preview of manual reply in preference pane
  • auto-reply window is now a utility panel
  • AppleScript path and Unix command take effect immediately after browsing
  • removed menu item (if you really miss this, email me and I’ll bring it back)
  • more tokens are parsed (%f, %l, %s)
  • manual reply string is now saved with attributes (style)
  • more environment variables (iCAR_status, iCAR_statusmessage, iCAR_timingmode)
  • no reply is sent if iChat is set to the default available status (that is, “Available”)
  • compiled for Panther — fixes many crasher bugs on 10.3, probably will not work on Jaguar
  • support for iChat 1.0 removed

My to-do list is in the Readme if you’re really that interested.

iCAR elsewhere: Pygmy Software, SourceForge, Freshmeat, MacUpdate, VersionTracker, MacShareware.

Finally, please allow me to plug my donation page again. I do a lot of work on software like iCAR, and I do it all for free, but I’m sure you can imagine the glowing feeling I get inside when someone appreciates my work enough to buy me a drink. Now that I mention it, I think only one user has donated for iCAR so far, so etch your name into the bathroom wall of history and help open-source Mac software to continue.

This is a story about how my meager code-slinging attempts got publicity on a blog known as nothing less than 90% Crud.

I was alerted via my information addiction that this character had put an DRMed iTunes Music Store AAC song up for sale on eBay, and was driven to check out his blog, if only because of its intriguing name. Lo and behold, as I scrolled through his recent posts, I found a quick mention of iCAR.

If one word were to sum up my emotions at that moment: woohoo!

Thanks for mentioning my project, George, even if it has been indirectly classified as nine-tenths catchpenny.