Written: June 11th, 2007, 1:08 (UTC) By: omer 3 comments
Another development from over the past few days is my first application that interacts with the Mac OS X Address Book. It is available here. Basically, all it does is tell you how many people are in your Mac OS X address book and lists their names. It currently can only handle ASCII values (just so that it can be easily printed to the terminal), and it's an entirely terminal-based application, but it is a first step for interacting with the Address Book. And, perhaps more importantly, it is a first step using the Address Book Carbon API (Carbon is what OOo uses) rather than the Cocoa API. Meaning: it should be possible to integrate the Address Book using Carbon and C (both supported by OOo) rather than Cocoa and Objective-C (which are not). Enjoy!
File: abnames.tar
API clarification
Written: June 12th, 2007, 19:27 (UTC) By: Florian Heckl [e-mail: florian@florian-heckl.de] permalink
I should clarify here that "The Address Book framework consists of two APIs: one for C, the other for Objective-C." (see http://developer.apple.com/documentation/UserExperience/Conceptual/AddressBook/index.html), rather than Carbon / Cocoa API. You are of course right in that Carbon uses plain C while Cocoa uses Objective-C.
corrected version of abnames
Written: June 12th, 2007, 20:14 (UTC) By: Florian Heckl [e-mail: florian@florian-heckl.de] permalink
Well, your code crashed with my address book. So I played around a little and can offer you the following:
/******
*
* Test Carbon Program -- print all first and last names from Address
* Book (in ASCII).
*
******/
/* Include */
#include <stdio.h>
#include <string.h>
#include <Carbon/Carbon.h>
#include <AddressBook/ABAddressBookC.h>
int main(int argc, char *argv[])
{
int i, numPeople;
CFStringRef firstNameCFString, lastNameCFString;
char *lastNameString, *firstNameString;
/* Get the address book and everyone inside of it */
ABAddressBookRef AB = ABGetSharedAddressBook();
CFArrayRef all = ABCopyArrayOfAllPeople(AB);
/* This is used to turn a CFArrayRef into a C array */
numPeople = (int) CFArrayGetCount(all);
//CFRange range = {0,numPeople};
//const ABPersonRef **everyone;
//CFArrayGetValues(all,range,(const void **) everyone);
/* Print the number of people... (why not?) */
printf("Number of people in address book: %dn", numPeople);
/* Go through the array... */
for(i = 0; i < numPeople; i++)
{
/* First, get the names out of this ABPerson */
ABRecordRef person = (ABPersonRef) CFArrayGetValueAtIndex(all, i);
firstNameCFString = (CFStringRef) ABRecordCopyValue((ABRecordRef) person, kABFirstNameProperty);
lastNameCFString = (CFStringRef) ABRecordCopyValue((ABRecordRef) person, kABLastNameProperty);
/* The names are extracted as "CFStringRef"s, so this gives us a
* char * version, for printing. Notice that we have to give an
* encoding type. I used ASCII for the quick test. I also gave
* a lot more space than I needed to with malloc. I don't know why
* yet, but giving the length itself in malloc and then in
* CFStringGetCString makes firstNameString and lastNameString both
* blank. So, until I figure out why (if I ever need to), I gave
* them some padding.
*/
static char* fallback = "<null>";
int fbLength = strlen(fallback);
int firstNameLength = fbLength;
bool firstNameFallback = true;
int lastNameLength = fbLength;
bool lastNameFallback = true;
if (firstNameCFString != NULL) {
firstNameLength = (int) CFStringGetLength(firstNameCFString);
firstNameFallback = false;
}
if (lastNameCFString != NULL) {
lastNameLength = (int) CFStringGetLength(lastNameCFString);
lastNameFallback = false;
}
//fallback again
if (firstNameLength == 0) {
firstNameLength = fbLength;
firstNameFallback = true;
}
if (lastNameLength == 0) {
lastNameLength = fbLength;
lastNameFallback = true;
}
firstNameString = malloc(sizeof(char)*(firstNameLength+1));
lastNameString = malloc(sizeof(char)*(lastNameLength+1));
if (firstNameFallback == true) {
strcpy(firstNameString, fallback);
} else {
CFStringGetCString(firstNameCFString, firstNameString, 10*CFStringGetLength(firstNameCFString), kCFStringEncodingASCII);
}
if (lastNameFallback == true) {
strcpy(lastNameString, fallback);
} else {
CFStringGetCString(lastNameCFString, lastNameString, 10*CFStringGetLength(lastNameCFString), kCFStringEncodingASCII);
}
/* Print them out... */
printf("%s %sn",firstNameString, lastNameString);
/* Free our variables */
if (firstNameCFString != NULL) {
CFRelease(firstNameCFString);
}
if (lastNameCFString != NULL) {
CFRelease(lastNameCFString);
}
free(firstNameString);
free(lastNameString);
} // end of for loop
CFRelease(all);
return 0;
} // end of main function
Thanks
Written: June 14th, 2007, 20:07 (UTC) By: omer [www] [e-mail: omer [dot] baror (at) gmail [dot] com] permalink
Thanks for the fixes, Florian! I hadn't tested with null/empty names. The error came up for me later when attempting to print properties other than first and last names. I'm posting a new version of the program now, one that prints all properties for all people in the address book. Let me know what you think (and if it crashes too)!