OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/chromeos/contacts/gdata_contacts_service.h" | 5 #include "chrome/browser/chromeos/contacts/gdata_contacts_service.h" |
6 | 6 |
7 #include <cstring> | 7 #include <cstring> |
8 #include <map> | 8 #include <map> |
9 #include <string> | 9 #include <string> |
10 #include <utility> | 10 #include <utility> |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
149 // Returns a string containing a pretty-printed JSON representation of |value|. | 149 // Returns a string containing a pretty-printed JSON representation of |value|. |
150 std::string PrettyPrintValue(const base::Value& value) { | 150 std::string PrettyPrintValue(const base::Value& value) { |
151 std::string out; | 151 std::string out; |
152 base::JSONWriter::WriteWithOptions( | 152 base::JSONWriter::WriteWithOptions( |
153 &value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &out); | 153 &value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &out); |
154 return out; | 154 return out; |
155 } | 155 } |
156 | 156 |
157 // Assigns the value at |path| within |dict| to |out|, returning false if the | 157 // Assigns the value at |path| within |dict| to |out|, returning false if the |
158 // path wasn't present. Unicode byte order marks are removed from the string. | 158 // path wasn't present. Unicode byte order marks are removed from the string. |
159 bool GetCleanedString(const DictionaryValue& dict, | 159 bool GetCleanedString(const base::DictionaryValue& dict, |
160 const std::string& path, | 160 const std::string& path, |
161 std::string* out) { | 161 std::string* out) { |
162 if (!dict.GetString(path, out)) | 162 if (!dict.GetString(path, out)) |
163 return false; | 163 return false; |
164 | 164 |
165 // The Unicode byte order mark, U+FEFF, is useless in UTF-8 strings (which are | 165 // The Unicode byte order mark, U+FEFF, is useless in UTF-8 strings (which are |
166 // interpreted one byte at a time). | 166 // interpreted one byte at a time). |
167 ReplaceSubstringsAfterOffset(out, 0, "\xEF\xBB\xBF", ""); | 167 ReplaceSubstringsAfterOffset(out, 0, "\xEF\xBB\xBF", ""); |
168 return true; | 168 return true; |
169 } | 169 } |
170 | 170 |
171 // Returns whether an address is primary, given a dictionary representing a | 171 // Returns whether an address is primary, given a dictionary representing a |
172 // single address. | 172 // single address. |
173 bool IsAddressPrimary(const DictionaryValue& address_dict) { | 173 bool IsAddressPrimary(const base::DictionaryValue& address_dict) { |
174 std::string primary; | 174 std::string primary; |
175 address_dict.GetString(kAddressPrimaryField, &primary); | 175 address_dict.GetString(kAddressPrimaryField, &primary); |
176 return primary == kAddressPrimaryTrueValue; | 176 return primary == kAddressPrimaryTrueValue; |
177 } | 177 } |
178 | 178 |
179 // Initializes an AddressType message given a dictionary representing a single | 179 // Initializes an AddressType message given a dictionary representing a single |
180 // address. | 180 // address. |
181 void InitAddressType(const DictionaryValue& address_dict, | 181 void InitAddressType(const base::DictionaryValue& address_dict, |
182 Contact_AddressType* type) { | 182 Contact_AddressType* type) { |
183 DCHECK(type); | 183 DCHECK(type); |
184 type->Clear(); | 184 type->Clear(); |
185 | 185 |
186 std::string rel; | 186 std::string rel; |
187 address_dict.GetString(kAddressRelField, &rel); | 187 address_dict.GetString(kAddressRelField, &rel); |
188 if (rel == kAddressRelHomeValue) | 188 if (rel == kAddressRelHomeValue) |
189 type->set_relation(Contact_AddressType_Relation_HOME); | 189 type->set_relation(Contact_AddressType_Relation_HOME); |
190 else if (rel == kAddressRelWorkValue) | 190 else if (rel == kAddressRelWorkValue) |
191 type->set_relation(Contact_AddressType_Relation_WORK); | 191 type->set_relation(Contact_AddressType_Relation_WORK); |
192 else if (rel == kAddressRelMobileValue) | 192 else if (rel == kAddressRelMobileValue) |
193 type->set_relation(Contact_AddressType_Relation_MOBILE); | 193 type->set_relation(Contact_AddressType_Relation_MOBILE); |
194 else | 194 else |
195 type->set_relation(Contact_AddressType_Relation_OTHER); | 195 type->set_relation(Contact_AddressType_Relation_OTHER); |
196 | 196 |
197 GetCleanedString(address_dict, kAddressLabelField, type->mutable_label()); | 197 GetCleanedString(address_dict, kAddressLabelField, type->mutable_label()); |
198 } | 198 } |
199 | 199 |
200 // Maps the protocol from a dictionary representing a contact's IM address to a | 200 // Maps the protocol from a dictionary representing a contact's IM address to a |
201 // contacts::Contact_InstantMessagingAddress_Protocol value. | 201 // contacts::Contact_InstantMessagingAddress_Protocol value. |
202 contacts::Contact_InstantMessagingAddress_Protocol | 202 contacts::Contact_InstantMessagingAddress_Protocol |
203 GetInstantMessagingProtocol(const DictionaryValue& im_dict) { | 203 GetInstantMessagingProtocol(const base::DictionaryValue& im_dict) { |
204 std::string protocol; | 204 std::string protocol; |
205 im_dict.GetString(kInstantMessagingProtocolField, &protocol); | 205 im_dict.GetString(kInstantMessagingProtocolField, &protocol); |
206 if (protocol == kInstantMessagingProtocolAimValue) | 206 if (protocol == kInstantMessagingProtocolAimValue) |
207 return contacts::Contact_InstantMessagingAddress_Protocol_AIM; | 207 return contacts::Contact_InstantMessagingAddress_Protocol_AIM; |
208 else if (protocol == kInstantMessagingProtocolMsnValue) | 208 else if (protocol == kInstantMessagingProtocolMsnValue) |
209 return contacts::Contact_InstantMessagingAddress_Protocol_MSN; | 209 return contacts::Contact_InstantMessagingAddress_Protocol_MSN; |
210 else if (protocol == kInstantMessagingProtocolYahooValue) | 210 else if (protocol == kInstantMessagingProtocolYahooValue) |
211 return contacts::Contact_InstantMessagingAddress_Protocol_YAHOO; | 211 return contacts::Contact_InstantMessagingAddress_Protocol_YAHOO; |
212 else if (protocol == kInstantMessagingProtocolSkypeValue) | 212 else if (protocol == kInstantMessagingProtocolSkypeValue) |
213 return contacts::Contact_InstantMessagingAddress_Protocol_SKYPE; | 213 return contacts::Contact_InstantMessagingAddress_Protocol_SKYPE; |
214 else if (protocol == kInstantMessagingProtocolQqValue) | 214 else if (protocol == kInstantMessagingProtocolQqValue) |
215 return contacts::Contact_InstantMessagingAddress_Protocol_QQ; | 215 return contacts::Contact_InstantMessagingAddress_Protocol_QQ; |
216 else if (protocol == kInstantMessagingProtocolGoogleTalkValue) | 216 else if (protocol == kInstantMessagingProtocolGoogleTalkValue) |
217 return contacts::Contact_InstantMessagingAddress_Protocol_GOOGLE_TALK; | 217 return contacts::Contact_InstantMessagingAddress_Protocol_GOOGLE_TALK; |
218 else if (protocol == kInstantMessagingProtocolIcqValue) | 218 else if (protocol == kInstantMessagingProtocolIcqValue) |
219 return contacts::Contact_InstantMessagingAddress_Protocol_ICQ; | 219 return contacts::Contact_InstantMessagingAddress_Protocol_ICQ; |
220 else if (protocol == kInstantMessagingProtocolJabberValue) | 220 else if (protocol == kInstantMessagingProtocolJabberValue) |
221 return contacts::Contact_InstantMessagingAddress_Protocol_JABBER; | 221 return contacts::Contact_InstantMessagingAddress_Protocol_JABBER; |
222 else | 222 else |
223 return contacts::Contact_InstantMessagingAddress_Protocol_OTHER; | 223 return contacts::Contact_InstantMessagingAddress_Protocol_OTHER; |
224 } | 224 } |
225 | 225 |
226 // Gets the photo URL from a contact's dictionary (within the "entry" list). | 226 // Gets the photo URL from a contact's dictionary (within the "entry" list). |
227 // Returns an empty string if no photo was found. | 227 // Returns an empty string if no photo was found. |
228 std::string GetPhotoUrl(const DictionaryValue& dict) { | 228 std::string GetPhotoUrl(const base::DictionaryValue& dict) { |
229 const ListValue* link_list = NULL; | 229 const base::ListValue* link_list = NULL; |
230 if (!dict.GetList(kLinkField, &link_list)) | 230 if (!dict.GetList(kLinkField, &link_list)) |
231 return std::string(); | 231 return std::string(); |
232 | 232 |
233 for (size_t i = 0; i < link_list->GetSize(); ++i) { | 233 for (size_t i = 0; i < link_list->GetSize(); ++i) { |
234 const DictionaryValue* link_dict = NULL; | 234 const base::DictionaryValue* link_dict = NULL; |
235 if (!link_list->GetDictionary(i, &link_dict)) | 235 if (!link_list->GetDictionary(i, &link_dict)) |
236 continue; | 236 continue; |
237 | 237 |
238 std::string rel; | 238 std::string rel; |
239 if (!link_dict->GetString(kLinkRelField, &rel)) | 239 if (!link_dict->GetString(kLinkRelField, &rel)) |
240 continue; | 240 continue; |
241 if (rel != kLinkRelPhotoValue) | 241 if (rel != kLinkRelPhotoValue) |
242 continue; | 242 continue; |
243 | 243 |
244 // From https://goo.gl/7T6Od: "If a contact does not have a photo, then the | 244 // From https://goo.gl/7T6Od: "If a contact does not have a photo, then the |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
279 return true; | 279 return true; |
280 | 280 |
281 GetCleanedString(dict, kFullNameField, contact->mutable_full_name()); | 281 GetCleanedString(dict, kFullNameField, contact->mutable_full_name()); |
282 GetCleanedString(dict, kGivenNameField, contact->mutable_given_name()); | 282 GetCleanedString(dict, kGivenNameField, contact->mutable_given_name()); |
283 GetCleanedString( | 283 GetCleanedString( |
284 dict, kAdditionalNameField, contact->mutable_additional_name()); | 284 dict, kAdditionalNameField, contact->mutable_additional_name()); |
285 GetCleanedString(dict, kFamilyNameField, contact->mutable_family_name()); | 285 GetCleanedString(dict, kFamilyNameField, contact->mutable_family_name()); |
286 GetCleanedString(dict, kNamePrefixField, contact->mutable_name_prefix()); | 286 GetCleanedString(dict, kNamePrefixField, contact->mutable_name_prefix()); |
287 GetCleanedString(dict, kNameSuffixField, contact->mutable_name_suffix()); | 287 GetCleanedString(dict, kNameSuffixField, contact->mutable_name_suffix()); |
288 | 288 |
289 const ListValue* email_list = NULL; | 289 const base::ListValue* email_list = NULL; |
290 if (dict.GetList(kEmailField, &email_list)) { | 290 if (dict.GetList(kEmailField, &email_list)) { |
291 for (size_t i = 0; i < email_list->GetSize(); ++i) { | 291 for (size_t i = 0; i < email_list->GetSize(); ++i) { |
292 const DictionaryValue* email_dict = NULL; | 292 const base::DictionaryValue* email_dict = NULL; |
293 if (!email_list->GetDictionary(i, &email_dict)) | 293 if (!email_list->GetDictionary(i, &email_dict)) |
294 return false; | 294 return false; |
295 | 295 |
296 contacts::Contact_EmailAddress* email = contact->add_email_addresses(); | 296 contacts::Contact_EmailAddress* email = contact->add_email_addresses(); |
297 if (!GetCleanedString(*email_dict, | 297 if (!GetCleanedString(*email_dict, |
298 kEmailAddressField, | 298 kEmailAddressField, |
299 email->mutable_address())) { | 299 email->mutable_address())) { |
300 return false; | 300 return false; |
301 } | 301 } |
302 email->set_primary(IsAddressPrimary(*email_dict)); | 302 email->set_primary(IsAddressPrimary(*email_dict)); |
303 InitAddressType(*email_dict, email->mutable_type()); | 303 InitAddressType(*email_dict, email->mutable_type()); |
304 } | 304 } |
305 } | 305 } |
306 | 306 |
307 const ListValue* phone_list = NULL; | 307 const base::ListValue* phone_list = NULL; |
308 if (dict.GetList(kPhoneField, &phone_list)) { | 308 if (dict.GetList(kPhoneField, &phone_list)) { |
309 for (size_t i = 0; i < phone_list->GetSize(); ++i) { | 309 for (size_t i = 0; i < phone_list->GetSize(); ++i) { |
310 const DictionaryValue* phone_dict = NULL; | 310 const base::DictionaryValue* phone_dict = NULL; |
311 if (!phone_list->GetDictionary(i, &phone_dict)) | 311 if (!phone_list->GetDictionary(i, &phone_dict)) |
312 return false; | 312 return false; |
313 | 313 |
314 contacts::Contact_PhoneNumber* phone = contact->add_phone_numbers(); | 314 contacts::Contact_PhoneNumber* phone = contact->add_phone_numbers(); |
315 if (!GetCleanedString(*phone_dict, | 315 if (!GetCleanedString(*phone_dict, |
316 kPhoneNumberField, | 316 kPhoneNumberField, |
317 phone->mutable_number())) { | 317 phone->mutable_number())) { |
318 return false; | 318 return false; |
319 } | 319 } |
320 phone->set_primary(IsAddressPrimary(*phone_dict)); | 320 phone->set_primary(IsAddressPrimary(*phone_dict)); |
321 InitAddressType(*phone_dict, phone->mutable_type()); | 321 InitAddressType(*phone_dict, phone->mutable_type()); |
322 } | 322 } |
323 } | 323 } |
324 | 324 |
325 const ListValue* address_list = NULL; | 325 const base::ListValue* address_list = NULL; |
326 if (dict.GetList(kPostalAddressField, &address_list)) { | 326 if (dict.GetList(kPostalAddressField, &address_list)) { |
327 for (size_t i = 0; i < address_list->GetSize(); ++i) { | 327 for (size_t i = 0; i < address_list->GetSize(); ++i) { |
328 const DictionaryValue* address_dict = NULL; | 328 const base::DictionaryValue* address_dict = NULL; |
329 if (!address_list->GetDictionary(i, &address_dict)) | 329 if (!address_list->GetDictionary(i, &address_dict)) |
330 return false; | 330 return false; |
331 | 331 |
332 contacts::Contact_PostalAddress* address = | 332 contacts::Contact_PostalAddress* address = |
333 contact->add_postal_addresses(); | 333 contact->add_postal_addresses(); |
334 if (!GetCleanedString(*address_dict, | 334 if (!GetCleanedString(*address_dict, |
335 kPostalAddressFormattedField, | 335 kPostalAddressFormattedField, |
336 address->mutable_address())) { | 336 address->mutable_address())) { |
337 return false; | 337 return false; |
338 } | 338 } |
339 address->set_primary(IsAddressPrimary(*address_dict)); | 339 address->set_primary(IsAddressPrimary(*address_dict)); |
340 InitAddressType(*address_dict, address->mutable_type()); | 340 InitAddressType(*address_dict, address->mutable_type()); |
341 } | 341 } |
342 } | 342 } |
343 | 343 |
344 const ListValue* im_list = NULL; | 344 const base::ListValue* im_list = NULL; |
345 if (dict.GetList(kInstantMessagingField, &im_list)) { | 345 if (dict.GetList(kInstantMessagingField, &im_list)) { |
346 for (size_t i = 0; i < im_list->GetSize(); ++i) { | 346 for (size_t i = 0; i < im_list->GetSize(); ++i) { |
347 const DictionaryValue* im_dict = NULL; | 347 const base::DictionaryValue* im_dict = NULL; |
348 if (!im_list->GetDictionary(i, &im_dict)) | 348 if (!im_list->GetDictionary(i, &im_dict)) |
349 return false; | 349 return false; |
350 | 350 |
351 contacts::Contact_InstantMessagingAddress* im = | 351 contacts::Contact_InstantMessagingAddress* im = |
352 contact->add_instant_messaging_addresses(); | 352 contact->add_instant_messaging_addresses(); |
353 if (!GetCleanedString(*im_dict, | 353 if (!GetCleanedString(*im_dict, |
354 kInstantMessagingAddressField, | 354 kInstantMessagingAddressField, |
355 im->mutable_address())) { | 355 im->mutable_address())) { |
356 return false; | 356 return false; |
357 } | 357 } |
(...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
617 photo_download_timer_.Start( | 617 photo_download_timer_.Start( |
618 FROM_HERE, service_->photo_download_timer_interval_, | 618 FROM_HERE, service_->photo_download_timer_interval_, |
619 this, &DownloadContactsRequest::StartPhotoDownloads); | 619 this, &DownloadContactsRequest::StartPhotoDownloads); |
620 CheckCompletion(); | 620 CheckCompletion(); |
621 } | 621 } |
622 | 622 |
623 // Processes the raw contacts feed from |feed_data| and fills |contacts_|. | 623 // Processes the raw contacts feed from |feed_data| and fills |contacts_|. |
624 // Returns true on success. | 624 // Returns true on success. |
625 bool ProcessContactsFeedData(const base::Value& feed_data) { | 625 bool ProcessContactsFeedData(const base::Value& feed_data) { |
626 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 626 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
627 const DictionaryValue* toplevel_dict = NULL; | 627 const base::DictionaryValue* toplevel_dict = NULL; |
628 if (!feed_data.GetAsDictionary(&toplevel_dict)) { | 628 if (!feed_data.GetAsDictionary(&toplevel_dict)) { |
629 LOG(WARNING) << "Top-level object is not a dictionary"; | 629 LOG(WARNING) << "Top-level object is not a dictionary"; |
630 return false; | 630 return false; |
631 } | 631 } |
632 | 632 |
633 const DictionaryValue* feed_dict = NULL; | 633 const base::DictionaryValue* feed_dict = NULL; |
634 if (!toplevel_dict->GetDictionary(kFeedField, &feed_dict)) { | 634 if (!toplevel_dict->GetDictionary(kFeedField, &feed_dict)) { |
635 LOG(WARNING) << "Feed dictionary missing"; | 635 LOG(WARNING) << "Feed dictionary missing"; |
636 return false; | 636 return false; |
637 } | 637 } |
638 | 638 |
639 // Check the category field to confirm that this is actually a contact feed. | 639 // Check the category field to confirm that this is actually a contact feed. |
640 const ListValue* category_list = NULL; | 640 const base::ListValue* category_list = NULL; |
641 if (!feed_dict->GetList(kCategoryField, &category_list)) { | 641 if (!feed_dict->GetList(kCategoryField, &category_list)) { |
642 LOG(WARNING) << "Category list missing"; | 642 LOG(WARNING) << "Category list missing"; |
643 return false; | 643 return false; |
644 } | 644 } |
645 const DictionaryValue* category_dict = NULL; | 645 const base::DictionaryValue* category_dict = NULL; |
646 if (category_list->GetSize() != 1 || | 646 if (category_list->GetSize() != 1 || |
647 !category_list->GetDictionary(0, &category_dict)) { | 647 !category_list->GetDictionary(0, &category_dict)) { |
648 LOG(WARNING) << "Unable to get dictionary from category list of size " | 648 LOG(WARNING) << "Unable to get dictionary from category list of size " |
649 << category_list->GetSize(); | 649 << category_list->GetSize(); |
650 return false; | 650 return false; |
651 } | 651 } |
652 std::string category_scheme, category_term; | 652 std::string category_scheme, category_term; |
653 if (!category_dict->GetString(kCategorySchemeField, &category_scheme) || | 653 if (!category_dict->GetString(kCategorySchemeField, &category_scheme) || |
654 !category_dict->GetString(kCategoryTermField, &category_term) || | 654 !category_dict->GetString(kCategoryTermField, &category_term) || |
655 category_scheme != kCategorySchemeValue || | 655 category_scheme != kCategorySchemeValue || |
656 category_term != kCategoryTermValue) { | 656 category_term != kCategoryTermValue) { |
657 LOG(WARNING) << "Unexpected category (scheme was \"" << category_scheme | 657 LOG(WARNING) << "Unexpected category (scheme was \"" << category_scheme |
658 << "\", term was \"" << category_term << "\")"; | 658 << "\", term was \"" << category_term << "\")"; |
659 return false; | 659 return false; |
660 } | 660 } |
661 | 661 |
662 // A missing entry list means no entries (maybe we're doing an incremental | 662 // A missing entry list means no entries (maybe we're doing an incremental |
663 // update and nothing has changed). | 663 // update and nothing has changed). |
664 const ListValue* entry_list = NULL; | 664 const base::ListValue* entry_list = NULL; |
665 if (!feed_dict->GetList(kEntryField, &entry_list)) | 665 if (!feed_dict->GetList(kEntryField, &entry_list)) |
666 return true; | 666 return true; |
667 | 667 |
668 contacts_needing_photo_downloads_.reserve(entry_list->GetSize()); | 668 contacts_needing_photo_downloads_.reserve(entry_list->GetSize()); |
669 | 669 |
670 for (ListValue::const_iterator entry_it = entry_list->begin(); | 670 for (base::ListValue::const_iterator entry_it = entry_list->begin(); |
671 entry_it != entry_list->end(); ++entry_it) { | 671 entry_it != entry_list->end(); ++entry_it) { |
672 const size_t index = (entry_it - entry_list->begin()); | 672 const size_t index = (entry_it - entry_list->begin()); |
673 const DictionaryValue* contact_dict = NULL; | 673 const base::DictionaryValue* contact_dict = NULL; |
674 if (!(*entry_it)->GetAsDictionary(&contact_dict)) { | 674 if (!(*entry_it)->GetAsDictionary(&contact_dict)) { |
675 LOG(WARNING) << "Entry " << index << " isn't a dictionary"; | 675 LOG(WARNING) << "Entry " << index << " isn't a dictionary"; |
676 return false; | 676 return false; |
677 } | 677 } |
678 | 678 |
679 scoped_ptr<contacts::Contact> contact(new contacts::Contact); | 679 scoped_ptr<contacts::Contact> contact(new contacts::Contact); |
680 if (!FillContactFromDictionary(*contact_dict, contact.get())) { | 680 if (!FillContactFromDictionary(*contact_dict, contact.get())) { |
681 LOG(WARNING) << "Unable to fill entry " << index; | 681 LOG(WARNING) << "Unable to fill entry " << index; |
682 return false; | 682 return false; |
683 } | 683 } |
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
885 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 885 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
886 DCHECK(request); | 886 DCHECK(request); |
887 VLOG(1) << "Download request " << request << " complete"; | 887 VLOG(1) << "Download request " << request << " complete"; |
888 if (!request->my_contacts_group_id().empty()) | 888 if (!request->my_contacts_group_id().empty()) |
889 cached_my_contacts_group_id_ = request->my_contacts_group_id(); | 889 cached_my_contacts_group_id_ = request->my_contacts_group_id(); |
890 requests_.erase(request); | 890 requests_.erase(request); |
891 delete request; | 891 delete request; |
892 } | 892 } |
893 | 893 |
894 } // namespace contacts | 894 } // namespace contacts |
OLD | NEW |