• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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