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