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/ui/webui/options/autofill_options_handler.h"
6
7#include <vector>
8
9#include "base/logging.h"
10#include "base/string16.h"
11#include "base/string_number_conversions.h"
12#include "base/utf_string_conversions.h"
13#include "base/values.h"
14#include "chrome/browser/autofill/autofill_country.h"
15#include "chrome/browser/autofill/autofill_profile.h"
16#include "chrome/browser/autofill/credit_card.h"
17#include "chrome/browser/profiles/profile.h"
18#include "chrome/browser/ui/webui/web_ui_util.h"
19#include "chrome/common/guid.h"
20#include "grit/generated_resources.h"
21#include "grit/webkit_resources.h"
22#include "ui/base/l10n/l10n_util.h"
23
24namespace {
25
26// Converts a credit card type to the appropriate resource ID of the CC icon.
27int CreditCardTypeToResourceID(const std::string& type) {
28  if (type == kAmericanExpressCard)
29    return IDR_AUTOFILL_CC_AMEX;
30  else if (type == kDinersCard)
31    return IDR_AUTOFILL_CC_DINERS;
32  else if (type == kDiscoverCard)
33    return IDR_AUTOFILL_CC_DISCOVER;
34  else if (type == kGenericCard)
35    return IDR_AUTOFILL_CC_GENERIC;
36  else if (type == kJCBCard)
37    return IDR_AUTOFILL_CC_JCB;
38  else if (type == kMasterCard)
39    return IDR_AUTOFILL_CC_MASTERCARD;
40  else if (type == kSoloCard)
41    return IDR_AUTOFILL_CC_SOLO;
42  else if (type == kVisaCard)
43    return IDR_AUTOFILL_CC_VISA;
44
45  NOTREACHED();
46  return 0;
47}
48
49// Converts a credit card type to the appropriate localized card type.
50string16 LocalizedCreditCardType(const std::string& type) {
51  if (type == kAmericanExpressCard)
52    return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_AMEX);
53  else if (type == kDinersCard)
54    return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_DINERS);
55  else if (type == kDiscoverCard)
56    return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_DISCOVER);
57  else if (type == kGenericCard)
58    return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_GENERIC);
59  else if (type == kJCBCard)
60    return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_JCB);
61  else if (type == kMasterCard)
62    return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_MASTERCARD);
63  else if (type == kSoloCard)
64    return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_SOLO);
65  else if (type == kVisaCard)
66    return l10n_util::GetStringUTF16(IDS_AUTOFILL_CC_VISA);
67
68  NOTREACHED();
69  return string16();
70}
71
72// Returns a dictionary that maps country codes to data for the country.
73DictionaryValue* GetCountryData() {
74  std::string app_locale = AutofillCountry::ApplicationLocale();
75  std::vector<std::string> country_codes;
76  AutofillCountry::GetAvailableCountries(&country_codes);
77
78  DictionaryValue* country_data = new DictionaryValue();
79  for (size_t i = 0; i < country_codes.size(); ++i) {
80    const AutofillCountry country(country_codes[i], app_locale);
81
82    DictionaryValue* details = new DictionaryValue();
83    details->SetString("name", country.name());
84    details->SetString("postalCodeLabel", country.postal_code_label());
85    details->SetString("stateLabel", country.state_label());
86
87    country_data->Set(country.country_code(), details);
88  }
89
90  return country_data;
91}
92
93// Get the multi-valued element for |type| and return it in |ListValue| form.
94void GetValueList(const AutofillProfile& profile,
95                  AutofillFieldType type,
96                  scoped_ptr<ListValue>* list) {
97  std::vector<string16> values;
98  profile.GetMultiInfo(type, &values);
99  list->reset(new ListValue);
100  for (size_t i = 0; i < values.size(); ++i) {
101    (*list)->Set(i, Value::CreateStringValue(values[i]));
102  }
103}
104
105// Set the multi-valued element for |type| from input |list| values.
106void SetValueList(const ListValue* list,
107                  AutofillFieldType type,
108                  AutofillProfile* profile) {
109  std::vector<string16> values(list->GetSize());
110  for (size_t i = 0; i < list->GetSize(); ++i) {
111    string16 value;
112    if (list->GetString(i, &value))
113      values[i] = value;
114  }
115  profile->SetMultiInfo(type, values);
116}
117
118}  // namespace
119
120AutofillOptionsHandler::AutofillOptionsHandler()
121    : personal_data_(NULL) {
122}
123
124AutofillOptionsHandler::~AutofillOptionsHandler() {
125  if (personal_data_)
126    personal_data_->RemoveObserver(this);
127}
128
129/////////////////////////////////////////////////////////////////////////////
130// OptionsPageUIHandler implementation:
131void AutofillOptionsHandler::GetLocalizedValues(
132    DictionaryValue* localized_strings) {
133  DCHECK(localized_strings);
134
135  static OptionsStringResource resources[] = {
136    { "autofillAddresses", IDS_AUTOFILL_ADDRESSES_GROUP_NAME },
137    { "autofillCreditCards", IDS_AUTOFILL_CREDITCARDS_GROUP_NAME },
138    { "autofillAddAddress", IDS_AUTOFILL_ADD_ADDRESS_BUTTON },
139    { "autofillAddCreditCard", IDS_AUTOFILL_ADD_CREDITCARD_BUTTON },
140    { "helpButton", IDS_AUTOFILL_HELP_LABEL },
141    { "addAddressTitle", IDS_AUTOFILL_ADD_ADDRESS_CAPTION },
142    { "editAddressTitle", IDS_AUTOFILL_EDIT_ADDRESS_CAPTION },
143    { "addCreditCardTitle", IDS_AUTOFILL_ADD_CREDITCARD_CAPTION },
144    { "editCreditCardTitle", IDS_AUTOFILL_EDIT_CREDITCARD_CAPTION },
145#if defined(OS_MACOSX)
146    { "auxiliaryProfilesEnabled", IDS_AUTOFILL_USE_MAC_ADDRESS_BOOK },
147#endif  // defined(OS_MACOSX)
148  };
149
150  RegisterStrings(localized_strings, resources, arraysize(resources));
151  RegisterTitle(localized_strings, "autofillOptionsPage",
152                IDS_AUTOFILL_OPTIONS_TITLE);
153
154  SetAddressOverlayStrings(localized_strings);
155  SetCreditCardOverlayStrings(localized_strings);
156}
157
158void AutofillOptionsHandler::Initialize() {
159  personal_data_ = web_ui_->GetProfile()->GetPersonalDataManager();
160  personal_data_->SetObserver(this);
161
162  LoadAutofillData();
163}
164
165void AutofillOptionsHandler::RegisterMessages() {
166  web_ui_->RegisterMessageCallback(
167      "removeAddress",
168      NewCallback(this, &AutofillOptionsHandler::RemoveAddress));
169  web_ui_->RegisterMessageCallback(
170      "removeCreditCard",
171      NewCallback(this, &AutofillOptionsHandler::RemoveCreditCard));
172  web_ui_->RegisterMessageCallback(
173      "loadAddressEditor",
174      NewCallback(this, &AutofillOptionsHandler::LoadAddressEditor));
175  web_ui_->RegisterMessageCallback(
176      "loadCreditCardEditor",
177      NewCallback(this, &AutofillOptionsHandler::LoadCreditCardEditor));
178  web_ui_->RegisterMessageCallback(
179      "setAddress",
180      NewCallback(this, &AutofillOptionsHandler::SetAddress));
181  web_ui_->RegisterMessageCallback(
182      "setCreditCard",
183      NewCallback(this, &AutofillOptionsHandler::SetCreditCard));
184}
185
186/////////////////////////////////////////////////////////////////////////////
187// PersonalDataManager::Observer implementation:
188void  AutofillOptionsHandler::OnPersonalDataLoaded() {
189  LoadAutofillData();
190}
191
192void AutofillOptionsHandler::OnPersonalDataChanged() {
193  LoadAutofillData();
194}
195
196void AutofillOptionsHandler::SetAddressOverlayStrings(
197    DictionaryValue* localized_strings) {
198  localized_strings->SetString("autofillEditAddressTitle",
199      l10n_util::GetStringUTF16(IDS_AUTOFILL_EDIT_ADDRESS_CAPTION));
200  localized_strings->SetString("fullNameLabel",
201      l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_FULL_NAME));
202  localized_strings->SetString("companyNameLabel",
203      l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_COMPANY_NAME));
204  localized_strings->SetString("addrLine1Label",
205      l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_ADDRESS_LINE_1));
206  localized_strings->SetString("addrLine2Label",
207      l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_ADDRESS_LINE_2));
208  localized_strings->SetString("cityLabel",
209      l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_CITY));
210  localized_strings->SetString("countryLabel",
211      l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_COUNTRY));
212  localized_strings->SetString("phoneLabel",
213      l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_PHONE));
214  localized_strings->SetString("faxLabel",
215      l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_FAX));
216  localized_strings->SetString("emailLabel",
217      l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_EMAIL));
218  localized_strings->SetString("addNewNamePlaceholder",
219      l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_ADD_NEW_NAME));
220  localized_strings->SetString("addNewPhonePlaceholder",
221      l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_ADD_NEW_PHONE));
222  localized_strings->SetString("addNewFaxPlaceholder",
223      l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_ADD_NEW_FAX));
224  localized_strings->SetString("addNewEmailPlaceholder",
225      l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_ADD_NEW_EMAIL));
226
227  std::string app_locale = AutofillCountry::ApplicationLocale();
228  std::string default_country_code =
229      AutofillCountry::CountryCodeForLocale(app_locale);
230  localized_strings->SetString("defaultCountryCode", default_country_code);
231  localized_strings->Set("autofillCountryData", GetCountryData());
232}
233
234void AutofillOptionsHandler::SetCreditCardOverlayStrings(
235    DictionaryValue* localized_strings) {
236  localized_strings->SetString("autofillEditCreditCardTitle",
237      l10n_util::GetStringUTF16(IDS_AUTOFILL_EDIT_CREDITCARD_CAPTION));
238  localized_strings->SetString("nameOnCardLabel",
239      l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_NAME_ON_CARD));
240  localized_strings->SetString("creditCardNumberLabel",
241      l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_CREDIT_CARD_NUMBER));
242  localized_strings->SetString("creditCardExpirationDateLabel",
243      l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_EXPIRATION_DATE));
244}
245
246void AutofillOptionsHandler::LoadAutofillData() {
247  if (!personal_data_->IsDataLoaded())
248    return;
249
250  ListValue addresses;
251  for (std::vector<AutofillProfile*>::const_iterator i =
252           personal_data_->web_profiles().begin();
253       i != personal_data_->web_profiles().end(); ++i) {
254    ListValue* entry = new ListValue();
255    entry->Append(new StringValue((*i)->guid()));
256    entry->Append(new StringValue((*i)->Label()));
257    addresses.Append(entry);
258  }
259
260  web_ui_->CallJavascriptFunction("AutofillOptions.setAddressList", addresses);
261
262  ListValue credit_cards;
263  for (std::vector<CreditCard*>::const_iterator i =
264           personal_data_->credit_cards().begin();
265       i != personal_data_->credit_cards().end(); ++i) {
266    ListValue* entry = new ListValue();
267    entry->Append(new StringValue((*i)->guid()));
268    entry->Append(new StringValue((*i)->Label()));
269    int res = CreditCardTypeToResourceID((*i)->type());
270    entry->Append(
271        new StringValue(web_ui_util::GetImageDataUrlFromResource(res)));
272    entry->Append(new StringValue(LocalizedCreditCardType((*i)->type())));
273    credit_cards.Append(entry);
274  }
275
276  web_ui_->CallJavascriptFunction("AutofillOptions.setCreditCardList",
277                                  credit_cards);
278}
279
280void AutofillOptionsHandler::RemoveAddress(const ListValue* args) {
281  DCHECK(personal_data_->IsDataLoaded());
282
283  std::string guid;
284  if (!args->GetString(0, &guid)) {
285    NOTREACHED();
286    return;
287  }
288
289  personal_data_->RemoveProfile(guid);
290}
291
292void AutofillOptionsHandler::RemoveCreditCard(const ListValue* args) {
293  DCHECK(personal_data_->IsDataLoaded());
294
295  std::string guid;
296  if (!args->GetString(0, &guid)) {
297    NOTREACHED();
298    return;
299  }
300
301  personal_data_->RemoveCreditCard(guid);
302}
303
304void AutofillOptionsHandler::LoadAddressEditor(const ListValue* args) {
305  DCHECK(personal_data_->IsDataLoaded());
306
307  std::string guid;
308  if (!args->GetString(0, &guid)) {
309    NOTREACHED();
310    return;
311  }
312
313  AutofillProfile* profile = personal_data_->GetProfileByGUID(guid);
314  if (!profile) {
315    // There is a race where a user can click once on the close button and
316    // quickly click again on the list item before the item is removed (since
317    // the list is not updated until the model tells the list an item has been
318    // removed). This will activate the editor for a profile that has been
319    // removed. Do nothing in that case.
320    return;
321  }
322
323  DictionaryValue address;
324  address.SetString("guid", profile->guid());
325  scoped_ptr<ListValue> list;
326  GetValueList(*profile, NAME_FULL, &list);
327  address.Set("fullName", list.release());
328  address.SetString("companyName", profile->GetInfo(COMPANY_NAME));
329  address.SetString("addrLine1", profile->GetInfo(ADDRESS_HOME_LINE1));
330  address.SetString("addrLine2", profile->GetInfo(ADDRESS_HOME_LINE2));
331  address.SetString("city", profile->GetInfo(ADDRESS_HOME_CITY));
332  address.SetString("state", profile->GetInfo(ADDRESS_HOME_STATE));
333  address.SetString("postalCode", profile->GetInfo(ADDRESS_HOME_ZIP));
334  address.SetString("country", profile->CountryCode());
335  GetValueList(*profile, PHONE_HOME_WHOLE_NUMBER, &list);
336  address.Set("phone", list.release());
337  GetValueList(*profile, PHONE_FAX_WHOLE_NUMBER, &list);
338  address.Set("fax", list.release());
339  GetValueList(*profile, EMAIL_ADDRESS, &list);
340  address.Set("email", list.release());
341
342  web_ui_->CallJavascriptFunction("AutofillOptions.editAddress", address);
343}
344
345void AutofillOptionsHandler::LoadCreditCardEditor(const ListValue* args) {
346  DCHECK(personal_data_->IsDataLoaded());
347
348  std::string guid;
349  if (!args->GetString(0, &guid)) {
350    NOTREACHED();
351    return;
352  }
353
354  CreditCard* credit_card = personal_data_->GetCreditCardByGUID(guid);
355  if (!credit_card) {
356    // There is a race where a user can click once on the close button and
357    // quickly click again on the list item before the item is removed (since
358    // the list is not updated until the model tells the list an item has been
359    // removed). This will activate the editor for a profile that has been
360    // removed. Do nothing in that case.
361    return;
362  }
363
364  DictionaryValue credit_card_data;
365  credit_card_data.SetString("guid", credit_card->guid());
366  credit_card_data.SetString("nameOnCard",
367                             credit_card->GetInfo(CREDIT_CARD_NAME));
368  credit_card_data.SetString("creditCardNumber",
369                             credit_card->GetInfo(CREDIT_CARD_NUMBER));
370  credit_card_data.SetString("expirationMonth",
371                             credit_card->GetInfo(CREDIT_CARD_EXP_MONTH));
372  credit_card_data.SetString(
373      "expirationYear",
374      credit_card->GetInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR));
375
376  web_ui_->CallJavascriptFunction("AutofillOptions.editCreditCard",
377                                  credit_card_data);
378}
379
380void AutofillOptionsHandler::SetAddress(const ListValue* args) {
381  if (!personal_data_->IsDataLoaded())
382    return;
383
384  std::string guid;
385  if (!args->GetString(0, &guid)) {
386    NOTREACHED();
387    return;
388  }
389
390  AutofillProfile profile(guid);
391
392  std::string country_code;
393  string16 value;
394  ListValue* list_value;
395  if (args->GetList(1, &list_value))
396    SetValueList(list_value, NAME_FULL, &profile);
397  if (args->GetString(2, &value))
398    profile.SetInfo(COMPANY_NAME, value);
399  if (args->GetString(3, &value))
400    profile.SetInfo(ADDRESS_HOME_LINE1, value);
401  if (args->GetString(4, &value))
402    profile.SetInfo(ADDRESS_HOME_LINE2, value);
403  if (args->GetString(5, &value))
404    profile.SetInfo(ADDRESS_HOME_CITY, value);
405  if (args->GetString(6, &value))
406    profile.SetInfo(ADDRESS_HOME_STATE, value);
407  if (args->GetString(7, &value))
408    profile.SetInfo(ADDRESS_HOME_ZIP, value);
409  if (args->GetString(8, &country_code))
410    profile.SetCountryCode(country_code);
411  if (args->GetList(9, &list_value))
412    SetValueList(list_value, PHONE_HOME_WHOLE_NUMBER, &profile);
413  if (args->GetList(10, &list_value))
414    SetValueList(list_value, PHONE_FAX_WHOLE_NUMBER, &profile);
415  if (args->GetList(11, &list_value))
416    SetValueList(list_value, EMAIL_ADDRESS, &profile);
417
418  if (!guid::IsValidGUID(profile.guid())) {
419    profile.set_guid(guid::GenerateGUID());
420    personal_data_->AddProfile(profile);
421  } else {
422    personal_data_->UpdateProfile(profile);
423  }
424}
425
426void AutofillOptionsHandler::SetCreditCard(const ListValue* args) {
427  if (!personal_data_->IsDataLoaded())
428    return;
429
430  std::string guid;
431  if (!args->GetString(0, &guid)) {
432    NOTREACHED();
433    return;
434  }
435
436  CreditCard credit_card(guid);
437
438  string16 value;
439  if (args->GetString(1, &value))
440    credit_card.SetInfo(CREDIT_CARD_NAME, value);
441  if (args->GetString(2, &value))
442    credit_card.SetInfo(CREDIT_CARD_NUMBER, value);
443  if (args->GetString(3, &value))
444    credit_card.SetInfo(CREDIT_CARD_EXP_MONTH, value);
445  if (args->GetString(4, &value))
446    credit_card.SetInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, value);
447
448  if (!guid::IsValidGUID(credit_card.guid())) {
449    credit_card.set_guid(guid::GenerateGUID());
450    personal_data_->AddCreditCard(credit_card);
451  } else {
452    personal_data_->UpdateCreditCard(credit_card);
453  }
454}
455