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/syncable/entry_kernel.h"
      6 
      7 #include "base/strings/string_number_conversions.h"
      8 #include "sync/protocol/proto_value_conversions.h"
      9 #include "sync/syncable/syncable_enum_conversions.h"
     10 #include "sync/util/cryptographer.h"
     11 
     12 namespace syncer {
     13 namespace syncable {
     14 
     15 EntryKernel::EntryKernel() : dirty_(false) {
     16   // Everything else should already be default-initialized.
     17   for (int i = INT64_FIELDS_BEGIN; i < INT64_FIELDS_END; ++i) {
     18     int64_fields[i] = 0;
     19   }
     20 }
     21 
     22 EntryKernel::~EntryKernel() {}
     23 
     24 ModelType EntryKernel::GetModelType() const {
     25   ModelType specifics_type = GetModelTypeFromSpecifics(ref(SPECIFICS));
     26   if (specifics_type != UNSPECIFIED)
     27     return specifics_type;
     28   if (ref(ID).IsRoot())
     29     return TOP_LEVEL_FOLDER;
     30   // Loose check for server-created top-level folders that aren't
     31   // bound to a particular model type.
     32   if (!ref(UNIQUE_SERVER_TAG).empty() && ref(SERVER_IS_DIR))
     33     return TOP_LEVEL_FOLDER;
     34 
     35   return UNSPECIFIED;
     36 }
     37 
     38 ModelType EntryKernel::GetServerModelType() const {
     39   ModelType specifics_type = GetModelTypeFromSpecifics(ref(SERVER_SPECIFICS));
     40   if (specifics_type != UNSPECIFIED)
     41     return specifics_type;
     42   if (ref(ID).IsRoot())
     43     return TOP_LEVEL_FOLDER;
     44   // Loose check for server-created top-level folders that aren't
     45   // bound to a particular model type.
     46   if (!ref(UNIQUE_SERVER_TAG).empty() && ref(SERVER_IS_DIR))
     47     return TOP_LEVEL_FOLDER;
     48 
     49   return UNSPECIFIED;
     50 }
     51 
     52 bool EntryKernel::ShouldMaintainPosition() const {
     53   // We maintain positions for all bookmarks, except those that are
     54   // server-created top-level folders.
     55   return (GetModelTypeFromSpecifics(ref(SPECIFICS)) == syncer::BOOKMARKS)
     56       && !(!ref(UNIQUE_SERVER_TAG).empty() && ref(IS_DIR));
     57 }
     58 
     59 bool EntryKernel::ShouldMaintainHierarchy() const {
     60   // We maintain hierarchy for bookmarks, device info, and top-level folders,
     61   // but no other types.  Note that the Nigori node consists of a single
     62   // top-level folder, so it's included in this set.
     63   return (GetModelTypeFromSpecifics(ref(SPECIFICS)) == syncer::BOOKMARKS)
     64       || (!ref(UNIQUE_SERVER_TAG).empty());
     65 }
     66 
     67 namespace {
     68 
     69 // Utility function to loop through a set of enum values and add the
     70 // field keys/values in the kernel to the given dictionary.
     71 //
     72 // V should be convertible to Value.
     73 template <class T, class U, class V>
     74 void SetFieldValues(const EntryKernel& kernel,
     75                     base::DictionaryValue* dictionary_value,
     76                     const char* (*enum_key_fn)(T),
     77                     V* (*enum_value_fn)(U),
     78                     int field_key_min, int field_key_max) {
     79   DCHECK_LE(field_key_min, field_key_max);
     80   for (int i = field_key_min; i <= field_key_max; ++i) {
     81     T field = static_cast<T>(i);
     82     const std::string& key = enum_key_fn(field);
     83     V* value = enum_value_fn(kernel.ref(field));
     84     dictionary_value->Set(key, value);
     85   }
     86 }
     87 
     88 void SetEncryptableProtoValues(
     89     const EntryKernel& kernel,
     90     Cryptographer* cryptographer,
     91     base::DictionaryValue* dictionary_value,
     92     int field_key_min, int field_key_max) {
     93   DCHECK_LE(field_key_min, field_key_max);
     94   for (int i = field_key_min; i <= field_key_max; ++i) {
     95     ProtoField field = static_cast<ProtoField>(i);
     96     const std::string& key = GetProtoFieldString(field);
     97 
     98     base::DictionaryValue* value = NULL;
     99     sync_pb::EntitySpecifics decrypted;
    100     const sync_pb::EncryptedData& encrypted = kernel.ref(field).encrypted();
    101     if (cryptographer &&
    102         kernel.ref(field).has_encrypted() &&
    103         cryptographer->CanDecrypt(encrypted) &&
    104         cryptographer->Decrypt(encrypted, &decrypted)) {
    105       value = EntitySpecificsToValue(decrypted);
    106       value->SetBoolean("encrypted", true);
    107     } else {
    108       value = EntitySpecificsToValue(kernel.ref(field));
    109     }
    110     dictionary_value->Set(key, value);
    111   }
    112 }
    113 
    114 // Helper functions for SetFieldValues().
    115 
    116 base::StringValue* Int64ToValue(int64 i) {
    117   return new base::StringValue(base::Int64ToString(i));
    118 }
    119 
    120 base::StringValue* TimeToValue(const base::Time& t) {
    121   return new base::StringValue(GetTimeDebugString(t));
    122 }
    123 
    124 base::StringValue* IdToValue(const Id& id) {
    125   return id.ToValue();
    126 }
    127 
    128 base::FundamentalValue* BooleanToValue(bool bool_val) {
    129   return new base::FundamentalValue(bool_val);
    130 }
    131 
    132 base::StringValue* StringToValue(const std::string& str) {
    133   return new base::StringValue(str);
    134 }
    135 
    136 base::StringValue* UniquePositionToValue(const UniquePosition& pos) {
    137   return new base::StringValue(pos.ToDebugString());
    138 }
    139 
    140 base::StringValue* AttachmentMetadataToValue(
    141     const sync_pb::AttachmentMetadata& a) {
    142   return new base::StringValue(a.SerializeAsString());
    143 }
    144 
    145 }  // namespace
    146 
    147 base::DictionaryValue* EntryKernel::ToValue(
    148     Cryptographer* cryptographer) const {
    149   base::DictionaryValue* kernel_info = new base::DictionaryValue();
    150   kernel_info->SetBoolean("isDirty", is_dirty());
    151   kernel_info->Set("serverModelType", ModelTypeToValue(GetServerModelType()));
    152 
    153   // Int64 fields.
    154   SetFieldValues(*this, kernel_info,
    155                  &GetMetahandleFieldString, &Int64ToValue,
    156                  INT64_FIELDS_BEGIN, META_HANDLE);
    157   SetFieldValues(*this, kernel_info,
    158                  &GetBaseVersionString, &Int64ToValue,
    159                  META_HANDLE + 1, BASE_VERSION);
    160   SetFieldValues(*this, kernel_info,
    161                  &GetInt64FieldString, &Int64ToValue,
    162                  BASE_VERSION + 1, INT64_FIELDS_END - 1);
    163 
    164   // Time fields.
    165   SetFieldValues(*this, kernel_info,
    166                  &GetTimeFieldString, &TimeToValue,
    167                  TIME_FIELDS_BEGIN, TIME_FIELDS_END - 1);
    168 
    169   // ID fields.
    170   SetFieldValues(*this, kernel_info,
    171                  &GetIdFieldString, &IdToValue,
    172                  ID_FIELDS_BEGIN, ID_FIELDS_END - 1);
    173 
    174   // Bit fields.
    175   SetFieldValues(*this, kernel_info,
    176                  &GetIndexedBitFieldString, &BooleanToValue,
    177                  BIT_FIELDS_BEGIN, INDEXED_BIT_FIELDS_END - 1);
    178   SetFieldValues(*this, kernel_info,
    179                  &GetIsDelFieldString, &BooleanToValue,
    180                  INDEXED_BIT_FIELDS_END, IS_DEL);
    181   SetFieldValues(*this, kernel_info,
    182                  &GetBitFieldString, &BooleanToValue,
    183                  IS_DEL + 1, BIT_FIELDS_END - 1);
    184 
    185   // String fields.
    186   {
    187     // Pick out the function overload we want.
    188     SetFieldValues(*this, kernel_info,
    189                    &GetStringFieldString, &StringToValue,
    190                    STRING_FIELDS_BEGIN, STRING_FIELDS_END - 1);
    191   }
    192 
    193   // Proto fields.
    194   SetEncryptableProtoValues(*this, cryptographer, kernel_info,
    195                             PROTO_FIELDS_BEGIN, PROTO_FIELDS_END - 1);
    196 
    197   // UniquePosition fields
    198   SetFieldValues(*this, kernel_info,
    199                  &GetUniquePositionFieldString, &UniquePositionToValue,
    200                  UNIQUE_POSITION_FIELDS_BEGIN, UNIQUE_POSITION_FIELDS_END - 1);
    201 
    202   // AttachmentMetadata fields
    203   SetFieldValues(*this,
    204                  kernel_info,
    205                  &GetAttachmentMetadataFieldString,
    206                  &AttachmentMetadataToValue,
    207                  ATTACHMENT_METADATA_FIELDS_BEGIN,
    208                  ATTACHMENT_METADATA_FIELDS_END - 1);
    209 
    210   // Bit temps.
    211   SetFieldValues(*this, kernel_info,
    212                  &GetBitTempString, &BooleanToValue,
    213                  BIT_TEMPS_BEGIN, BIT_TEMPS_END - 1);
    214 
    215   return kernel_info;
    216 }
    217 
    218 base::ListValue* EntryKernelMutationMapToValue(
    219     const EntryKernelMutationMap& mutations) {
    220   base::ListValue* list = new base::ListValue();
    221   for (EntryKernelMutationMap::const_iterator it = mutations.begin();
    222        it != mutations.end(); ++it) {
    223     list->Append(EntryKernelMutationToValue(it->second));
    224   }
    225   return list;
    226 }
    227 
    228 base::DictionaryValue* EntryKernelMutationToValue(
    229     const EntryKernelMutation& mutation) {
    230   base::DictionaryValue* dict = new base::DictionaryValue();
    231   dict->Set("original", mutation.original.ToValue(NULL));
    232   dict->Set("mutated", mutation.mutated.ToValue(NULL));
    233   return dict;
    234 }
    235 
    236 }  // namespace syncer
    237 }  // namespace syncable
    238