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_subvalues
*)malloc(
178 sizeof(struct gcal_structured_subvalues
));
179 contact
->structured_address
->field_typenr
= 0;
180 contact
->structured_address
->field_key
= NULL
;
181 contact
->structured_address
->field_value
= NULL
;
182 contact
->structured_address
->next_field
= NULL
;
183 contact
->structured_address_nr
= 0;
184 contact
->structured_address_type
= NULL
;
186 contact
->structured_name
= (struct gcal_structured_subvalues
*)malloc(
187 sizeof(struct gcal_structured_subvalues
));
188 contact
->structured_name
->field_typenr
= 0;
189 contact
->structured_name
->field_key
= NULL
;
190 contact
->structured_name
->field_value
= NULL
;
191 contact
->structured_name
->next_field
= NULL
;
193 contact
->common
.store_xml
= 0;
194 contact
->common
.id
= contact
->common
.updated
= NULL
;
195 contact
->common
.title
= contact
->common
.xml
= NULL
;
196 contact
->common
.edit_uri
= contact
->common
.etag
= NULL
;
197 contact
->emails_field
= contact
->emails_type
= NULL
;
198 contact
->emails_nr
= contact
->pref_email
= 0;
199 contact
->content
= NULL
;
200 contact
->nickname
= NULL
;
201 contact
->occupation
= NULL
;
202 contact
->org_name
= contact
->org_title
= contact
->im
= NULL
;
203 contact
->phone_numbers_field
= contact
->phone_numbers_type
= NULL
;
204 contact
->phone_numbers_nr
= contact
->groupMembership_nr
= 0;
205 contact
->post_address
= NULL
;
206 contact
->groupMembership
= NULL
;
207 contact
->homepage
= NULL
;
208 contact
->blog
= NULL
;
209 contact
->photo
= contact
->photo_data
= NULL
;
210 contact
->photo_length
= 0;
211 contact
->birthday
= NULL
;
214 void gcal_destroy_contact(struct gcal_contact
*contact
)
216 struct gcal_structured_subvalues
*temp_structured_entry
;
221 clean_string(contact
->common
.id
);
222 clean_string(contact
->common
.updated
);
223 clean_string(contact
->common
.title
);
224 clean_string(contact
->common
.edit_uri
);
225 clean_string(contact
->common
.etag
);
226 clean_multi_string(contact
->emails_field
, contact
->emails_nr
);
227 clean_multi_string(contact
->emails_type
, contact
->emails_nr
);
228 contact
->emails_nr
= contact
->pref_email
= 0;
229 clean_string(contact
->common
.xml
);
232 clean_string(contact
->content
);
233 clean_string(contact
->nickname
);
234 clean_string(contact
->occupation
);
235 clean_string(contact
->org_name
);
236 clean_string(contact
->org_title
);
237 clean_string(contact
->im
);
238 clean_multi_string(contact
->phone_numbers_field
, contact
->phone_numbers_nr
);
239 clean_multi_string(contact
->phone_numbers_type
, contact
->phone_numbers_nr
);
240 clean_multi_string(contact
->groupMembership
, contact
->groupMembership_nr
);
241 contact
->phone_numbers_nr
= contact
->groupMembership_nr
= 0;
242 clean_string(contact
->post_address
);
243 clean_string(contact
->homepage
);
244 clean_string(contact
->blog
);
245 clean_string(contact
->photo
);
246 clean_string(contact
->photo_data
);
247 contact
->photo_length
= 0;
248 clean_string(contact
->birthday
);
251 temp_structured_entry
= contact
->structured_address
;
252 if (temp_structured_entry
) {
253 temp_structured_entry
->field_typenr
= 0;
254 clean_string(temp_structured_entry
->field_key
);
255 clean_string(temp_structured_entry
->field_value
);
256 contact
->structured_address
= temp_structured_entry
->next_field
;
257 free(temp_structured_entry
);
259 } while (contact
->structured_address
);
261 clean_multi_string(contact
->structured_address_type
, contact
->structured_address_nr
);
262 contact
->structured_address_nr
= 0;
265 temp_structured_entry
= contact
->structured_name
;
266 if (temp_structured_entry
) {
267 temp_structured_entry
->field_typenr
= 0;
268 clean_string(temp_structured_entry
->field_key
);
269 clean_string(temp_structured_entry
->field_value
);
270 contact
->structured_name
= temp_structured_entry
->next_field
;
271 free(temp_structured_entry
);
273 } while (contact
->structured_name
);
276 void gcal_destroy_contacts(struct gcal_contact
*contacts
, size_t length
)
283 for (; i
< length
; ++i
)
284 gcal_destroy_contact((contacts
+ i
));
289 int gcal_create_contact(struct gcal_resource
*gcalobj
,
290 struct gcal_contact
*contact
,
291 struct gcal_contact
*updated
)
293 int result
= -1, length
;
294 char *xml_contact
= NULL
, *buffer
;
296 if ((!contact
) || (!gcalobj
))
299 result
= xmlcontact_create(contact
, &xml_contact
, &length
);
304 length
= sizeof(GCONTACT_START
) + sizeof(GCONTACT_END
) +
305 strlen(gcalobj
->user
) + sizeof(GCAL_DELIMITER
) +
306 strlen(gcalobj
->domain
) + 1;
307 buffer
= (char *) malloc(length
);
311 snprintf(buffer
, length
- 1, "%s%s%s%s%s", GCONTACT_START
,
312 gcalobj
->user
, GCAL_DELIMITER
, gcalobj
->domain
, GCONTACT_END
);
314 result
= up_entry(xml_contact
, strlen(xml_contact
), gcalobj
,
315 buffer
, NULL
, POST
, NULL
, GCAL_EDIT_ANSWER
);
320 if (gcalobj
->store_xml_entry
) {
321 if (contact
->common
.xml
)
322 free(contact
->common
.xml
);
323 if (!(contact
->common
.xml
= strdup(gcalobj
->buffer
)))
327 /* Parse buffer and create the new contact object */
331 gcalobj
->document
= build_dom_document(gcalobj
->buffer
);
332 if (!gcalobj
->document
)
335 /* There is only one 'entry' in the buffer */
336 gcal_init_contact(updated
);
337 result
= extract_all_contacts(gcalobj
->document
, updated
, 1);
341 /* Adding photo is the same as an edit operation */
342 if (contact
->photo_length
) {
343 result
= up_entry(contact
->photo_data
, contact
->photo_length
,
344 gcalobj
, updated
->photo
,
345 /* Google Data API 2.0 requires ETag */
347 PUT
, "Content-Type: image/*",
348 GCAL_DEFAULT_ANSWER
);
356 clean_dom_document(gcalobj
->document
);
357 gcalobj
->document
= NULL
;
370 int gcal_delete_contact(struct gcal_resource
*gcalobj
,
371 struct gcal_contact
*contact
)
373 int result
= -1, length
;
376 if (!contact
|| !gcalobj
)
379 /* Must cleanup HTTP buffer between requests */
380 clean_buffer(gcalobj
);
382 /* TODO: add X-HTTP header */
383 length
= strlen(gcalobj
->auth
) + sizeof(HEADER_GET
) + 1;
384 h_auth
= (char *) malloc(length
);
387 snprintf(h_auth
, length
- 1, "%s%s", HEADER_GET
, gcalobj
->auth
);
389 curl_easy_setopt(gcalobj
->curl
, CURLOPT_CUSTOMREQUEST
, "DELETE");
390 result
= http_post(gcalobj
, contact
->common
.edit_uri
,
391 "Content-Type: application/atom+xml",
392 /* Google Data API 2.0 requires ETag */
395 NULL
, NULL
, 0, GCAL_DEFAULT_ANSWER
,
396 "GData-Version: 3.0");
398 /* Restores curl context to previous standard mode */
399 curl_easy_setopt(gcalobj
->curl
, CURLOPT_CUSTOMREQUEST
, NULL
);
409 int gcal_edit_contact(struct gcal_resource
*gcalobj
,
410 struct gcal_contact
*contact
,
411 struct gcal_contact
*updated
)
414 int result
= -1, length
;
415 char *xml_contact
= NULL
;
417 if ((!contact
) || (!gcalobj
))
420 result
= xmlcontact_create(contact
, &xml_contact
, &length
);
424 result
= up_entry(xml_contact
, strlen(xml_contact
), gcalobj
,
425 contact
->common
.edit_uri
,
426 /* Google Data API 2.0 requires ETag */
428 PUT
, NULL
, GCAL_DEFAULT_ANSWER
);
433 if (gcalobj
->store_xml_entry
) {
434 if (contact
->common
.xml
)
435 free(contact
->common
.xml
);
436 if (!(contact
->common
.xml
= strdup(gcalobj
->buffer
)))
440 /* Parse buffer and create the new contact object */
444 gcalobj
->document
= build_dom_document(gcalobj
->buffer
);
445 if (!gcalobj
->document
)
448 /* There is only one 'entry' in the buffer */
449 gcal_init_contact(updated
);
450 result
= extract_all_contacts(gcalobj
->document
, updated
, 1);
454 /* Adding photo is the same as an edit operation */
455 if (contact
->photo_length
) {
456 result
= up_entry(contact
->photo_data
, contact
->photo_length
,
457 gcalobj
, updated
->photo
,
458 /* Google Data API 2.0 requires ETag */
460 PUT
, "Content-Type: image/*",
461 GCAL_DEFAULT_ANSWER
);
471 clean_dom_document(gcalobj
->document
);
472 gcalobj
->document
= NULL
;