Add v0.0.1 of Hermes from source tarball
[hermes] / package / src / contact-update.c
1 /**
2  * contact-update                          (c) Andrew Flegg 2009
3  * ~~~~~~~~~~~~~~                          Released under the Artistic Licence.
4  *
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).
8  *
9  * Error handling: limited
10  * Syntax: contact-update <name> --photo <mime-type> <file>
11  *         contact-update <name> --birthday <year> <month> <day>
12  */
13 #include <libebook/e-book.h>
14 #include <libebook/e-contact.h>
15 #include <glib.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #include <string.h>
21
22 // gcc -o contact-update -std=c99 `pkg-config --cflags --libs libebook-1.2 glib-2.0` contact-update.c
23
24 GError *error = NULL;
25
26
27 /**
28  * Simple error handling.
29  *
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.
33  */
34 void* try(gboolean result, char* message) {
35         if (!result) {
36                 fprintf(stderr, "Error %s: %s\n", message, error ? error->message : "");
37                 exit(EXIT_FAILURE);
38         }
39 }
40
41
42 /**
43  * Load a photo from disk into an EContactPhoto record.
44  *
45  * @param mime_type MIME type to store in the photo record.
46  * @param filename Filename on disk to load.
47  */
48 EContactPhoto load_photo(char* mime_type, char* filename) {
49         struct stat stbuf;
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");
55         int read;
56         char* current = photo_data;
57         while ((read = fread(current, 1, stbuf.st_size, file)) > 0) {
58           current += read;
59         }
60         fclose(file);
61         
62         EContactPhoto photo;
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;
67         
68         return photo;
69 }
70
71
72 /**
73  * Create a date record corresponding to the given strings.
74  *
75  * @param year Character representation of the year.
76  * @param month Character representation of the month.
77  * @param day Character representation of the day.
78  */
79 EContactDate read_date(char* year, char* month, char* day) {
80         EContactDate date;
81         date.year  = atoi(year);
82         date.month = atoi(month);
83         date.day   = atoi(day);
84         return date;
85 }
86
87
88 /**
89  * Main entry point: do the work of updating matched records.
90  */
91 int main(int argc, char* argv[]) {
92         g_type_init();
93         
94         try(argc > 2, "\nsyntax: <name> --photo <mime-type> <file>\n        <name> --birthday <year> <month> <day>");
95
96         // -- Data structures we'll use later...
97         //
98         gboolean is_photo;
99         gboolean is_birthday;
100         EContactPhoto photo;
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]);
105           is_photo = 1;
106           
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]);
110           is_birthday = 1;
111           
112         } else {
113           try(1 == 0, "\nsyntax: <name> --photo <mime-type> <file>\n        <name> --birthday <year> <month> <day>");
114         }
115         
116         // -- Open the address book...
117         //
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");
122
123         // -- Find the list of contacts...
124         //
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);
129         
130         // -- Update the contacts...
131         //
132         int i = 0;
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);
137             
138           if (is_photo || is_birthday) {
139             try(e_book_commit_contact(book, contact, &error), "committing contact");
140             i++;
141           }
142         }
143         printf("Modified %d records\n", i);
144
145         return EXIT_SUCCESS;
146 }
147