2 * contact-update (c) Andrew Flegg 2009
3 * ~~~~~~~~~~~~~~ Released under the Artistic Licence.
5 * A very quick and dirty program to modify an EDS contact's photo and
6 * birthday. This is necessary because evolution-python only exposes the two
7 * structs GBoxed, which cannot be created or manipulated in Python (AFAICT).
9 * Error handling: limited
10 * Syntax: contact-update <name> --photo <mime-type> <file>
11 * contact-update <name> --birthday <year> <month> <day>
13 #include <libebook/e-book.h>
14 #include <libebook/e-contact.h>
19 #include <sys/types.h>
22 // gcc -o contact-update -std=c99 `pkg-config --cflags --libs libebook-1.2 glib-2.0` contact-update.c
28 * Simple error handling.
30 * @param result Result of an expression. If false, <var>message</var> will be shown
31 * and the process terminated.
32 * @param message Message to display if <var>result</var> is false.
34 void* try(gboolean result, char* message) {
36 fprintf(stderr, "Error %s: %s\n", message, error ? error->message : "");
43 * Load a photo from disk into an EContactPhoto record.
45 * @param mime_type MIME type to store in the photo record.
46 * @param filename Filename on disk to load.
48 EContactPhoto load_photo(char* mime_type, char* filename) {
50 stat(filename, &stbuf);
51 char* photo_data = malloc(stbuf.st_size);
52 try(photo_data != NULL, "allocating memory for photo");
53 FILE *file = fopen(filename, "r");
54 try(file != NULL, "opening file");
56 char* current = photo_data;
57 while ((read = fread(current, 1, stbuf.st_size, file)) > 0) {
63 photo.type = E_CONTACT_PHOTO_TYPE_INLINED;
64 photo.data.inlined.mime_type = mime_type;
65 photo.data.inlined.length = stbuf.st_size;
66 photo.data.inlined.data = photo_data;
73 * Create a date record corresponding to the given strings.
75 * @param year Character representation of the year.
76 * @param month Character representation of the month.
77 * @param day Character representation of the day.
79 EContactDate read_date(char* year, char* month, char* day) {
81 date.year = atoi(year);
82 date.month = atoi(month);
89 * Main entry point: do the work of updating matched records.
91 int main(int argc, char* argv[]) {
94 try(argc > 2, "\nsyntax: <name> --photo <mime-type> <file>\n <name> --birthday <year> <month> <day>");
96 // -- Data structures we'll use later...
101 EContactDate birthday;
102 if (strcmp(argv[2], "--photo") == 0) {
103 try(argc == 5, "syntax: <name> --photo <mime-type> <file>");
104 photo = load_photo(argv[3], argv[4]);
107 } else if (strcmp(argv[2], "--birthday") == 0) {
108 try(argc == 6, "syntax: <name> --birthday <year> <month> <day>");
109 birthday = read_date(argv[3], argv[4], argv[5]);
113 try(1 == 0, "\nsyntax: <name> --photo <mime-type> <file>\n <name> --birthday <year> <month> <day>");
116 // -- Open the address book...
118 EBook *book = e_book_new_system_addressbook(&error);
119 try(book != NULL, "finding address book");
120 try(e_book_open(book, FALSE, &error), "opening address book");
121 try(e_book_is_writable(book), "book is writable");
123 // -- Find the list of contacts...
125 GList *contacts = NULL;
126 EBookQuery *query = e_book_query_field_test(E_CONTACT_FULL_NAME, E_BOOK_QUERY_IS, argv[1]);
127 try(e_book_get_contacts(book, query, &contacts, &error), "listing contacts");
128 e_book_query_unref(query);
130 // -- Update the contacts...
133 for (GList* node = g_list_first(contacts); node != NULL; node = g_list_next(node)) {
134 EContact *contact = E_CONTACT(node->data);
135 if (is_photo) e_contact_set(contact, E_CONTACT_PHOTO, &photo);
136 if (is_birthday) e_contact_set(contact, E_CONTACT_BIRTH_DATE, &birthday);
138 if (is_photo || is_birthday) {
139 try(e_book_commit_contact(book, contact, &error), "committing contact");
143 printf("Modified %d records\n", i);