Home | History | Annotate | Download | only in syncable
      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
      3 // found in the LICENSE file.
      4 
      5 #include "sync/internal_api/public/base/model_type.h"
      6 
      7 #include "base/strings/string_split.h"
      8 #include "base/values.h"
      9 #include "sync/protocol/app_notification_specifics.pb.h"
     10 #include "sync/protocol/app_setting_specifics.pb.h"
     11 #include "sync/protocol/app_specifics.pb.h"
     12 #include "sync/protocol/autofill_specifics.pb.h"
     13 #include "sync/protocol/bookmark_specifics.pb.h"
     14 #include "sync/protocol/extension_setting_specifics.pb.h"
     15 #include "sync/protocol/extension_specifics.pb.h"
     16 #include "sync/protocol/nigori_specifics.pb.h"
     17 #include "sync/protocol/password_specifics.pb.h"
     18 #include "sync/protocol/preference_specifics.pb.h"
     19 #include "sync/protocol/search_engine_specifics.pb.h"
     20 #include "sync/protocol/session_specifics.pb.h"
     21 #include "sync/protocol/sync.pb.h"
     22 #include "sync/protocol/theme_specifics.pb.h"
     23 #include "sync/protocol/typed_url_specifics.pb.h"
     24 #include "sync/syncable/syncable_proto_util.h"
     25 
     26 namespace syncer {
     27 
     28 void AddDefaultFieldValue(ModelType datatype,
     29                           sync_pb::EntitySpecifics* specifics) {
     30   if (!ProtocolTypes().Has(datatype)) {
     31     NOTREACHED() << "Only protocol types have field values.";
     32     return;
     33   }
     34   switch (datatype) {
     35     case BOOKMARKS:
     36       specifics->mutable_bookmark();
     37       break;
     38     case PASSWORDS:
     39       specifics->mutable_password();
     40       break;
     41     case PREFERENCES:
     42       specifics->mutable_preference();
     43       break;
     44     case AUTOFILL:
     45       specifics->mutable_autofill();
     46       break;
     47     case AUTOFILL_PROFILE:
     48       specifics->mutable_autofill_profile();
     49       break;
     50     case THEMES:
     51       specifics->mutable_theme();
     52       break;
     53     case TYPED_URLS:
     54       specifics->mutable_typed_url();
     55       break;
     56     case EXTENSIONS:
     57       specifics->mutable_extension();
     58       break;
     59     case NIGORI:
     60       specifics->mutable_nigori();
     61       break;
     62     case SEARCH_ENGINES:
     63       specifics->mutable_search_engine();
     64       break;
     65     case SESSIONS:
     66       specifics->mutable_session();
     67       break;
     68     case APPS:
     69       specifics->mutable_app();
     70       break;
     71     case APP_LIST:
     72       specifics->mutable_app_list();
     73       break;
     74     case APP_SETTINGS:
     75       specifics->mutable_app_setting();
     76       break;
     77     case EXTENSION_SETTINGS:
     78       specifics->mutable_extension_setting();
     79       break;
     80     case APP_NOTIFICATIONS:
     81       specifics->mutable_app_notification();
     82       break;
     83     case HISTORY_DELETE_DIRECTIVES:
     84       specifics->mutable_history_delete_directive();
     85       break;
     86     case SYNCED_NOTIFICATIONS:
     87       specifics->mutable_synced_notification();
     88       break;
     89     case SYNCED_NOTIFICATION_APP_INFO:
     90       specifics->mutable_synced_notification_app_info();
     91       break;
     92     case DEVICE_INFO:
     93       specifics->mutable_device_info();
     94       break;
     95     case EXPERIMENTS:
     96       specifics->mutable_experiments();
     97       break;
     98     case PRIORITY_PREFERENCES:
     99       specifics->mutable_priority_preference();
    100       break;
    101     case DICTIONARY:
    102       specifics->mutable_dictionary();
    103       break;
    104     case FAVICON_IMAGES:
    105       specifics->mutable_favicon_image();
    106       break;
    107     case FAVICON_TRACKING:
    108       specifics->mutable_favicon_tracking();
    109       break;
    110     case SUPERVISED_USER_SETTINGS:
    111       specifics->mutable_managed_user_setting();
    112       break;
    113     case SUPERVISED_USERS:
    114       specifics->mutable_managed_user();
    115       break;
    116     case SUPERVISED_USER_SHARED_SETTINGS:
    117       specifics->mutable_managed_user_shared_setting();
    118       break;
    119     case ARTICLES:
    120       specifics->mutable_article();
    121       break;
    122     default:
    123       NOTREACHED() << "No known extension for model type.";
    124   }
    125 }
    126 
    127 ModelType GetModelTypeFromSpecificsFieldNumber(int field_number) {
    128   ModelTypeSet protocol_types = ProtocolTypes();
    129   for (ModelTypeSet::Iterator iter = protocol_types.First(); iter.Good();
    130        iter.Inc()) {
    131     if (GetSpecificsFieldNumberFromModelType(iter.Get()) == field_number)
    132       return iter.Get();
    133   }
    134   return UNSPECIFIED;
    135 }
    136 
    137 int GetSpecificsFieldNumberFromModelType(ModelType model_type) {
    138   DCHECK(ProtocolTypes().Has(model_type))
    139       << "Only protocol types have field values.";
    140   switch (model_type) {
    141     case BOOKMARKS:
    142       return sync_pb::EntitySpecifics::kBookmarkFieldNumber;
    143     case PASSWORDS:
    144       return sync_pb::EntitySpecifics::kPasswordFieldNumber;
    145     case PREFERENCES:
    146       return sync_pb::EntitySpecifics::kPreferenceFieldNumber;
    147     case AUTOFILL:
    148       return sync_pb::EntitySpecifics::kAutofillFieldNumber;
    149     case AUTOFILL_PROFILE:
    150       return sync_pb::EntitySpecifics::kAutofillProfileFieldNumber;
    151     case THEMES:
    152       return sync_pb::EntitySpecifics::kThemeFieldNumber;
    153     case TYPED_URLS:
    154       return sync_pb::EntitySpecifics::kTypedUrlFieldNumber;
    155     case EXTENSIONS:
    156       return sync_pb::EntitySpecifics::kExtensionFieldNumber;
    157     case NIGORI:
    158       return sync_pb::EntitySpecifics::kNigoriFieldNumber;
    159     case SEARCH_ENGINES:
    160       return sync_pb::EntitySpecifics::kSearchEngineFieldNumber;
    161     case SESSIONS:
    162       return sync_pb::EntitySpecifics::kSessionFieldNumber;
    163     case APPS:
    164       return sync_pb::EntitySpecifics::kAppFieldNumber;
    165     case APP_LIST:
    166       return sync_pb::EntitySpecifics::kAppListFieldNumber;
    167     case APP_SETTINGS:
    168       return sync_pb::EntitySpecifics::kAppSettingFieldNumber;
    169     case EXTENSION_SETTINGS:
    170       return sync_pb::EntitySpecifics::kExtensionSettingFieldNumber;
    171     case APP_NOTIFICATIONS:
    172       return sync_pb::EntitySpecifics::kAppNotificationFieldNumber;
    173     case HISTORY_DELETE_DIRECTIVES:
    174       return sync_pb::EntitySpecifics::kHistoryDeleteDirectiveFieldNumber;
    175     case SYNCED_NOTIFICATIONS:
    176       return sync_pb::EntitySpecifics::kSyncedNotificationFieldNumber;
    177     case SYNCED_NOTIFICATION_APP_INFO:
    178       return sync_pb::EntitySpecifics::kSyncedNotificationAppInfoFieldNumber;
    179     case DEVICE_INFO:
    180       return sync_pb::EntitySpecifics::kDeviceInfoFieldNumber;
    181     case EXPERIMENTS:
    182       return sync_pb::EntitySpecifics::kExperimentsFieldNumber;
    183     case PRIORITY_PREFERENCES:
    184       return sync_pb::EntitySpecifics::kPriorityPreferenceFieldNumber;
    185     case DICTIONARY:
    186       return sync_pb::EntitySpecifics::kDictionaryFieldNumber;
    187     case FAVICON_IMAGES:
    188       return sync_pb::EntitySpecifics::kFaviconImageFieldNumber;
    189     case FAVICON_TRACKING:
    190       return sync_pb::EntitySpecifics::kFaviconTrackingFieldNumber;
    191     case SUPERVISED_USER_SETTINGS:
    192       return sync_pb::EntitySpecifics::kManagedUserSettingFieldNumber;
    193     case SUPERVISED_USERS:
    194       return sync_pb::EntitySpecifics::kManagedUserFieldNumber;
    195     case SUPERVISED_USER_SHARED_SETTINGS:
    196       return sync_pb::EntitySpecifics::kManagedUserSharedSettingFieldNumber;
    197     case ARTICLES:
    198       return sync_pb::EntitySpecifics::kArticleFieldNumber;
    199     default:
    200       NOTREACHED() << "No known extension for model type.";
    201       return 0;
    202   }
    203 }
    204 
    205 FullModelTypeSet ToFullModelTypeSet(ModelTypeSet in) {
    206   FullModelTypeSet out;
    207   for (ModelTypeSet::Iterator i = in.First(); i.Good(); i.Inc()) {
    208     out.Put(i.Get());
    209   }
    210   return out;
    211 }
    212 
    213 // Note: keep this consistent with GetModelType in entry.cc!
    214 ModelType GetModelType(const sync_pb::SyncEntity& sync_entity) {
    215   DCHECK(!IsRoot(sync_entity));  // Root shouldn't ever go over the wire.
    216 
    217   // Backwards compatibility with old (pre-specifics) protocol.
    218   if (sync_entity.has_bookmarkdata())
    219     return BOOKMARKS;
    220 
    221   ModelType specifics_type = GetModelTypeFromSpecifics(sync_entity.specifics());
    222   if (specifics_type != UNSPECIFIED)
    223     return specifics_type;
    224 
    225   // Loose check for server-created top-level folders that aren't
    226   // bound to a particular model type.
    227   if (!sync_entity.server_defined_unique_tag().empty() &&
    228       IsFolder(sync_entity)) {
    229     return TOP_LEVEL_FOLDER;
    230   }
    231 
    232   // This is an item of a datatype we can't understand. Maybe it's
    233   // from the future?  Either we mis-encoded the object, or the
    234   // server sent us entries it shouldn't have.
    235   NOTREACHED() << "Unknown datatype in sync proto.";
    236   return UNSPECIFIED;
    237 }
    238 
    239 ModelType GetModelTypeFromSpecifics(const sync_pb::EntitySpecifics& specifics) {
    240   if (specifics.has_bookmark())
    241     return BOOKMARKS;
    242 
    243   if (specifics.has_password())
    244     return PASSWORDS;
    245 
    246   if (specifics.has_preference())
    247     return PREFERENCES;
    248 
    249   if (specifics.has_autofill())
    250     return AUTOFILL;
    251 
    252   if (specifics.has_autofill_profile())
    253     return AUTOFILL_PROFILE;
    254 
    255   if (specifics.has_theme())
    256     return THEMES;
    257 
    258   if (specifics.has_typed_url())
    259     return TYPED_URLS;
    260 
    261   if (specifics.has_extension())
    262     return EXTENSIONS;
    263 
    264   if (specifics.has_nigori())
    265     return NIGORI;
    266 
    267   if (specifics.has_app())
    268     return APPS;
    269 
    270   if (specifics.has_app_list())
    271     return APP_LIST;
    272 
    273   if (specifics.has_search_engine())
    274     return SEARCH_ENGINES;
    275 
    276   if (specifics.has_session())
    277     return SESSIONS;
    278 
    279   if (specifics.has_app_setting())
    280     return APP_SETTINGS;
    281 
    282   if (specifics.has_extension_setting())
    283     return EXTENSION_SETTINGS;
    284 
    285   if (specifics.has_app_notification())
    286     return APP_NOTIFICATIONS;
    287 
    288   if (specifics.has_history_delete_directive())
    289     return HISTORY_DELETE_DIRECTIVES;
    290 
    291   if (specifics.has_synced_notification())
    292     return SYNCED_NOTIFICATIONS;
    293 
    294   if (specifics.has_synced_notification_app_info())
    295     return SYNCED_NOTIFICATION_APP_INFO;
    296 
    297   if (specifics.has_device_info())
    298     return DEVICE_INFO;
    299 
    300   if (specifics.has_experiments())
    301     return EXPERIMENTS;
    302 
    303   if (specifics.has_priority_preference())
    304     return PRIORITY_PREFERENCES;
    305 
    306   if (specifics.has_dictionary())
    307     return DICTIONARY;
    308 
    309   if (specifics.has_favicon_image())
    310     return FAVICON_IMAGES;
    311 
    312   if (specifics.has_favicon_tracking())
    313     return FAVICON_TRACKING;
    314 
    315   if (specifics.has_managed_user_setting())
    316     return SUPERVISED_USER_SETTINGS;
    317 
    318   if (specifics.has_managed_user())
    319     return SUPERVISED_USERS;
    320 
    321   if (specifics.has_managed_user_shared_setting())
    322     return SUPERVISED_USER_SHARED_SETTINGS;
    323 
    324   if (specifics.has_article())
    325     return ARTICLES;
    326 
    327   return UNSPECIFIED;
    328 }
    329 
    330 ModelTypeSet ProtocolTypes() {
    331   ModelTypeSet set = ModelTypeSet::All();
    332   set.RemoveAll(ProxyTypes());
    333   return set;
    334 }
    335 
    336 ModelTypeSet UserTypes() {
    337   ModelTypeSet set;
    338   // TODO(sync): We should be able to build the actual enumset's internal
    339   // bitset value here at compile time, rather than performing an iteration
    340   // every time.
    341   for (int i = FIRST_USER_MODEL_TYPE; i <= LAST_USER_MODEL_TYPE; ++i) {
    342     set.Put(ModelTypeFromInt(i));
    343   }
    344   return set;
    345 }
    346 
    347 ModelTypeSet UserSelectableTypes() {
    348   ModelTypeSet set;
    349   // Although the order doesn't technically matter here, it's clearer to keep
    350   // these in the same order as their definition in the ModelType enum.
    351   set.Put(BOOKMARKS);
    352   set.Put(PREFERENCES);
    353   set.Put(PASSWORDS);
    354   set.Put(AUTOFILL);
    355   set.Put(THEMES);
    356   set.Put(TYPED_URLS);
    357   set.Put(EXTENSIONS);
    358   set.Put(APPS);
    359   set.Put(PROXY_TABS);
    360   return set;
    361 }
    362 
    363 bool IsUserSelectableType(ModelType model_type) {
    364   return UserSelectableTypes().Has(model_type);
    365 }
    366 
    367 ModelTypeSet EncryptableUserTypes() {
    368   ModelTypeSet encryptable_user_types = UserTypes();
    369   // We never encrypt history delete directives.
    370   encryptable_user_types.Remove(HISTORY_DELETE_DIRECTIVES);
    371   // Synced notifications are not encrypted since the server must see changes.
    372   encryptable_user_types.Remove(SYNCED_NOTIFICATIONS);
    373   // Synced Notification App Info does not have private data, so it is not
    374   // encrypted.
    375   encryptable_user_types.Remove(SYNCED_NOTIFICATION_APP_INFO);
    376   // Priority preferences are not encrypted because they might be synced before
    377   // encryption is ready.
    378   encryptable_user_types.Remove(PRIORITY_PREFERENCES);
    379   // Supervised user settings are not encrypted since they are set server-side.
    380   encryptable_user_types.Remove(SUPERVISED_USER_SETTINGS);
    381   // Supervised users are not encrypted since they are managed server-side.
    382   encryptable_user_types.Remove(SUPERVISED_USERS);
    383   // Supervised user shared settings are not encrypted since they are managed
    384   // server-side and shared between manager and supervised user.
    385   encryptable_user_types.Remove(SUPERVISED_USER_SHARED_SETTINGS);
    386   // Proxy types have no sync representation and are therefore not encrypted.
    387   // Note however that proxy types map to one or more protocol types, which
    388   // may or may not be encrypted themselves.
    389   encryptable_user_types.RemoveAll(ProxyTypes());
    390   return encryptable_user_types;
    391 }
    392 
    393 ModelTypeSet PriorityUserTypes() {
    394   return ModelTypeSet(PRIORITY_PREFERENCES);
    395 }
    396 
    397 ModelTypeSet ControlTypes() {
    398   ModelTypeSet set;
    399   // TODO(sync): We should be able to build the actual enumset's internal
    400   // bitset value here at compile time, rather than performing an iteration
    401   // every time.
    402   for (int i = FIRST_CONTROL_MODEL_TYPE; i <= LAST_CONTROL_MODEL_TYPE; ++i) {
    403     set.Put(ModelTypeFromInt(i));
    404   }
    405 
    406   return set;
    407 }
    408 
    409 ModelTypeSet ProxyTypes() {
    410   ModelTypeSet set;
    411   set.Put(PROXY_TABS);
    412   return set;
    413 }
    414 
    415 bool IsControlType(ModelType model_type) {
    416   return ControlTypes().Has(model_type);
    417 }
    418 
    419 ModelTypeSet CoreTypes() {
    420   syncer::ModelTypeSet result;
    421   result.PutAll(PriorityCoreTypes());
    422 
    423   // The following are low priority core types.
    424   result.Put(SYNCED_NOTIFICATIONS);
    425   result.Put(SYNCED_NOTIFICATION_APP_INFO);
    426   result.Put(SUPERVISED_USER_SHARED_SETTINGS);
    427 
    428   return result;
    429 }
    430 
    431 ModelTypeSet PriorityCoreTypes() {
    432   syncer::ModelTypeSet result;
    433   result.PutAll(ControlTypes());
    434 
    435   // The following are non-control core types.
    436   result.Put(SUPERVISED_USERS);
    437 
    438   return result;
    439 }
    440 
    441 ModelTypeSet BackupTypes() {
    442   ModelTypeSet result;
    443   result.Put(BOOKMARKS);
    444   result.Put(PREFERENCES);
    445   result.Put(THEMES);
    446   result.Put(EXTENSIONS);
    447   result.Put(SEARCH_ENGINES);
    448   result.Put(APPS);
    449   result.Put(APP_LIST);
    450   result.Put(APP_SETTINGS);
    451   result.Put(EXTENSION_SETTINGS);
    452   result.Put(PRIORITY_PREFERENCES);
    453   return result;
    454 }
    455 
    456 const char* ModelTypeToString(ModelType model_type) {
    457   // This is used in serialization routines as well as for displaying debug
    458   // information.  Do not attempt to change these string values unless you know
    459   // what you're doing.
    460   switch (model_type) {
    461     case TOP_LEVEL_FOLDER:
    462       return "Top Level Folder";
    463     case UNSPECIFIED:
    464       return "Unspecified";
    465     case BOOKMARKS:
    466       return "Bookmarks";
    467     case PREFERENCES:
    468       return "Preferences";
    469     case PASSWORDS:
    470       return "Passwords";
    471     case AUTOFILL:
    472       return "Autofill";
    473     case THEMES:
    474       return "Themes";
    475     case TYPED_URLS:
    476       return "Typed URLs";
    477     case EXTENSIONS:
    478       return "Extensions";
    479     case NIGORI:
    480       return "Encryption keys";
    481     case SEARCH_ENGINES:
    482       return "Search Engines";
    483     case SESSIONS:
    484       return "Sessions";
    485     case APPS:
    486       return "Apps";
    487     case APP_LIST:
    488       return "App List";
    489     case AUTOFILL_PROFILE:
    490       return "Autofill Profiles";
    491     case APP_SETTINGS:
    492       return "App settings";
    493     case EXTENSION_SETTINGS:
    494       return "Extension settings";
    495     case APP_NOTIFICATIONS:
    496       return "App Notifications";
    497     case HISTORY_DELETE_DIRECTIVES:
    498       return "History Delete Directives";
    499     case SYNCED_NOTIFICATIONS:
    500       return "Synced Notifications";
    501     case SYNCED_NOTIFICATION_APP_INFO:
    502       return "Synced Notification App Info";
    503     case DEVICE_INFO:
    504       return "Device Info";
    505     case EXPERIMENTS:
    506       return "Experiments";
    507     case PRIORITY_PREFERENCES:
    508       return "Priority Preferences";
    509     case DICTIONARY:
    510       return "Dictionary";
    511     case FAVICON_IMAGES:
    512       return "Favicon Images";
    513     case FAVICON_TRACKING:
    514       return "Favicon Tracking";
    515     case SUPERVISED_USER_SETTINGS:
    516       return "Managed User Settings";
    517     case SUPERVISED_USERS:
    518       return "Managed Users";
    519     case SUPERVISED_USER_SHARED_SETTINGS:
    520       return "Managed User Shared Settings";
    521     case ARTICLES:
    522       return "Articles";
    523     case PROXY_TABS:
    524       return "Tabs";
    525     default:
    526       break;
    527   }
    528   NOTREACHED() << "No known extension for model type.";
    529   return "INVALID";
    530 }
    531 
    532 // The normal rules about histograms apply here.  Always append to the bottom of
    533 // the list, and be careful to not reuse integer values that have already been
    534 // assigned.  Don't forget to update histograms.xml when you make changes to
    535 // this list.
    536 int ModelTypeToHistogramInt(ModelType model_type) {
    537   switch (model_type) {
    538     case UNSPECIFIED:
    539       return 0;
    540     case TOP_LEVEL_FOLDER:
    541       return 1;
    542     case BOOKMARKS:
    543       return 2;
    544     case PREFERENCES:
    545       return 3;
    546     case PASSWORDS:
    547       return 4;
    548     case AUTOFILL_PROFILE:
    549       return 5;
    550     case AUTOFILL:
    551       return 6;
    552     case THEMES:
    553       return 7;
    554     case TYPED_URLS:
    555       return 8;
    556     case EXTENSIONS:
    557       return 9;
    558     case SEARCH_ENGINES:
    559       return 10;
    560     case SESSIONS:
    561       return 11;
    562     case APPS:
    563       return 12;
    564     case APP_SETTINGS:
    565       return 13;
    566     case EXTENSION_SETTINGS:
    567       return 14;
    568     case APP_NOTIFICATIONS:
    569       return 15;
    570     case HISTORY_DELETE_DIRECTIVES:
    571       return 16;
    572     case NIGORI:
    573       return 17;
    574     case DEVICE_INFO:
    575       return 18;
    576     case EXPERIMENTS:
    577       return 19;
    578     case SYNCED_NOTIFICATIONS:
    579       return 20;
    580     case PRIORITY_PREFERENCES:
    581       return 21;
    582     case DICTIONARY:
    583       return 22;
    584     case FAVICON_IMAGES:
    585       return 23;
    586     case FAVICON_TRACKING:
    587       return 24;
    588     case PROXY_TABS:
    589       return 25;
    590     case SUPERVISED_USER_SETTINGS:
    591       return 26;
    592     case SUPERVISED_USERS:
    593       return 27;
    594     case ARTICLES:
    595       return 28;
    596     case APP_LIST:
    597       return 29;
    598     case SUPERVISED_USER_SHARED_SETTINGS:
    599       return 30;
    600     case SYNCED_NOTIFICATION_APP_INFO:
    601       return 31;
    602     // Silence a compiler warning.
    603     case MODEL_TYPE_COUNT:
    604       return 0;
    605   }
    606   return 0;
    607 }
    608 
    609 base::StringValue* ModelTypeToValue(ModelType model_type) {
    610   if (model_type >= FIRST_REAL_MODEL_TYPE) {
    611     return new base::StringValue(ModelTypeToString(model_type));
    612   } else if (model_type == TOP_LEVEL_FOLDER) {
    613     return new base::StringValue("Top-level folder");
    614   } else if (model_type == UNSPECIFIED) {
    615     return new base::StringValue("Unspecified");
    616   }
    617   NOTREACHED();
    618   return new base::StringValue(std::string());
    619 }
    620 
    621 ModelType ModelTypeFromValue(const base::Value& value) {
    622   if (value.IsType(base::Value::TYPE_STRING)) {
    623     std::string result;
    624     CHECK(value.GetAsString(&result));
    625     return ModelTypeFromString(result);
    626   } else if (value.IsType(base::Value::TYPE_INTEGER)) {
    627     int result;
    628     CHECK(value.GetAsInteger(&result));
    629     return ModelTypeFromInt(result);
    630   } else {
    631     NOTREACHED() << "Unsupported value type: " << value.GetType();
    632     return UNSPECIFIED;
    633   }
    634 }
    635 
    636 ModelType ModelTypeFromString(const std::string& model_type_string) {
    637   if (model_type_string == "Bookmarks")
    638     return BOOKMARKS;
    639   else if (model_type_string == "Preferences")
    640     return PREFERENCES;
    641   else if (model_type_string == "Passwords")
    642     return PASSWORDS;
    643   else if (model_type_string == "Autofill")
    644     return AUTOFILL;
    645   else if (model_type_string == "Autofill Profiles")
    646     return AUTOFILL_PROFILE;
    647   else if (model_type_string == "Themes")
    648     return THEMES;
    649   else if (model_type_string == "Typed URLs")
    650     return TYPED_URLS;
    651   else if (model_type_string == "Extensions")
    652     return EXTENSIONS;
    653   else if (model_type_string == "Encryption keys")
    654     return NIGORI;
    655   else if (model_type_string == "Search Engines")
    656     return SEARCH_ENGINES;
    657   else if (model_type_string == "Sessions")
    658     return SESSIONS;
    659   else if (model_type_string == "Apps")
    660     return APPS;
    661   else if (model_type_string == "App List")
    662     return APP_LIST;
    663   else if (model_type_string == "App settings")
    664     return APP_SETTINGS;
    665   else if (model_type_string == "Extension settings")
    666     return EXTENSION_SETTINGS;
    667   else if (model_type_string == "App Notifications")
    668     return APP_NOTIFICATIONS;
    669   else if (model_type_string == "History Delete Directives")
    670     return HISTORY_DELETE_DIRECTIVES;
    671   else if (model_type_string == "Synced Notifications")
    672     return SYNCED_NOTIFICATIONS;
    673   else if (model_type_string == "Synced Notification App Info")
    674     return SYNCED_NOTIFICATION_APP_INFO;
    675   else if (model_type_string == "Device Info")
    676     return DEVICE_INFO;
    677   else if (model_type_string == "Experiments")
    678     return EXPERIMENTS;
    679   else if (model_type_string == "Priority Preferences")
    680     return PRIORITY_PREFERENCES;
    681   else if (model_type_string == "Dictionary")
    682     return DICTIONARY;
    683   else if (model_type_string == "Favicon Images")
    684     return FAVICON_IMAGES;
    685   else if (model_type_string == "Favicon Tracking")
    686     return FAVICON_TRACKING;
    687   else if (model_type_string == "Managed User Settings")
    688     return SUPERVISED_USER_SETTINGS;
    689   else if (model_type_string == "Managed Users")
    690     return SUPERVISED_USERS;
    691   else if (model_type_string == "Managed User Shared Settings")
    692     return SUPERVISED_USER_SHARED_SETTINGS;
    693   else if (model_type_string == "Articles")
    694     return ARTICLES;
    695   else if (model_type_string == "Tabs")
    696     return PROXY_TABS;
    697   else
    698     NOTREACHED() << "No known model type corresponding to "
    699                  << model_type_string << ".";
    700   return UNSPECIFIED;
    701 }
    702 
    703 std::string ModelTypeSetToString(ModelTypeSet model_types) {
    704   std::string result;
    705   for (ModelTypeSet::Iterator it = model_types.First(); it.Good(); it.Inc()) {
    706     if (!result.empty()) {
    707       result += ", ";
    708     }
    709     result += ModelTypeToString(it.Get());
    710   }
    711   return result;
    712 }
    713 
    714 ModelTypeSet ModelTypeSetFromString(const std::string& model_types_string) {
    715   std::string working_copy = model_types_string;
    716   ModelTypeSet model_types;
    717   while (!working_copy.empty()) {
    718     // Remove any leading spaces.
    719     working_copy = working_copy.substr(working_copy.find_first_not_of(' '));
    720     if (working_copy.empty())
    721       break;
    722     std::string type_str;
    723     size_t end = working_copy.find(',');
    724     if (end == std::string::npos) {
    725       end = working_copy.length() - 1;
    726       type_str = working_copy;
    727     } else {
    728       type_str = working_copy.substr(0, end);
    729     }
    730     syncer::ModelType type = ModelTypeFromString(type_str);
    731     if (IsRealDataType(type))
    732       model_types.Put(type);
    733     working_copy = working_copy.substr(end + 1);
    734   }
    735   return model_types;
    736 }
    737 
    738 base::ListValue* ModelTypeSetToValue(ModelTypeSet model_types) {
    739   base::ListValue* value = new base::ListValue();
    740   for (ModelTypeSet::Iterator it = model_types.First(); it.Good(); it.Inc()) {
    741     value->Append(new base::StringValue(ModelTypeToString(it.Get())));
    742   }
    743   return value;
    744 }
    745 
    746 ModelTypeSet ModelTypeSetFromValue(const base::ListValue& value) {
    747   ModelTypeSet result;
    748   for (base::ListValue::const_iterator i = value.begin();
    749        i != value.end(); ++i) {
    750     result.Put(ModelTypeFromValue(**i));
    751   }
    752   return result;
    753 }
    754 
    755 // TODO(zea): remove all hardcoded tags in model associators and have them use
    756 // this instead.
    757 // NOTE: Proxy types should return empty strings (so that we don't NOTREACHED
    758 // in tests when we verify they have no root node).
    759 std::string ModelTypeToRootTag(ModelType type) {
    760   switch (type) {
    761     case BOOKMARKS:
    762       return "google_chrome_bookmarks";
    763     case PREFERENCES:
    764       return "google_chrome_preferences";
    765     case PASSWORDS:
    766       return "google_chrome_passwords";
    767     case AUTOFILL:
    768       return "google_chrome_autofill";
    769     case THEMES:
    770       return "google_chrome_themes";
    771     case TYPED_URLS:
    772       return "google_chrome_typed_urls";
    773     case EXTENSIONS:
    774       return "google_chrome_extensions";
    775     case NIGORI:
    776       return "google_chrome_nigori";
    777     case SEARCH_ENGINES:
    778       return "google_chrome_search_engines";
    779     case SESSIONS:
    780       return "google_chrome_sessions";
    781     case APPS:
    782       return "google_chrome_apps";
    783     case APP_LIST:
    784       return "google_chrome_app_list";
    785     case AUTOFILL_PROFILE:
    786       return "google_chrome_autofill_profiles";
    787     case APP_SETTINGS:
    788       return "google_chrome_app_settings";
    789     case EXTENSION_SETTINGS:
    790       return "google_chrome_extension_settings";
    791     case APP_NOTIFICATIONS:
    792       return "google_chrome_app_notifications";
    793     case HISTORY_DELETE_DIRECTIVES:
    794       return "google_chrome_history_delete_directives";
    795     case SYNCED_NOTIFICATIONS:
    796       return "google_chrome_synced_notifications";
    797     case SYNCED_NOTIFICATION_APP_INFO:
    798       return "google_chrome_synced_notification_app_info";
    799     case DEVICE_INFO:
    800       return "google_chrome_device_info";
    801     case EXPERIMENTS:
    802       return "google_chrome_experiments";
    803     case PRIORITY_PREFERENCES:
    804       return "google_chrome_priority_preferences";
    805     case DICTIONARY:
    806       return "google_chrome_dictionary";
    807     case FAVICON_IMAGES:
    808       return "google_chrome_favicon_images";
    809     case FAVICON_TRACKING:
    810       return "google_chrome_favicon_tracking";
    811     case SUPERVISED_USER_SETTINGS:
    812       return "google_chrome_managed_user_settings";
    813     case SUPERVISED_USERS:
    814       return "google_chrome_managed_users";
    815     case SUPERVISED_USER_SHARED_SETTINGS:
    816       return "google_chrome_managed_user_shared_settings";
    817     case ARTICLES:
    818       return "google_chrome_articles";
    819     case PROXY_TABS:
    820       return std::string();
    821     default:
    822       break;
    823   }
    824   NOTREACHED() << "No known extension for model type.";
    825   return "INVALID";
    826 }
    827 
    828 // TODO(akalin): Figure out a better way to do these mappings.
    829 // Note: Do not include proxy types in this list. They should never receive
    830 // or trigger notifications.
    831 namespace {
    832 const char kBookmarkNotificationType[] = "BOOKMARK";
    833 const char kPreferenceNotificationType[] = "PREFERENCE";
    834 const char kPasswordNotificationType[] = "PASSWORD";
    835 const char kAutofillNotificationType[] = "AUTOFILL";
    836 const char kThemeNotificationType[] = "THEME";
    837 const char kTypedUrlNotificationType[] = "TYPED_URL";
    838 const char kExtensionNotificationType[] = "EXTENSION";
    839 const char kExtensionSettingNotificationType[] = "EXTENSION_SETTING";
    840 const char kNigoriNotificationType[] = "NIGORI";
    841 const char kAppSettingNotificationType[] = "APP_SETTING";
    842 const char kAppNotificationType[] = "APP";
    843 const char kAppListNotificationType[] = "APP_LIST";
    844 const char kSearchEngineNotificationType[] = "SEARCH_ENGINE";
    845 const char kSessionNotificationType[] = "SESSION";
    846 const char kAutofillProfileNotificationType[] = "AUTOFILL_PROFILE";
    847 const char kAppNotificationNotificationType[] = "APP_NOTIFICATION";
    848 const char kHistoryDeleteDirectiveNotificationType[] =
    849     "HISTORY_DELETE_DIRECTIVE";
    850 const char kSyncedNotificationType[] = "SYNCED_NOTIFICATION";
    851 const char kSyncedNotificationAppInfoType[] = "SYNCED_NOTIFICATION_APP_INFO";
    852 const char kDeviceInfoNotificationType[] = "DEVICE_INFO";
    853 const char kExperimentsNotificationType[] = "EXPERIMENTS";
    854 const char kPriorityPreferenceNotificationType[] = "PRIORITY_PREFERENCE";
    855 const char kDictionaryNotificationType[] = "DICTIONARY";
    856 const char kFaviconImageNotificationType[] = "FAVICON_IMAGE";
    857 const char kFaviconTrackingNotificationType[] = "FAVICON_TRACKING";
    858 const char kSupervisedUserSettingNotificationType[] = "MANAGED_USER_SETTING";
    859 const char kSupervisedUserNotificationType[] = "MANAGED_USER";
    860 const char kSupervisedUserSharedSettingNotificationType[] =
    861     "MANAGED_USER_SHARED_SETTING";
    862 const char kArticleNotificationType[] = "ARTICLE";
    863 }  // namespace
    864 
    865 bool RealModelTypeToNotificationType(ModelType model_type,
    866                                      std::string* notification_type) {
    867   switch (model_type) {
    868     case BOOKMARKS:
    869       *notification_type = kBookmarkNotificationType;
    870       return true;
    871     case PREFERENCES:
    872       *notification_type = kPreferenceNotificationType;
    873       return true;
    874     case PASSWORDS:
    875       *notification_type = kPasswordNotificationType;
    876       return true;
    877     case AUTOFILL:
    878       *notification_type = kAutofillNotificationType;
    879       return true;
    880     case THEMES:
    881       *notification_type = kThemeNotificationType;
    882       return true;
    883     case TYPED_URLS:
    884       *notification_type = kTypedUrlNotificationType;
    885       return true;
    886     case EXTENSIONS:
    887       *notification_type = kExtensionNotificationType;
    888       return true;
    889     case NIGORI:
    890       *notification_type = kNigoriNotificationType;
    891       return true;
    892     case APP_SETTINGS:
    893       *notification_type = kAppSettingNotificationType;
    894       return true;
    895     case APPS:
    896       *notification_type = kAppNotificationType;
    897       return true;
    898     case APP_LIST:
    899       *notification_type = kAppListNotificationType;
    900       return true;
    901     case SEARCH_ENGINES:
    902       *notification_type = kSearchEngineNotificationType;
    903       return true;
    904     case SESSIONS:
    905       *notification_type = kSessionNotificationType;
    906       return true;
    907     case AUTOFILL_PROFILE:
    908       *notification_type = kAutofillProfileNotificationType;
    909       return true;
    910     case EXTENSION_SETTINGS:
    911       *notification_type = kExtensionSettingNotificationType;
    912       return true;
    913     case APP_NOTIFICATIONS:
    914       *notification_type = kAppNotificationNotificationType;
    915       return true;
    916     case HISTORY_DELETE_DIRECTIVES:
    917       *notification_type = kHistoryDeleteDirectiveNotificationType;
    918       return true;
    919     case SYNCED_NOTIFICATIONS:
    920       *notification_type = kSyncedNotificationType;
    921       return true;
    922     case SYNCED_NOTIFICATION_APP_INFO:
    923       *notification_type = kSyncedNotificationAppInfoType;
    924       return true;
    925     case DEVICE_INFO:
    926       *notification_type = kDeviceInfoNotificationType;
    927       return true;
    928     case EXPERIMENTS:
    929       *notification_type = kExperimentsNotificationType;
    930       return true;
    931     case PRIORITY_PREFERENCES:
    932       *notification_type = kPriorityPreferenceNotificationType;
    933       return true;
    934     case DICTIONARY:
    935       *notification_type = kDictionaryNotificationType;
    936       return true;
    937     case FAVICON_IMAGES:
    938       *notification_type = kFaviconImageNotificationType;
    939       return true;
    940     case FAVICON_TRACKING:
    941       *notification_type = kFaviconTrackingNotificationType;
    942       return true;
    943     case SUPERVISED_USER_SETTINGS:
    944       *notification_type = kSupervisedUserSettingNotificationType;
    945       return true;
    946     case SUPERVISED_USERS:
    947       *notification_type = kSupervisedUserNotificationType;
    948       return true;
    949     case SUPERVISED_USER_SHARED_SETTINGS:
    950       *notification_type = kSupervisedUserSharedSettingNotificationType;
    951       return true;
    952     case ARTICLES:
    953       *notification_type = kArticleNotificationType;
    954       return true;
    955     default:
    956       break;
    957   }
    958   notification_type->clear();
    959   return false;
    960 }
    961 
    962 bool NotificationTypeToRealModelType(const std::string& notification_type,
    963                                      ModelType* model_type) {
    964   if (notification_type == kBookmarkNotificationType) {
    965     *model_type = BOOKMARKS;
    966     return true;
    967   } else if (notification_type == kPreferenceNotificationType) {
    968     *model_type = PREFERENCES;
    969     return true;
    970   } else if (notification_type == kPasswordNotificationType) {
    971     *model_type = PASSWORDS;
    972     return true;
    973   } else if (notification_type == kAutofillNotificationType) {
    974     *model_type = AUTOFILL;
    975     return true;
    976   } else if (notification_type == kThemeNotificationType) {
    977     *model_type = THEMES;
    978     return true;
    979   } else if (notification_type == kTypedUrlNotificationType) {
    980     *model_type = TYPED_URLS;
    981     return true;
    982   } else if (notification_type == kExtensionNotificationType) {
    983     *model_type = EXTENSIONS;
    984     return true;
    985   } else if (notification_type == kNigoriNotificationType) {
    986     *model_type = NIGORI;
    987     return true;
    988   } else if (notification_type == kAppNotificationType) {
    989     *model_type = APPS;
    990     return true;
    991   } else if (notification_type == kAppListNotificationType) {
    992     *model_type = APP_LIST;
    993     return true;
    994   } else if (notification_type == kSearchEngineNotificationType) {
    995     *model_type = SEARCH_ENGINES;
    996     return true;
    997   } else if (notification_type == kSessionNotificationType) {
    998     *model_type = SESSIONS;
    999     return true;
   1000   } else if (notification_type == kAutofillProfileNotificationType) {
   1001     *model_type = AUTOFILL_PROFILE;
   1002     return true;
   1003   } else if (notification_type == kAppSettingNotificationType) {
   1004     *model_type = APP_SETTINGS;
   1005     return true;
   1006   } else if (notification_type == kExtensionSettingNotificationType) {
   1007     *model_type = EXTENSION_SETTINGS;
   1008     return true;
   1009   } else if (notification_type == kAppNotificationNotificationType) {
   1010     *model_type = APP_NOTIFICATIONS;
   1011     return true;
   1012   } else if (notification_type == kHistoryDeleteDirectiveNotificationType) {
   1013     *model_type = HISTORY_DELETE_DIRECTIVES;
   1014     return true;
   1015   } else if (notification_type == kSyncedNotificationType) {
   1016     *model_type = SYNCED_NOTIFICATIONS;
   1017     return true;
   1018   } else if (notification_type == kSyncedNotificationAppInfoType) {
   1019     *model_type = SYNCED_NOTIFICATION_APP_INFO;
   1020     return true;
   1021   } else if (notification_type == kDeviceInfoNotificationType) {
   1022     *model_type = DEVICE_INFO;
   1023     return true;
   1024   } else if (notification_type == kExperimentsNotificationType) {
   1025     *model_type = EXPERIMENTS;
   1026     return true;
   1027   } else if (notification_type == kPriorityPreferenceNotificationType) {
   1028     *model_type = PRIORITY_PREFERENCES;
   1029     return true;
   1030   } else if (notification_type == kDictionaryNotificationType) {
   1031     *model_type = DICTIONARY;
   1032     return true;
   1033   } else if (notification_type == kFaviconImageNotificationType) {
   1034     *model_type = FAVICON_IMAGES;
   1035     return true;
   1036   } else if (notification_type == kFaviconTrackingNotificationType) {
   1037     *model_type = FAVICON_TRACKING;
   1038     return true;
   1039   } else if (notification_type == kSupervisedUserSettingNotificationType) {
   1040     *model_type = SUPERVISED_USER_SETTINGS;
   1041     return true;
   1042   } else if (notification_type == kSupervisedUserNotificationType) {
   1043     *model_type = SUPERVISED_USERS;
   1044     return true;
   1045   } else if (notification_type ==
   1046       kSupervisedUserSharedSettingNotificationType) {
   1047     *model_type = SUPERVISED_USER_SHARED_SETTINGS;
   1048     return true;
   1049   } else if (notification_type == kArticleNotificationType) {
   1050     *model_type = ARTICLES;
   1051     return true;
   1052   }
   1053   *model_type = UNSPECIFIED;
   1054   return false;
   1055 }
   1056 
   1057 bool IsRealDataType(ModelType model_type) {
   1058   return model_type >= FIRST_REAL_MODEL_TYPE && model_type < MODEL_TYPE_COUNT;
   1059 }
   1060 
   1061 bool IsProxyType(ModelType model_type) {
   1062   return model_type >= FIRST_PROXY_TYPE && model_type <= LAST_PROXY_TYPE;
   1063 }
   1064 
   1065 bool IsActOnceDataType(ModelType model_type) {
   1066   return model_type == HISTORY_DELETE_DIRECTIVES;
   1067 }
   1068 
   1069 }  // namespace syncer
   1070