2 Copyright (c) 2008 Instituto Nokia de Tecnologia
5 Redistribution and use in source and binary forms, with or without modification,
6 are permitted provided that the following conditions are met:
8 * Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright notice,
11 this list of conditions and the following disclaimer in the documentation
12 and/or other materials provided with the distribution.
13 * Neither the name of the INdT nor the names of its contributors
14 may be used to endorse or promote products derived from this software
15 without specific prior written permission.
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 POSSIBILITY OF SUCH DAMAGE.
32 * @author Adenilson Cavalcanti
33 * @date Fri May 30 15:30:35 2008
35 * @brief Base file for google contacts service access library.
38 * - for some firewalls, X-HTTP-Method-Override: DELETE can be required
42 #include "internal_gcal.h"
44 #include "gcal_parser.h"
45 #include "msvc_hacks.h"
48 static size_t write_cb_binary(void *ptr
, size_t count
, size_t chunk_size
,
52 size_t size
= count
* chunk_size
;
53 struct gcal_resource
*gcal_ptr
= (struct gcal_resource
*)data
;
56 if (size
> (gcal_ptr
->length
- gcal_ptr
->previous_length
- 1)) {
57 gcal_ptr
->length
= gcal_ptr
->length
+ size
+ 1;
58 ptr_tmp
= realloc(gcal_ptr
->buffer
, gcal_ptr
->length
);
61 if (gcal_ptr
->fout_log
)
62 fprintf(gcal_ptr
->fout_log
,
63 "write_cb: Failed relloc!\n");
67 gcal_ptr
->buffer
= ptr_tmp
;
70 memcpy(gcal_ptr
->buffer
+ gcal_ptr
->previous_length
, ptr
, size
);
71 gcal_ptr
->previous_length
+= size
;
77 struct gcal_contact
*gcal_get_all_contacts(struct gcal_resource
*gcalobj
,
83 struct gcal_contact
*ptr_res
= NULL
;
88 if (!gcalobj
->buffer
|| !gcalobj
->has_xml
)
91 gcalobj
->document
= build_dom_document(gcalobj
->buffer
);
92 if (!gcalobj
->document
)
96 result
= get_entries_number(gcalobj
->document
);
100 ptr_res
= malloc(sizeof(struct gcal_contact
) * result
);
103 memset(ptr_res
, 0, sizeof(struct gcal_contact
) * result
);
106 for (i
= 0; i
< *length
; ++i
) {
107 gcal_init_contact((ptr_res
+ i
));
108 if (gcalobj
->store_xml_entry
)
109 (ptr_res
+ i
)->common
.store_xml
= 1;
112 result
= extract_all_contacts(gcalobj
->document
, ptr_res
, *length
);
119 /* Check contacts with photo and download the pictures */
120 for (i
= 0; i
< *length
; ++i
){
121 if (ptr_res
[i
].photo_length
) {
122 if (gcalobj
->fout_log
)
123 fprintf(gcalobj
->fout_log
,
124 "contact with photo!\n");
126 result
= get_follow_redirection(gcalobj
,
129 "GData-Version: 3.0");
130 ptr_res
[i
].photo_data
= malloc(sizeof(char) *
132 if (!ptr_res
[i
].photo_data
)
134 ptr_res
[i
].photo_length
= gcalobj
->length
;
135 memcpy(ptr_res
[i
].photo_data
, gcalobj
->buffer
,
136 ptr_res
[i
].photo_length
);
138 clean_buffer(gcalobj
);
140 } else if (gcalobj
->fout_log
)
141 fprintf(gcalobj
->fout_log
, "contact without photo!\n");
146 clean_dom_document(gcalobj
->document
);
147 gcalobj
->document
= NULL
;
154 static void clean_string(char *ptr_str
)
160 static void clean_multi_string(char **ptr_str
, int n
)
165 for (i
= 0; i
< n
; i
++)
172 void gcal_init_contact(struct gcal_contact
*contact
)
177 contact
->structured_address
=(struct gcal_structured_postal_address
*)malloc(sizeof(struct gcal_structured_postal_address
));
178 contact
->structured_address
->address_field_key
= NULL
;
179 contact
->structured_address
->address_field_value
= NULL
;
180 contact
->structured_address
->next_address_field
= NULL
;
182 contact
->common
.store_xml
= 0;
183 contact
->common
.id
= contact
->common
.updated
= NULL
;
184 contact
->common
.title
= contact
->common
.xml
= NULL
;
185 contact
->common
.edit_uri
= contact
->common
.etag
= NULL
;
186 contact
->emails_field
= contact
->emails_type
= NULL
;
187 contact
->emails_nr
= contact
->pref_email
= 0;
188 contact
->content
= NULL
;
189 contact
->org_name
= contact
->org_title
= contact
->im
= NULL
;
190 contact
->phone_numbers_field
= contact
->phone_numbers_type
= NULL
;
191 contact
->phone_numbers_nr
= contact
->groupMembership_nr
= 0;
192 contact
->post_address
= NULL
;
193 contact
->groupMembership
= NULL
;
194 contact
->homepage
= NULL
;
195 contact
->blog
= NULL
;
196 contact
->photo
= contact
->photo_data
= NULL
;
197 contact
->photo_length
= 0;
198 contact
->birthday
= NULL
;
201 void gcal_destroy_contact(struct gcal_contact
*contact
)
203 struct gcal_structured_postal_address
*temp_structured_address
= contact
->structured_address
;
207 clean_string(contact
->common
.id
);
208 clean_string(contact
->common
.updated
);
209 clean_string(contact
->common
.title
);
210 clean_string(contact
->common
.edit_uri
);
211 clean_string(contact
->common
.etag
);
212 clean_multi_string(contact
->emails_field
, contact
->emails_nr
);
213 clean_multi_string(contact
->emails_type
, contact
->emails_nr
);
214 contact
->emails_nr
= contact
->pref_email
= 0;
215 clean_string(contact
->common
.xml
);
218 clean_string(contact
->content
);
219 clean_string(contact
->org_name
);
220 clean_string(contact
->org_title
);
221 clean_string(contact
->im
);
222 clean_multi_string(contact
->phone_numbers_field
, contact
->phone_numbers_nr
);
223 clean_multi_string(contact
->phone_numbers_type
, contact
->phone_numbers_nr
);
224 clean_multi_string(contact
->groupMembership
, contact
->groupMembership_nr
);
225 contact
->phone_numbers_nr
= contact
->groupMembership_nr
= 0;
226 clean_string(contact
->post_address
);
227 clean_string(contact
->homepage
);
228 clean_string(contact
->blog
);
229 clean_string(contact
->photo
);
230 clean_string(contact
->photo_data
);
231 contact
->photo_length
= 0;
232 clean_string(contact
->birthday
);
234 while (temp_structured_address
!= NULL
)
236 struct gcal_structured_postal_address
*next_structured_address
= temp_structured_address
->next_address_field
;
237 clean_string(temp_structured_address
->address_field_value
);
238 clean_string(temp_structured_address
->address_field_key
);
239 free(temp_structured_address
);
240 temp_structured_address
= next_structured_address
;
244 void gcal_destroy_contacts(struct gcal_contact
*contacts
, size_t length
)
251 for (; i
< length
; ++i
)
252 gcal_destroy_contact((contacts
+ i
));
257 int gcal_create_contact(struct gcal_resource
*gcalobj
,
258 struct gcal_contact
*contact
,
259 struct gcal_contact
*updated
)
261 int result
= -1, length
;
262 char *xml_contact
= NULL
, *buffer
;
264 if ((!contact
) || (!gcalobj
))
267 result
= xmlcontact_create(contact
, &xml_contact
, &length
);
272 length
= sizeof(GCONTACT_START
) + sizeof(GCONTACT_END
) +
273 strlen(gcalobj
->user
) + sizeof(GCAL_DELIMITER
) +
274 strlen(gcalobj
->domain
) + 1;
275 buffer
= (char *) malloc(length
);
278 snprintf(buffer
, length
- 1, "%s%s%s%s%s", GCONTACT_START
,
279 gcalobj
->user
, GCAL_DELIMITER
, gcalobj
->domain
, GCONTACT_END
);
281 result
= up_entry(xml_contact
, strlen(xml_contact
), gcalobj
,
282 buffer
, NULL
, POST
, NULL
, GCAL_EDIT_ANSWER
);
287 if (gcalobj
->store_xml_entry
) {
288 if (contact
->common
.xml
)
289 free(contact
->common
.xml
);
290 if (!(contact
->common
.xml
= strdup(gcalobj
->buffer
)))
294 /* Parse buffer and create the new contact object */
298 gcalobj
->document
= build_dom_document(gcalobj
->buffer
);
299 if (!gcalobj
->document
)
302 /* There is only one 'entry' in the buffer */
303 gcal_init_contact(updated
);
304 result
= extract_all_contacts(gcalobj
->document
, updated
, 1);
308 /* Adding photo is the same as an edit operation */
309 if (contact
->photo_length
) {
310 result
= up_entry(contact
->photo_data
, contact
->photo_length
,
311 gcalobj
, updated
->photo
, NULL
,
312 PUT
, "Content-Type: image/*",
313 GCAL_DEFAULT_ANSWER
);
323 clean_dom_document(gcalobj
->document
);
324 gcalobj
->document
= NULL
;
337 int gcal_delete_contact(struct gcal_resource
*gcalobj
,
338 struct gcal_contact
*contact
)
340 int result
= -1, length
;
343 if (!contact
|| !gcalobj
)
346 /* Must cleanup HTTP buffer between requests */
347 clean_buffer(gcalobj
);
349 /* TODO: add X-HTTP header */
350 length
= strlen(gcalobj
->auth
) + sizeof(HEADER_GET
) + 1;
351 h_auth
= (char *) malloc(length
);
354 snprintf(h_auth
, length
- 1, "%s%s", HEADER_GET
, gcalobj
->auth
);
356 curl_easy_setopt(gcalobj
->curl
, CURLOPT_CUSTOMREQUEST
, "DELETE");
357 result
= http_post(gcalobj
, contact
->common
.edit_uri
,
358 "Content-Type: application/atom+xml",
359 /* Google Data API 2.0 requires ETag */
362 NULL
, NULL
, 0, GCAL_DEFAULT_ANSWER
,
363 "GData-Version: 3.0");
365 /* Restores curl context to previous standard mode */
366 curl_easy_setopt(gcalobj
->curl
, CURLOPT_CUSTOMREQUEST
, NULL
);
376 int gcal_edit_contact(struct gcal_resource
*gcalobj
,
377 struct gcal_contact
*contact
,
378 struct gcal_contact
*updated
)
381 int result
= -1, length
;
382 char *xml_contact
= NULL
;
384 if ((!contact
) || (!gcalobj
))
387 result
= xmlcontact_create(contact
, &xml_contact
, &length
);
391 result
= up_entry(xml_contact
, strlen(xml_contact
), gcalobj
,
392 contact
->common
.edit_uri
,
393 /* Google Data API 2.0 requires ETag */
395 PUT
, NULL
, GCAL_DEFAULT_ANSWER
);
400 if (gcalobj
->store_xml_entry
) {
401 if (contact
->common
.xml
)
402 free(contact
->common
.xml
);
403 if (!(contact
->common
.xml
= strdup(gcalobj
->buffer
)))
407 /* Parse buffer and create the new contact object */
411 gcalobj
->document
= build_dom_document(gcalobj
->buffer
);
412 if (!gcalobj
->document
)
415 /* There is only one 'entry' in the buffer */
416 gcal_init_contact(updated
);
417 result
= extract_all_contacts(gcalobj
->document
, updated
, 1);
421 /* Adding photo is the same as an edit operation */
422 if (contact
->photo_length
) {
423 result
= up_entry(contact
->photo_data
, contact
->photo_length
,
424 gcalobj
, updated
->photo
,
425 /* Google Data API 2.0 requires ETag */
427 PUT
, "Content-Type: image/*",
428 GCAL_DEFAULT_ANSWER
);
438 clean_dom_document(gcalobj
->document
);
439 gcalobj
->document
= NULL
;