1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/autofill/autofill_profile.h"
6
7#include <algorithm>
8#include <map>
9#include <set>
10
11#include "base/basictypes.h"
12#include "base/logging.h"
13#include "base/string_util.h"
14#include "base/utf_string_conversions.h"
15#include "chrome/browser/autofill/address.h"
16#include "chrome/browser/autofill/autofill_type.h"
17#include "chrome/browser/autofill/contact_info.h"
18#include "chrome/browser/autofill/fax_number.h"
19#include "chrome/browser/autofill/home_phone_number.h"
20#include "chrome/common/guid.h"
21#include "grit/generated_resources.h"
22#include "ui/base/l10n/l10n_util.h"
23
24namespace {
25
26// Like |AutofillType::GetEquivalentFieldType()|, but also returns |NAME_FULL|
27// for first, middle, and last name field types.
28AutofillFieldType GetEquivalentFieldTypeCollapsingNames(
29    AutofillFieldType field_type) {
30  if (field_type == NAME_FIRST || field_type == NAME_MIDDLE ||
31      field_type == NAME_LAST)
32    return NAME_FULL;
33
34  return AutofillType::GetEquivalentFieldType(field_type);
35}
36
37// Fills |distinguishing_fields| with a list of fields to use when creating
38// labels that can help to distinguish between two profiles. Draws fields from
39// |suggested_fields| if it is non-NULL; otherwise returns a default list.
40// If |suggested_fields| is non-NULL, does not include |excluded_field| in the
41// list. Otherwise, |excluded_field| is ignored, and should be set to
42// |UNKNOWN_TYPE| by convention. The resulting list of fields is sorted in
43// decreasing order of importance.
44void GetFieldsForDistinguishingProfiles(
45    const std::vector<AutofillFieldType>* suggested_fields,
46    AutofillFieldType excluded_field,
47    std::vector<AutofillFieldType>* distinguishing_fields) {
48  static const AutofillFieldType kDefaultDistinguishingFields[] = {
49    NAME_FULL,
50    ADDRESS_HOME_LINE1,
51    ADDRESS_HOME_CITY,
52    ADDRESS_HOME_STATE,
53    ADDRESS_HOME_ZIP,
54    ADDRESS_HOME_COUNTRY,
55    EMAIL_ADDRESS,
56    PHONE_HOME_WHOLE_NUMBER,
57    PHONE_FAX_WHOLE_NUMBER,
58    COMPANY_NAME,
59  };
60
61  if (!suggested_fields) {
62    DCHECK_EQ(excluded_field, UNKNOWN_TYPE);
63    distinguishing_fields->assign(
64        kDefaultDistinguishingFields,
65        kDefaultDistinguishingFields + arraysize(kDefaultDistinguishingFields));
66    return;
67  }
68
69  // Keep track of which fields we've seen so that we avoid duplicate entries.
70  // Always ignore fields of unknown type and the excluded field.
71  std::set<AutofillFieldType> seen_fields;
72  seen_fields.insert(UNKNOWN_TYPE);
73  seen_fields.insert(GetEquivalentFieldTypeCollapsingNames(excluded_field));
74
75  distinguishing_fields->clear();
76  for (std::vector<AutofillFieldType>::const_iterator it =
77           suggested_fields->begin();
78       it != suggested_fields->end(); ++it) {
79    AutofillFieldType suggested_type =
80        GetEquivalentFieldTypeCollapsingNames(*it);
81    if (seen_fields.insert(suggested_type).second)
82      distinguishing_fields->push_back(suggested_type);
83  }
84
85  // Special case: If the excluded field is a partial name (e.g. first name) and
86  // the suggested fields include other name fields, include |NAME_FULL| in the
87  // list of distinguishing fields as a last-ditch fallback. This allows us to
88  // distinguish between profiles that are identical except for the name.
89  if (excluded_field != NAME_FULL &&
90      GetEquivalentFieldTypeCollapsingNames(excluded_field) == NAME_FULL) {
91    for (std::vector<AutofillFieldType>::const_iterator it =
92             suggested_fields->begin();
93         it != suggested_fields->end(); ++it) {
94      if (*it != excluded_field &&
95          GetEquivalentFieldTypeCollapsingNames(*it) == NAME_FULL) {
96        distinguishing_fields->push_back(NAME_FULL);
97        break;
98      }
99    }
100  }
101}
102
103// A helper function for string streaming.  Concatenates multi-valued entries
104// stored for a given |type| into a single string.  This string is returned.
105const string16 MultiString(const AutofillProfile& p, AutofillFieldType type) {
106  std::vector<string16> values;
107  p.GetMultiInfo(type, &values);
108  string16 accumulate;
109  for (size_t i = 0; i < values.size(); ++i) {
110    if (i > 0)
111      accumulate += ASCIIToUTF16(" ");
112    accumulate += values[i];
113  }
114  return accumulate;
115}
116
117template <class T>
118void CopyValuesToItems(AutofillFieldType type,
119                       const std::vector<string16>& values,
120                       std::vector<T>* form_group_items) {
121  form_group_items->resize(values.size());
122  for (size_t i = 0; i < form_group_items->size(); ++i)
123    (*form_group_items)[i].SetInfo(type, CollapseWhitespace(values[i], false));
124  // Must have at least one (possibly empty) element.
125  if (form_group_items->empty())
126    form_group_items->resize(1);
127}
128
129template <class T>
130void CopyItemsToValues(AutofillFieldType type,
131                       const std::vector<T>& form_group_items,
132                       std::vector<string16>* values) {
133  values->resize(form_group_items.size());
134  for (size_t i = 0; i < values->size(); ++i)
135    (*values)[i] = form_group_items[i].GetInfo(type);
136}
137
138// Collapse compound field types to their "full" type.  I.e. First name
139// collapses to full name, area code collapses to full phone, etc.
140void CollapseCompoundFieldTypes(FieldTypeSet* type_set) {
141  FieldTypeSet collapsed_set;
142  for (FieldTypeSet::iterator iter = type_set->begin(); iter != type_set->end();
143       ++iter) {
144    switch (*iter) {
145      case NAME_FIRST:
146      case NAME_MIDDLE:
147      case NAME_LAST:
148      case NAME_MIDDLE_INITIAL:
149      case NAME_FULL:
150      case NAME_SUFFIX:
151        collapsed_set.insert(NAME_FULL);
152        break;
153
154      case PHONE_HOME_NUMBER:
155      case PHONE_HOME_CITY_CODE:
156      case PHONE_HOME_COUNTRY_CODE:
157      case PHONE_HOME_CITY_AND_NUMBER:
158      case PHONE_HOME_WHOLE_NUMBER:
159        collapsed_set.insert(PHONE_HOME_WHOLE_NUMBER);
160        break;
161
162      case PHONE_FAX_NUMBER:
163      case PHONE_FAX_CITY_CODE:
164      case PHONE_FAX_COUNTRY_CODE:
165      case PHONE_FAX_CITY_AND_NUMBER:
166      case PHONE_FAX_WHOLE_NUMBER:
167        collapsed_set.insert(PHONE_FAX_WHOLE_NUMBER);
168        break;
169
170      default:
171        collapsed_set.insert(*iter);
172    }
173  }
174  std::swap(*type_set, collapsed_set);
175}
176
177}  // namespace
178
179AutofillProfile::AutofillProfile(const std::string& guid)
180    : guid_(guid), name_(1), email_(1), home_number_(1), fax_number_(1) {
181}
182
183AutofillProfile::AutofillProfile()
184    : guid_(guid::GenerateGUID()),
185      name_(1),
186      email_(1),
187      home_number_(1),
188      fax_number_(1) {
189}
190
191AutofillProfile::AutofillProfile(const AutofillProfile& profile)
192    : FormGroup() {
193  operator=(profile);
194}
195
196AutofillProfile::~AutofillProfile() {
197}
198
199AutofillProfile& AutofillProfile::operator=(const AutofillProfile& profile) {
200  if (this == &profile)
201    return *this;
202
203  label_ = profile.label_;
204  guid_ = profile.guid_;
205
206  name_ = profile.name_;
207  email_ = profile.email_;
208  company_ = profile.company_;
209  home_number_ = profile.home_number_;
210  fax_number_ = profile.fax_number_;
211  address_ = profile.address_;
212
213  return *this;
214}
215
216void AutofillProfile::GetPossibleFieldTypes(
217    const string16& text,
218    FieldTypeSet* possible_types) const {
219  FormGroupList info = FormGroups();
220  for (FormGroupList::const_iterator it = info.begin(); it != info.end(); ++it)
221    (*it)->GetPossibleFieldTypes(text, possible_types);
222}
223
224void AutofillProfile::GetAvailableFieldTypes(
225    FieldTypeSet* available_types) const {
226  FormGroupList info = FormGroups();
227  for (FormGroupList::const_iterator it = info.begin(); it != info.end(); ++it)
228    (*it)->GetAvailableFieldTypes(available_types);
229}
230
231string16 AutofillProfile::GetInfo(AutofillFieldType type) const {
232  AutofillFieldType return_type = AutofillType::GetEquivalentFieldType(type);
233  const FormGroup* form_group = FormGroupForType(return_type);
234  if (!form_group)
235    return string16();
236
237  return form_group->GetInfo(return_type);
238}
239
240void AutofillProfile::SetInfo(AutofillFieldType type, const string16& value) {
241  FormGroup* form_group = MutableFormGroupForType(type);
242  if (form_group)
243    form_group->SetInfo(type, CollapseWhitespace(value, false));
244}
245
246void AutofillProfile::SetMultiInfo(AutofillFieldType type,
247                                   const std::vector<string16>& values) {
248  switch (AutofillType(type).group()) {
249    case AutofillType::NAME:
250      CopyValuesToItems(type, values, &name_);
251      break;
252    case AutofillType::EMAIL:
253      CopyValuesToItems(type, values, &email_);
254      break;
255    case AutofillType::PHONE_HOME:
256      CopyValuesToItems(type, values, &home_number_);
257      break;
258    case AutofillType::PHONE_FAX:
259      CopyValuesToItems(type, values, &fax_number_);
260      break;
261    default:
262      if (values.size() == 1) {
263        SetInfo(type, values[0]);
264      } else if (values.size() == 0) {
265        SetInfo(type, string16());
266      } else {
267        NOTREACHED()
268            << "Attempt to set multiple values on single-valued field.";
269      }
270      break;
271  }
272}
273
274void AutofillProfile::GetMultiInfo(AutofillFieldType type,
275                                   std::vector<string16>* values) const {
276  switch (AutofillType(type).group()) {
277    case AutofillType::NAME:
278      CopyItemsToValues(type, name_, values);
279      break;
280    case AutofillType::EMAIL:
281      CopyItemsToValues(type, email_, values);
282      break;
283    case AutofillType::PHONE_HOME:
284      CopyItemsToValues(type, home_number_, values);
285      break;
286    case AutofillType::PHONE_FAX:
287      CopyItemsToValues(type, fax_number_, values);
288      break;
289    default:
290      values->resize(1);
291      (*values)[0] = GetInfo(type);
292  }
293}
294
295// static
296bool AutofillProfile::SupportsMultiValue(AutofillFieldType type) {
297  AutofillType::FieldTypeGroup group = AutofillType(type).group();
298  return group == AutofillType::NAME ||
299         group == AutofillType::EMAIL ||
300         group == AutofillType::PHONE_HOME ||
301         group == AutofillType::PHONE_FAX;
302}
303
304const string16 AutofillProfile::Label() const {
305  return label_;
306}
307
308const std::string AutofillProfile::CountryCode() const {
309  return address_.country_code();
310}
311
312void AutofillProfile::SetCountryCode(const std::string& country_code) {
313  address_.set_country_code(country_code);
314}
315
316// static
317bool AutofillProfile::AdjustInferredLabels(
318    std::vector<AutofillProfile*>* profiles) {
319  const size_t kMinimalFieldsShown = 2;
320
321  std::vector<string16> created_labels;
322  CreateInferredLabels(profiles, NULL, UNKNOWN_TYPE, kMinimalFieldsShown,
323                       &created_labels);
324  DCHECK_EQ(profiles->size(), created_labels.size());
325
326  bool updated_labels = false;
327  for (size_t i = 0; i < profiles->size(); ++i) {
328    if ((*profiles)[i]->Label() != created_labels[i]) {
329      updated_labels = true;
330      (*profiles)[i]->label_ = created_labels[i];
331    }
332  }
333  return updated_labels;
334}
335
336// static
337void AutofillProfile::CreateInferredLabels(
338    const std::vector<AutofillProfile*>* profiles,
339    const std::vector<AutofillFieldType>* suggested_fields,
340    AutofillFieldType excluded_field,
341    size_t minimal_fields_shown,
342    std::vector<string16>* created_labels) {
343  DCHECK(profiles);
344  DCHECK(created_labels);
345
346  std::vector<AutofillFieldType> fields_to_use;
347  GetFieldsForDistinguishingProfiles(suggested_fields, excluded_field,
348                                     &fields_to_use);
349
350  // Construct the default label for each profile. Also construct a map that
351  // associates each label with the profiles that have this label. This map is
352  // then used to detect which labels need further differentiating fields.
353  std::map<string16, std::list<size_t> > labels;
354  for (size_t i = 0; i < profiles->size(); ++i) {
355    string16 label =
356        (*profiles)[i]->ConstructInferredLabel(fields_to_use,
357                                               minimal_fields_shown);
358    labels[label].push_back(i);
359  }
360
361  created_labels->resize(profiles->size());
362  for (std::map<string16, std::list<size_t> >::const_iterator it =
363           labels.begin();
364       it != labels.end(); ++it) {
365    if (it->second.size() == 1) {
366      // This label is unique, so use it without any further ado.
367      string16 label = it->first;
368      size_t profile_index = it->second.front();
369      (*created_labels)[profile_index] = label;
370    } else {
371      // We have more than one profile with the same label, so add
372      // differentiating fields.
373      CreateDifferentiatingLabels(*profiles, it->second, fields_to_use,
374                                  minimal_fields_shown, created_labels);
375    }
376  }
377}
378
379bool AutofillProfile::IsEmpty() const {
380  FieldTypeSet types;
381  GetAvailableFieldTypes(&types);
382  return types.empty();
383}
384
385int AutofillProfile::Compare(const AutofillProfile& profile) const {
386  // The following Autofill field types are the only types we store in the WebDB
387  // so far, so we're only concerned with matching these types in the profile.
388  const AutofillFieldType types[] = { NAME_FIRST,
389                                      NAME_MIDDLE,
390                                      NAME_LAST,
391                                      EMAIL_ADDRESS,
392                                      COMPANY_NAME,
393                                      ADDRESS_HOME_LINE1,
394                                      ADDRESS_HOME_LINE2,
395                                      ADDRESS_HOME_CITY,
396                                      ADDRESS_HOME_STATE,
397                                      ADDRESS_HOME_ZIP,
398                                      ADDRESS_HOME_COUNTRY,
399                                      PHONE_HOME_NUMBER,
400                                      PHONE_FAX_NUMBER };
401
402  for (size_t index = 0; index < arraysize(types); ++index) {
403    int comparison = GetInfo(types[index]).compare(
404        profile.GetInfo(types[index]));
405    if (comparison != 0)
406      return comparison;
407  }
408
409  return 0;
410}
411
412int AutofillProfile::CompareMulti(const AutofillProfile& profile) const {
413  const AutofillFieldType single_value_types[] = { COMPANY_NAME,
414                                                   ADDRESS_HOME_LINE1,
415                                                   ADDRESS_HOME_LINE2,
416                                                   ADDRESS_HOME_CITY,
417                                                   ADDRESS_HOME_STATE,
418                                                   ADDRESS_HOME_ZIP,
419                                                   ADDRESS_HOME_COUNTRY };
420
421  for (size_t i = 0; i < arraysize(single_value_types); ++i) {
422    int comparison = GetInfo(single_value_types[i]).compare(
423        profile.GetInfo(single_value_types[i]));
424    if (comparison != 0)
425      return comparison;
426  }
427
428  const AutofillFieldType multi_value_types[] = { NAME_FIRST,
429                                                  NAME_MIDDLE,
430                                                  NAME_LAST,
431                                                  EMAIL_ADDRESS,
432                                                  PHONE_HOME_NUMBER,
433                                                  PHONE_FAX_NUMBER };
434
435  for (size_t i = 0; i < arraysize(multi_value_types); ++i) {
436    std::vector<string16> values_a;
437    std::vector<string16> values_b;
438    GetMultiInfo(multi_value_types[i], &values_a);
439    profile.GetMultiInfo(multi_value_types[i], &values_b);
440    if (values_a.size() < values_b.size())
441      return -1;
442    if (values_a.size() > values_b.size())
443      return 1;
444    for (size_t j = 0; j < values_a.size(); ++j) {
445      int comparison = values_a[j].compare(values_b[j]);
446      if (comparison != 0)
447        return comparison;
448    }
449  }
450
451  return 0;
452}
453
454bool AutofillProfile::operator==(const AutofillProfile& profile) const {
455  return guid_ == profile.guid_ && Compare(profile) == 0;
456}
457
458bool AutofillProfile::operator!=(const AutofillProfile& profile) const {
459  return !operator==(profile);
460}
461
462const string16 AutofillProfile::PrimaryValue() const {
463  return GetInfo(ADDRESS_HOME_LINE1) +
464         GetInfo(ADDRESS_HOME_CITY);
465}
466
467void AutofillProfile::OverwriteWithOrAddTo(const AutofillProfile& profile) {
468  FieldTypeSet field_types;
469  profile.GetAvailableFieldTypes(&field_types);
470
471  // Only transfer "full" types (e.g. full name) and not fragments (e.g.
472  // first name, last name).
473  CollapseCompoundFieldTypes(&field_types);
474
475  for (FieldTypeSet::const_iterator iter = field_types.begin();
476       iter != field_types.end(); ++iter) {
477    if (AutofillProfile::SupportsMultiValue(*iter)) {
478      std::vector<string16> new_values;
479      profile.GetMultiInfo(*iter, &new_values);
480      std::vector<string16> existing_values;
481      GetMultiInfo(*iter, &existing_values);
482      for (std::vector<string16>::iterator value_iter = new_values.begin();
483           value_iter != new_values.end(); ++value_iter) {
484        // Don't add duplicates.
485        if (std::find(existing_values.begin(), existing_values.end(),
486                      *value_iter) == existing_values.end()) {
487          existing_values.insert(existing_values.end(), *value_iter);
488        }
489      }
490      SetMultiInfo(*iter, existing_values);
491    } else {
492      SetInfo(*iter, profile.GetInfo(*iter));
493    }
494  }
495}
496
497string16 AutofillProfile::ConstructInferredLabel(
498    const std::vector<AutofillFieldType>& included_fields,
499    size_t num_fields_to_use) const {
500  const string16 separator =
501      l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_ADDRESS_SUMMARY_SEPARATOR);
502
503  string16 label;
504  size_t num_fields_used = 0;
505  for (std::vector<AutofillFieldType>::const_iterator it =
506           included_fields.begin();
507       it != included_fields.end() && num_fields_used < num_fields_to_use;
508       ++it) {
509    string16 field = GetInfo(*it);
510    if (field.empty())
511      continue;
512
513    if (!label.empty())
514      label.append(separator);
515
516#ifndef ANDROID
517    // Fax number has special format, to indicate that this is a fax number.
518    if (*it == PHONE_FAX_WHOLE_NUMBER) {
519      field = l10n_util::GetStringFUTF16(
520          IDS_AUTOFILL_DIALOG_ADDRESS_SUMMARY_FAX_FORMAT, field);
521    }
522#endif
523    label.append(field);
524    ++num_fields_used;
525  }
526  return label;
527}
528
529// static
530void AutofillProfile::CreateDifferentiatingLabels(
531    const std::vector<AutofillProfile*>& profiles,
532    const std::list<size_t>& indices,
533    const std::vector<AutofillFieldType>& fields,
534    size_t num_fields_to_include,
535    std::vector<string16>* created_labels) {
536  // For efficiency, we first construct a map of fields to their text values and
537  // each value's frequency.
538  std::map<AutofillFieldType,
539           std::map<string16, size_t> > field_text_frequencies_by_field;
540  for (std::vector<AutofillFieldType>::const_iterator field = fields.begin();
541       field != fields.end(); ++field) {
542    std::map<string16, size_t>& field_text_frequencies =
543        field_text_frequencies_by_field[*field];
544
545    for (std::list<size_t>::const_iterator it = indices.begin();
546         it != indices.end(); ++it) {
547      const AutofillProfile* profile = profiles[*it];
548      string16 field_text = profile->GetInfo(*field);
549
550      // If this label is not already in the map, add it with frequency 0.
551      if (!field_text_frequencies.count(field_text))
552        field_text_frequencies[field_text] = 0;
553
554      // Now, increment the frequency for this label.
555      ++field_text_frequencies[field_text];
556    }
557  }
558
559  // Now comes the meat of the algorithm. For each profile, we scan the list of
560  // fields to use, looking for two things:
561  //  1. A (non-empty) field that differentiates the profile from all others
562  //  2. At least |num_fields_to_include| non-empty fields
563  // Before we've satisfied condition (2), we include all fields, even ones that
564  // are identical across all the profiles. Once we've satisfied condition (2),
565  // we only include fields that that have at last two distinct values.
566  for (std::list<size_t>::const_iterator it = indices.begin();
567       it != indices.end(); ++it) {
568    const AutofillProfile* profile = profiles[*it];
569
570    std::vector<AutofillFieldType> label_fields;
571    bool found_differentiating_field = false;
572    for (std::vector<AutofillFieldType>::const_iterator field = fields.begin();
573         field != fields.end(); ++field) {
574      // Skip over empty fields.
575      string16 field_text = profile->GetInfo(*field);
576      if (field_text.empty())
577        continue;
578
579      std::map<string16, size_t>& field_text_frequencies =
580          field_text_frequencies_by_field[*field];
581      found_differentiating_field |=
582          !field_text_frequencies.count(string16()) &&
583          (field_text_frequencies[field_text] == 1);
584
585      // Once we've found enough non-empty fields, skip over any remaining
586      // fields that are identical across all the profiles.
587      if (label_fields.size() >= num_fields_to_include &&
588          (field_text_frequencies.size() == 1))
589        continue;
590
591      label_fields.push_back(*field);
592
593      // If we've (1) found a differentiating field and (2) found at least
594      // |num_fields_to_include| non-empty fields, we're done!
595      if (found_differentiating_field &&
596          label_fields.size() >= num_fields_to_include)
597        break;
598    }
599
600    (*created_labels)[*it] =
601        profile->ConstructInferredLabel(label_fields,
602                                        label_fields.size());
603  }
604}
605
606AutofillProfile::FormGroupList AutofillProfile::FormGroups() const {
607  FormGroupList v(6);
608  v[0] = &name_[0];
609  v[1] = &email_[0];
610  v[2] = &company_;
611  v[3] = &home_number_[0];
612  v[4] = &fax_number_[0];
613  v[5] = &address_;
614  return v;
615}
616
617const FormGroup* AutofillProfile::FormGroupForType(
618    AutofillFieldType type) const {
619  return const_cast<AutofillProfile*>(this)->MutableFormGroupForType(type);
620}
621
622FormGroup* AutofillProfile::MutableFormGroupForType(AutofillFieldType type) {
623 FormGroup* form_group = NULL;
624  switch (AutofillType(type).group()) {
625    case AutofillType::NAME:
626      form_group = &name_[0];
627      break;
628    case AutofillType::EMAIL:
629      form_group = &email_[0];
630      break;
631    case AutofillType::COMPANY:
632      form_group = &company_;
633      break;
634    case AutofillType::PHONE_HOME:
635      form_group = &home_number_[0];
636      break;
637    case AutofillType::PHONE_FAX:
638      form_group = &fax_number_[0];
639      break;
640    case AutofillType::ADDRESS_HOME:
641      form_group = &address_;
642      break;
643    default:
644      break;
645  }
646  return form_group;
647}
648
649// So we can compare AutofillProfiles with EXPECT_EQ().
650std::ostream& operator<<(std::ostream& os, const AutofillProfile& profile) {
651  return os
652      << UTF16ToUTF8(profile.Label())
653      << " "
654      << profile.guid()
655      << " "
656      << UTF16ToUTF8(MultiString(profile, NAME_FIRST))
657      << " "
658      << UTF16ToUTF8(MultiString(profile, NAME_MIDDLE))
659      << " "
660      << UTF16ToUTF8(MultiString(profile, NAME_LAST))
661      << " "
662      << UTF16ToUTF8(MultiString(profile, EMAIL_ADDRESS))
663      << " "
664      << UTF16ToUTF8(profile.GetInfo(COMPANY_NAME))
665      << " "
666      << UTF16ToUTF8(profile.GetInfo(ADDRESS_HOME_LINE1))
667      << " "
668      << UTF16ToUTF8(profile.GetInfo(ADDRESS_HOME_LINE2))
669      << " "
670      << UTF16ToUTF8(profile.GetInfo(ADDRESS_HOME_CITY))
671      << " "
672      << UTF16ToUTF8(profile.GetInfo(ADDRESS_HOME_STATE))
673      << " "
674      << UTF16ToUTF8(profile.GetInfo(ADDRESS_HOME_ZIP))
675      << " "
676      << UTF16ToUTF8(profile.GetInfo(ADDRESS_HOME_COUNTRY))
677      << " "
678      << UTF16ToUTF8(MultiString(profile, PHONE_HOME_WHOLE_NUMBER))
679      << " "
680      << UTF16ToUTF8(MultiString(profile, PHONE_FAX_WHOLE_NUMBER));
681}
682