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.
5 #include "sync/internal_api/public/base/model_type.h"
7 #include "base/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"
28 void AddDefaultFieldValue(ModelType datatype
,
29 sync_pb::EntitySpecifics
* specifics
) {
32 specifics
->mutable_bookmark();
35 specifics
->mutable_password();
38 specifics
->mutable_preference();
41 specifics
->mutable_autofill();
43 case AUTOFILL_PROFILE
:
44 specifics
->mutable_autofill_profile();
47 specifics
->mutable_theme();
50 specifics
->mutable_typed_url();
53 specifics
->mutable_extension();
56 specifics
->mutable_nigori();
59 specifics
->mutable_search_engine();
62 specifics
->mutable_session();
65 specifics
->mutable_app();
68 specifics
->mutable_app_setting();
70 case EXTENSION_SETTINGS
:
71 specifics
->mutable_extension_setting();
73 case APP_NOTIFICATIONS
:
74 specifics
->mutable_app_notification();
76 case HISTORY_DELETE_DIRECTIVES
:
77 specifics
->mutable_history_delete_directive();
79 case SYNCED_NOTIFICATIONS
:
80 specifics
->mutable_synced_notification();
83 specifics
->mutable_device_info();
86 specifics
->mutable_experiments();
89 NOTREACHED() << "No known extension for model type.";
93 ModelType
GetModelTypeFromSpecificsFieldNumber(int field_number
) {
94 for (int i
= FIRST_REAL_MODEL_TYPE
; i
< MODEL_TYPE_COUNT
; ++i
) {
95 ModelType model_type
= ModelTypeFromInt(i
);
96 if (GetSpecificsFieldNumberFromModelType(model_type
) == field_number
)
102 int GetSpecificsFieldNumberFromModelType(ModelType model_type
) {
103 switch (model_type
) {
105 return sync_pb::EntitySpecifics::kBookmarkFieldNumber
;
108 return sync_pb::EntitySpecifics::kPasswordFieldNumber
;
111 return sync_pb::EntitySpecifics::kPreferenceFieldNumber
;
114 return sync_pb::EntitySpecifics::kAutofillFieldNumber
;
116 case AUTOFILL_PROFILE
:
117 return sync_pb::EntitySpecifics::kAutofillProfileFieldNumber
;
120 return sync_pb::EntitySpecifics::kThemeFieldNumber
;
123 return sync_pb::EntitySpecifics::kTypedUrlFieldNumber
;
126 return sync_pb::EntitySpecifics::kExtensionFieldNumber
;
129 return sync_pb::EntitySpecifics::kNigoriFieldNumber
;
132 return sync_pb::EntitySpecifics::kSearchEngineFieldNumber
;
135 return sync_pb::EntitySpecifics::kSessionFieldNumber
;
138 return sync_pb::EntitySpecifics::kAppFieldNumber
;
141 return sync_pb::EntitySpecifics::kAppSettingFieldNumber
;
143 case EXTENSION_SETTINGS
:
144 return sync_pb::EntitySpecifics::kExtensionSettingFieldNumber
;
146 case APP_NOTIFICATIONS
:
147 return sync_pb::EntitySpecifics::kAppNotificationFieldNumber
;
149 case HISTORY_DELETE_DIRECTIVES
:
150 return sync_pb::EntitySpecifics::kHistoryDeleteDirectiveFieldNumber
;
151 case SYNCED_NOTIFICATIONS
:
152 return sync_pb::EntitySpecifics::kSyncedNotificationFieldNumber
;
154 return sync_pb::EntitySpecifics::kDeviceInfoFieldNumber
;
157 return sync_pb::EntitySpecifics::kExperimentsFieldNumber
;
160 NOTREACHED() << "No known extension for model type.";
163 NOTREACHED() << "Needed for linux_keep_shadow_stacks because of "
164 << "http://gcc.gnu.org/bugzilla/show_bug.cgi?id=20681";
168 FullModelTypeSet
ToFullModelTypeSet(ModelTypeSet in
) {
169 FullModelTypeSet out
;
170 for (ModelTypeSet::Iterator i
= in
.First(); i
.Good(); i
.Inc()) {
176 // Note: keep this consistent with GetModelType in entry.cc!
177 ModelType
GetModelType(const sync_pb::SyncEntity
& sync_entity
) {
178 DCHECK(!IsRoot(sync_entity
)); // Root shouldn't ever go over the wire.
180 if (sync_entity
.deleted())
183 // Backwards compatibility with old (pre-specifics) protocol.
184 if (sync_entity
.has_bookmarkdata())
187 ModelType specifics_type
= GetModelTypeFromSpecifics(sync_entity
.specifics());
188 if (specifics_type
!= UNSPECIFIED
)
189 return specifics_type
;
191 // Loose check for server-created top-level folders that aren't
192 // bound to a particular model type.
193 if (!sync_entity
.server_defined_unique_tag().empty() &&
194 IsFolder(sync_entity
)) {
195 return TOP_LEVEL_FOLDER
;
198 // This is an item of a datatype we can't understand. Maybe it's
199 // from the future? Either we mis-encoded the object, or the
200 // server sent us entries it shouldn't have.
201 NOTREACHED() << "Unknown datatype in sync proto.";
205 ModelType
GetModelTypeFromSpecifics(const sync_pb::EntitySpecifics
& specifics
) {
206 if (specifics
.has_bookmark())
209 if (specifics
.has_password())
212 if (specifics
.has_preference())
215 if (specifics
.has_autofill())
218 if (specifics
.has_autofill_profile())
219 return AUTOFILL_PROFILE
;
221 if (specifics
.has_theme())
224 if (specifics
.has_typed_url())
227 if (specifics
.has_extension())
230 if (specifics
.has_nigori())
233 if (specifics
.has_app())
236 if (specifics
.has_search_engine())
237 return SEARCH_ENGINES
;
239 if (specifics
.has_session())
242 if (specifics
.has_app_setting())
245 if (specifics
.has_extension_setting())
246 return EXTENSION_SETTINGS
;
248 if (specifics
.has_app_notification())
249 return APP_NOTIFICATIONS
;
251 if (specifics
.has_history_delete_directive())
252 return HISTORY_DELETE_DIRECTIVES
;
254 if (specifics
.has_synced_notification())
255 return SYNCED_NOTIFICATIONS
;
257 if (specifics
.has_device_info())
260 if (specifics
.has_experiments())
266 bool ShouldMaintainPosition(ModelType model_type
) {
267 return model_type
== BOOKMARKS
;
270 ModelTypeSet
UserTypes() {
272 for (int i
= FIRST_USER_MODEL_TYPE
; i
<= LAST_USER_MODEL_TYPE
; ++i
) {
273 set
.Put(ModelTypeFromInt(i
));
278 ModelTypeSet
EncryptableUserTypes() {
279 ModelTypeSet encryptable_user_types
= UserTypes();
280 // We never encrypt history delete directives.
281 encryptable_user_types
.Remove(HISTORY_DELETE_DIRECTIVES
);
282 // Synced notifications are not encrypted since the server must see changes.
283 encryptable_user_types
.Remove(SYNCED_NOTIFICATIONS
);
284 return encryptable_user_types
;
287 ModelTypeSet
ControlTypes() {
289 for (int i
= FIRST_CONTROL_MODEL_TYPE
; i
<= LAST_CONTROL_MODEL_TYPE
; ++i
) {
290 set
.Put(ModelTypeFromInt(i
));
296 bool IsControlType(ModelType model_type
) {
297 return ControlTypes().Has(model_type
);
300 const char* ModelTypeToString(ModelType model_type
) {
301 // This is used in serialization routines as well as for displaying debug
302 // information. Do not attempt to change these string values unless you know
303 // what you're doing.
304 switch (model_type
) {
305 case TOP_LEVEL_FOLDER
:
306 return "Top Level Folder";
308 return "Unspecified";
312 return "Preferences";
324 return "Encryption keys";
326 return "Search Engines";
331 case AUTOFILL_PROFILE
:
332 return "Autofill Profiles";
334 return "App settings";
335 case EXTENSION_SETTINGS
:
336 return "Extension settings";
337 case APP_NOTIFICATIONS
:
338 return "App Notifications";
339 case HISTORY_DELETE_DIRECTIVES
:
340 return "History Delete Directives";
341 case SYNCED_NOTIFICATIONS
:
342 return "Synced Notifications";
344 return "Device Info";
346 return "Experiments";
350 NOTREACHED() << "No known extension for model type.";
354 StringValue
* ModelTypeToValue(ModelType model_type
) {
355 if (model_type
>= FIRST_REAL_MODEL_TYPE
) {
356 return Value::CreateStringValue(ModelTypeToString(model_type
));
357 } else if (model_type
== TOP_LEVEL_FOLDER
) {
358 return Value::CreateStringValue("Top-level folder");
359 } else if (model_type
== UNSPECIFIED
) {
360 return Value::CreateStringValue("Unspecified");
363 return Value::CreateStringValue("");
366 ModelType
ModelTypeFromValue(const Value
& value
) {
367 if (value
.IsType(Value::TYPE_STRING
)) {
369 CHECK(value
.GetAsString(&result
));
370 return ModelTypeFromString(result
);
371 } else if (value
.IsType(Value::TYPE_INTEGER
)) {
373 CHECK(value
.GetAsInteger(&result
));
374 return ModelTypeFromInt(result
);
376 NOTREACHED() << "Unsupported value type: " << value
.GetType();
381 ModelType
ModelTypeFromString(const std::string
& model_type_string
) {
382 if (model_type_string
== "Bookmarks")
384 else if (model_type_string
== "Preferences")
386 else if (model_type_string
== "Passwords")
388 else if (model_type_string
== "Autofill")
390 else if (model_type_string
== "Autofill Profiles")
391 return AUTOFILL_PROFILE
;
392 else if (model_type_string
== "Themes")
394 else if (model_type_string
== "Typed URLs")
396 else if (model_type_string
== "Extensions")
398 else if (model_type_string
== "Encryption keys")
400 else if (model_type_string
== "Search Engines")
401 return SEARCH_ENGINES
;
402 else if (model_type_string
== "Sessions")
404 else if (model_type_string
== "Apps")
406 else if (model_type_string
== "App settings")
408 else if (model_type_string
== "Extension settings")
409 return EXTENSION_SETTINGS
;
410 else if (model_type_string
== "App Notifications")
411 return APP_NOTIFICATIONS
;
412 else if (model_type_string
== "History Delete Directives")
413 return HISTORY_DELETE_DIRECTIVES
;
414 else if (model_type_string
== "Synced Notifications")
415 return SYNCED_NOTIFICATIONS
;
416 else if (model_type_string
== "Device Info")
418 else if (model_type_string
== "Experiments")
421 NOTREACHED() << "No known model type corresponding to "
422 << model_type_string
<< ".";
426 std::string
ModelTypeSetToString(ModelTypeSet model_types
) {
428 for (ModelTypeSet::Iterator it
= model_types
.First(); it
.Good(); it
.Inc()) {
429 if (!result
.empty()) {
432 result
+= ModelTypeToString(it
.Get());
437 base::ListValue
* ModelTypeSetToValue(ModelTypeSet model_types
) {
438 ListValue
* value
= new ListValue();
439 for (ModelTypeSet::Iterator it
= model_types
.First(); it
.Good(); it
.Inc()) {
441 Value::CreateStringValue(ModelTypeToString(it
.Get())));
446 ModelTypeSet
ModelTypeSetFromValue(const base::ListValue
& value
) {
448 for (ListValue::const_iterator i
= value
.begin(); i
!= value
.end(); ++i
) {
449 result
.Put(ModelTypeFromValue(**i
));
454 // TODO(zea): remove all hardcoded tags in model associators and have them use
456 std::string
ModelTypeToRootTag(ModelType type
) {
459 return "google_chrome_bookmarks";
461 return "google_chrome_preferences";
463 return "google_chrome_passwords";
465 return "google_chrome_autofill";
467 return "google_chrome_themes";
469 return "google_chrome_typed_urls";
471 return "google_chrome_extensions";
473 return "google_chrome_nigori";
475 return "google_chrome_search_engines";
477 return "google_chrome_sessions";
479 return "google_chrome_apps";
480 case AUTOFILL_PROFILE
:
481 return "google_chrome_autofill_profiles";
483 return "google_chrome_app_settings";
484 case EXTENSION_SETTINGS
:
485 return "google_chrome_extension_settings";
486 case APP_NOTIFICATIONS
:
487 return "google_chrome_app_notifications";
488 case HISTORY_DELETE_DIRECTIVES
:
489 return "google_chrome_history_delete_directives";
490 case SYNCED_NOTIFICATIONS
:
491 return "google_chrome_synced_notifications";
493 return "google_chrome_device_info";
495 return "google_chrome_experiments";
499 NOTREACHED() << "No known extension for model type.";
503 // TODO(akalin): Figure out a better way to do these mappings.
506 const char kBookmarkNotificationType
[] = "BOOKMARK";
507 const char kPreferenceNotificationType
[] = "PREFERENCE";
508 const char kPasswordNotificationType
[] = "PASSWORD";
509 const char kAutofillNotificationType
[] = "AUTOFILL";
510 const char kThemeNotificationType
[] = "THEME";
511 const char kTypedUrlNotificationType
[] = "TYPED_URL";
512 const char kExtensionNotificationType
[] = "EXTENSION";
513 const char kExtensionSettingNotificationType
[] = "EXTENSION_SETTING";
514 const char kNigoriNotificationType
[] = "NIGORI";
515 const char kAppSettingNotificationType
[] = "APP_SETTING";
516 const char kAppNotificationType
[] = "APP";
517 const char kSearchEngineNotificationType
[] = "SEARCH_ENGINE";
518 const char kSessionNotificationType
[] = "SESSION";
519 const char kAutofillProfileNotificationType
[] = "AUTOFILL_PROFILE";
520 const char kAppNotificationNotificationType
[] = "APP_NOTIFICATION";
521 const char kHistoryDeleteDirectiveNotificationType
[] =
522 "HISTORY_DELETE_DIRECTIVE";
523 const char kSyncedNotificationType
[] = "SYNCED_NOTIFICATION";
524 const char kDeviceInfoNotificationType
[] = "DEVICE_INFO";
525 const char kExperimentsNotificationType
[] = "EXPERIMENTS";
528 bool RealModelTypeToNotificationType(ModelType model_type
,
529 std::string
* notification_type
) {
530 switch (model_type
) {
532 *notification_type
= kBookmarkNotificationType
;
535 *notification_type
= kPreferenceNotificationType
;
538 *notification_type
= kPasswordNotificationType
;
541 *notification_type
= kAutofillNotificationType
;
544 *notification_type
= kThemeNotificationType
;
547 *notification_type
= kTypedUrlNotificationType
;
550 *notification_type
= kExtensionNotificationType
;
553 *notification_type
= kNigoriNotificationType
;
556 *notification_type
= kAppSettingNotificationType
;
559 *notification_type
= kAppNotificationType
;
562 *notification_type
= kSearchEngineNotificationType
;
565 *notification_type
= kSessionNotificationType
;
567 case AUTOFILL_PROFILE
:
568 *notification_type
= kAutofillProfileNotificationType
;
570 case EXTENSION_SETTINGS
:
571 *notification_type
= kExtensionSettingNotificationType
;
573 case APP_NOTIFICATIONS
:
574 *notification_type
= kAppNotificationNotificationType
;
576 case HISTORY_DELETE_DIRECTIVES
:
577 *notification_type
= kHistoryDeleteDirectiveNotificationType
;
578 case SYNCED_NOTIFICATIONS
:
579 *notification_type
= kSyncedNotificationType
;
581 *notification_type
= kDeviceInfoNotificationType
;
584 *notification_type
= kExperimentsNotificationType
;
589 notification_type
->clear();
593 bool NotificationTypeToRealModelType(const std::string
& notification_type
,
594 ModelType
* model_type
) {
595 if (notification_type
== kBookmarkNotificationType
) {
596 *model_type
= BOOKMARKS
;
598 } else if (notification_type
== kPreferenceNotificationType
) {
599 *model_type
= PREFERENCES
;
601 } else if (notification_type
== kPasswordNotificationType
) {
602 *model_type
= PASSWORDS
;
604 } else if (notification_type
== kAutofillNotificationType
) {
605 *model_type
= AUTOFILL
;
607 } else if (notification_type
== kThemeNotificationType
) {
608 *model_type
= THEMES
;
610 } else if (notification_type
== kTypedUrlNotificationType
) {
611 *model_type
= TYPED_URLS
;
613 } else if (notification_type
== kExtensionNotificationType
) {
614 *model_type
= EXTENSIONS
;
616 } else if (notification_type
== kNigoriNotificationType
) {
617 *model_type
= NIGORI
;
619 } else if (notification_type
== kAppNotificationType
) {
622 } else if (notification_type
== kSearchEngineNotificationType
) {
623 *model_type
= SEARCH_ENGINES
;
625 } else if (notification_type
== kSessionNotificationType
) {
626 *model_type
= SESSIONS
;
628 } else if (notification_type
== kAutofillProfileNotificationType
) {
629 *model_type
= AUTOFILL_PROFILE
;
631 } else if (notification_type
== kAppSettingNotificationType
) {
632 *model_type
= APP_SETTINGS
;
634 } else if (notification_type
== kExtensionSettingNotificationType
) {
635 *model_type
= EXTENSION_SETTINGS
;
637 } else if (notification_type
== kAppNotificationNotificationType
) {
638 *model_type
= APP_NOTIFICATIONS
;
640 } else if (notification_type
== kHistoryDeleteDirectiveNotificationType
) {
641 *model_type
= HISTORY_DELETE_DIRECTIVES
;
642 } else if (notification_type
== kSyncedNotificationType
) {
643 *model_type
= SYNCED_NOTIFICATIONS
;
644 } else if (notification_type
== kDeviceInfoNotificationType
) {
645 *model_type
= DEVICE_INFO
;;
648 *model_type
= UNSPECIFIED
;
652 bool IsRealDataType(ModelType model_type
) {
653 return model_type
>= FIRST_REAL_MODEL_TYPE
&& model_type
< MODEL_TYPE_COUNT
;
656 } // namespace syncer