1#!/usr/bin/env python 2# Copyright (c) 2012 The Chromium Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6 7from grit.format.policy_templates.writers import template_writer 8 9 10NEWLINE = '\r\n' 11 12 13def GetWriter(config): 14 '''Factory method for creating AdmWriter objects. 15 See the constructor of TemplateWriter for description of 16 arguments. 17 ''' 18 return AdmWriter(['win'], config) 19 20 21class IndentedStringBuilder: 22 '''Utility class for building text with indented lines.''' 23 24 def __init__(self): 25 self.lines = [] 26 self.indent = '' 27 28 def AddLine(self, string='', indent_diff=0): 29 '''Appends a string with indentation and a linebreak to |self.lines|. 30 31 Args: 32 string: The string to print. 33 indent_diff: the difference of indentation of the printed line, 34 compared to the next/previous printed line. Increment occurs 35 after printing the line, while decrement occurs before that. 36 ''' 37 indent_diff *= 2 38 if indent_diff < 0: 39 self.indent = self.indent[(-indent_diff):] 40 if string != '': 41 self.lines.append(self.indent + string) 42 else: 43 self.lines.append('') 44 if indent_diff > 0: 45 self.indent += ''.ljust(indent_diff) 46 47 def AddLines(self, other): 48 '''Appends the content of another |IndentedStringBuilder| to |self.lines|. 49 Indentation of the added lines will be the sum of |self.indent| and 50 their original indentation. 51 52 Args: 53 other: The buffer from which lines are copied. 54 ''' 55 for line in other.lines: 56 self.AddLine(line) 57 58 def ToString(self): 59 '''Returns |self.lines| as text string.''' 60 return NEWLINE.join(self.lines) 61 62 63class AdmWriter(template_writer.TemplateWriter): 64 '''Class for generating policy templates in Windows ADM format. 65 It is used by PolicyTemplateGenerator to write ADM files. 66 ''' 67 68 TYPE_TO_INPUT = { 69 'string': 'EDITTEXT', 70 'int': 'NUMERIC', 71 'string-enum': 'DROPDOWNLIST', 72 'int-enum': 'DROPDOWNLIST', 73 'list': 'LISTBOX', 74 'string-enum-list': 'LISTBOX', 75 'dict': 'EDITTEXT' 76 } 77 78 def _AddGuiString(self, name, value): 79 # Escape newlines in the value. 80 value = value.replace('\n', '\\n') 81 if name in self.strings_seen: 82 err = ('%s was added as "%s" and now added again as "%s"' % 83 (name, self.strings_seen[name], value)) 84 assert value == self.strings_seen[name], err 85 else: 86 self.strings_seen[name] = value 87 line = '%s="%s"' % (name, value) 88 self.strings.AddLine(line) 89 90 def _WriteSupported(self, builder): 91 builder.AddLine('#if version >= 4', 1) 92 builder.AddLine('SUPPORTED !!SUPPORTED_WINXPSP2') 93 builder.AddLine('#endif', -1) 94 95 def _WritePart(self, policy, key_name, builder): 96 '''Writes the PART ... END PART section of a policy. 97 98 Args: 99 policy: The policy to write to the output. 100 key_name: The registry key backing the policy. 101 builder: Builder to append lines to. 102 ''' 103 policy_part_name = policy['name'] + '_Part' 104 self._AddGuiString(policy_part_name, policy['label']) 105 106 # Print the PART ... END PART section: 107 builder.AddLine() 108 adm_type = self.TYPE_TO_INPUT[policy['type']] 109 builder.AddLine('PART !!%s %s' % (policy_part_name, adm_type), 1) 110 if policy['type'] in ('list', 'string-enum-list'): 111 # Note that the following line causes FullArmor ADMX Migrator to create 112 # corrupt ADMX files. Please use admx_writer to get ADMX files. 113 builder.AddLine('KEYNAME "%s\\%s"' % (key_name, policy['name'])) 114 builder.AddLine('VALUEPREFIX ""') 115 else: 116 builder.AddLine('VALUENAME "%s"' % policy['name']) 117 if policy['type'] == 'int': 118 # The default max for NUMERIC values is 9999 which is too small for us. 119 builder.AddLine('MIN 0 MAX 2000000000') 120 if policy['type'] in ('int-enum', 'string-enum'): 121 builder.AddLine('ITEMLIST', 1) 122 for item in policy['items']: 123 if policy['type'] == 'int-enum': 124 value_text = 'NUMERIC ' + str(item['value']) 125 else: 126 value_text = '"' + item['value'] + '"' 127 builder.AddLine('NAME !!%s_DropDown VALUE %s' % 128 (item['name'], value_text)) 129 self._AddGuiString(item['name'] + '_DropDown', item['caption']) 130 builder.AddLine('END ITEMLIST', -1) 131 builder.AddLine('END PART', -1) 132 133 def _WritePolicy(self, policy, key_name, builder): 134 if policy['type'] == 'external': 135 # This type can only be set through cloud policy. 136 return 137 138 self._AddGuiString(policy['name'] + '_Policy', policy['caption']) 139 builder.AddLine('POLICY !!%s_Policy' % policy['name'], 1) 140 self._WriteSupported(builder) 141 policy_explain_name = policy['name'] + '_Explain' 142 self._AddGuiString(policy_explain_name, policy['desc']) 143 builder.AddLine('EXPLAIN !!' + policy_explain_name) 144 145 if policy['type'] == 'main': 146 builder.AddLine('VALUENAME "%s"' % policy['name']) 147 builder.AddLine('VALUEON NUMERIC 1') 148 builder.AddLine('VALUEOFF NUMERIC 0') 149 else: 150 self._WritePart(policy, key_name, builder) 151 152 builder.AddLine('END POLICY', -1) 153 builder.AddLine() 154 155 def WritePolicy(self, policy): 156 if self.CanBeMandatory(policy): 157 self._WritePolicy(policy, 158 self.config['win_reg_mandatory_key_name'], 159 self.policies) 160 161 def WriteRecommendedPolicy(self, policy): 162 self._WritePolicy(policy, 163 self.config['win_reg_recommended_key_name'], 164 self.recommended_policies) 165 166 def BeginPolicyGroup(self, group): 167 category_name = group['name'] + '_Category' 168 self._AddGuiString(category_name, group['caption']) 169 self.policies.AddLine('CATEGORY !!' + category_name, 1) 170 171 def EndPolicyGroup(self): 172 self.policies.AddLine('END CATEGORY', -1) 173 self.policies.AddLine('') 174 175 def BeginRecommendedPolicyGroup(self, group): 176 category_name = group['name'] + '_Category' 177 self._AddGuiString(category_name, group['caption']) 178 self.recommended_policies.AddLine('CATEGORY !!' + category_name, 1) 179 180 def EndRecommendedPolicyGroup(self): 181 self.recommended_policies.AddLine('END CATEGORY', -1) 182 self.recommended_policies.AddLine('') 183 184 def _CreateTemplate(self, category_path, key_name, policies): 185 '''Creates the whole ADM template except for the [Strings] section, and 186 returns it as an |IndentedStringBuilder|. 187 188 Args: 189 category_path: List of strings representing the category path. 190 key_name: Main registry key backing the policies. 191 policies: ADM code for all the policies in an |IndentedStringBuilder|. 192 ''' 193 lines = IndentedStringBuilder() 194 for part in category_path: 195 lines.AddLine('CATEGORY !!' + part, 1) 196 lines.AddLine('KEYNAME "%s"' % key_name) 197 lines.AddLine() 198 199 lines.AddLines(policies) 200 201 for part in category_path: 202 lines.AddLine('END CATEGORY', -1) 203 lines.AddLine() 204 205 return lines 206 207 def BeginTemplate(self): 208 self._AddGuiString(self.config['win_supported_os'], 209 self.messages['win_supported_winxpsp2']['text']) 210 category_path = self.config['win_mandatory_category_path'] 211 recommended_category_path = self.config['win_recommended_category_path'] 212 recommended_name = '%s - %s' % \ 213 (self.config['app_name'], self.messages['doc_recommended']['text']) 214 if self.config['build'] == 'chrome': 215 self._AddGuiString(category_path[0], 'Google') 216 self._AddGuiString(category_path[1], self.config['app_name']) 217 self._AddGuiString(recommended_category_path[1], recommended_name) 218 elif self.config['build'] == 'chromium': 219 self._AddGuiString(category_path[0], self.config['app_name']) 220 self._AddGuiString(recommended_category_path[0], recommended_name) 221 # All the policies will be written into self.policies. 222 # The final template text will be assembled into self.lines by 223 # self.EndTemplate(). 224 225 def EndTemplate(self): 226 # Copy policies into self.lines. 227 policy_class = self.config['win_group_policy_class'].upper() 228 for class_name in ['MACHINE', 'USER']: 229 if policy_class != 'BOTH' and policy_class != class_name: 230 continue 231 self.lines.AddLine('CLASS ' + class_name, 1) 232 self.lines.AddLines(self._CreateTemplate( 233 self.config['win_mandatory_category_path'], 234 self.config['win_reg_mandatory_key_name'], 235 self.policies)) 236 self.lines.AddLines(self._CreateTemplate( 237 self.config['win_recommended_category_path'], 238 self.config['win_reg_recommended_key_name'], 239 self.recommended_policies)) 240 self.lines.AddLine('', -1) 241 # Copy user strings into self.lines. 242 self.lines.AddLine('[Strings]') 243 self.lines.AddLines(self.strings) 244 245 def Init(self): 246 # String buffer for building the whole ADM file. 247 self.lines = IndentedStringBuilder() 248 # String buffer for building the strings section of the ADM file. 249 self.strings = IndentedStringBuilder() 250 # Map of strings seen, to avoid duplicates. 251 self.strings_seen = {} 252 # String buffer for building the policies of the ADM file. 253 self.policies = IndentedStringBuilder() 254 # String buffer for building the recommended policies of the ADM file. 255 self.recommended_policies = IndentedStringBuilder() 256 257 def GetTemplateText(self): 258 return self.lines.ToString() 259