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
6from xml.dom import minidom
7from grit.format.policy_templates.writers import xml_formatted_writer
8
9
10def GetWriter(config):
11  '''Factory method for instanciating the ADMLWriter. Every Writer needs a
12  GetWriter method because the TemplateFormatter uses this method to
13  instantiate a Writer.
14  '''
15  return ADMLWriter(['win'], config)
16
17
18class ADMLWriter(xml_formatted_writer.XMLFormattedWriter):
19  ''' Class for generating an ADML policy template. It is used by the
20  PolicyTemplateGenerator to write the ADML file.
21  '''
22
23  # DOM root node of the generated ADML document.
24  _doc = None
25
26  # The string-table contains all ADML "string" elements.
27  _string_table_elem = None
28
29  # The presentation-table is the container for presentation elements, that
30  # describe the presentation of Policy-Groups and Policies.
31  _presentation_table_elem = None
32
33  def _AddString(self, parent, id, text):
34    ''' Adds an ADML "string" element to the passed parent. The following
35    ADML snippet contains an example:
36
37    <string id="$(id)">$(text)</string>
38
39    Args:
40      parent: Parent element to which the new "string" element is added.
41      id: ID of the newly created "string" element.
42      text: Value of the newly created "string" element.
43    '''
44    string_elem = self.AddElement(parent, 'string', {'id': id})
45    string_elem.appendChild(self._doc.createTextNode(text))
46
47  def WritePolicy(self, policy):
48    '''Generates the ADML elements for a Policy.
49    <stringTable>
50      ...
51      <string id="$(policy_group_name)">$(caption)</string>
52      <string id="$(policy_group_name)_Explain">$(description)</string>
53    </stringTable>
54
55    <presentationTables>
56      ...
57      <presentation id=$(policy_group_name)/>
58    </presentationTables>
59
60    Args:
61      policy: The Policy to generate ADML elements for.
62    '''
63    policy_type = policy['type']
64    policy_name = policy['name']
65    if 'caption' in policy:
66      policy_caption = policy['caption']
67    else:
68      policy_caption = policy_name
69    if 'desc' in policy:
70      policy_description = policy['desc']
71    else:
72      policy_description = policy_name
73    if 'label' in policy:
74      policy_label = policy['label']
75    else:
76      policy_label = policy_name
77
78    self._AddString(self._string_table_elem, policy_name, policy_caption)
79    self._AddString(self._string_table_elem, policy_name + '_Explain',
80                    policy_description)
81    presentation_elem = self.AddElement(
82        self._presentation_table_elem, 'presentation', {'id': policy_name})
83
84    if policy_type == 'main':
85      pass
86    elif policy_type in ('string', 'dict'):
87      # 'dict' policies are configured as JSON-encoded strings on Windows.
88      textbox_elem = self.AddElement(presentation_elem, 'textBox',
89                                     {'refId': policy_name})
90      label_elem = self.AddElement(textbox_elem, 'label')
91      label_elem.appendChild(self._doc.createTextNode(policy_label))
92    elif policy_type == 'int':
93      textbox_elem = self.AddElement(presentation_elem, 'decimalTextBox',
94                                     {'refId': policy_name})
95      textbox_elem.appendChild(self._doc.createTextNode(policy_label + ':'))
96    elif policy_type in ('int-enum', 'string-enum'):
97      for item in policy['items']:
98        self._AddString(self._string_table_elem, item['name'], item['caption'])
99      dropdownlist_elem = self.AddElement(presentation_elem, 'dropdownList',
100                                          {'refId': policy_name})
101      dropdownlist_elem.appendChild(self._doc.createTextNode(policy_label))
102    elif policy_type == 'list':
103      self._AddString(self._string_table_elem,
104                      policy_name + 'Desc',
105                      policy_caption)
106      listbox_elem = self.AddElement(presentation_elem, 'listBox',
107                                     {'refId': policy_name + 'Desc'})
108      listbox_elem.appendChild(self._doc.createTextNode(policy_label))
109    elif policy_type == 'group':
110      pass
111    else:
112      raise Exception('Unknown policy type %s.' % policy_type)
113
114  def BeginPolicyGroup(self, group):
115    '''Generates ADML elements for a Policy-Group. For each Policy-Group two
116    ADML "string" elements are added to the string-table. One contains the
117    caption of the Policy-Group and the other a description. A Policy-Group also
118    requires an ADML "presentation" element that must be added to the
119    presentation-table. The "presentation" element is the container for the
120    elements that define the visual presentation of the Policy-Goup's Policies.
121    The following ADML snippet shows an example:
122
123    Args:
124      group: The Policy-Group to generate ADML elements for.
125    '''
126    # Add ADML "string" elements to the string-table that are required by a
127    # Policy-Group.
128    self._AddString(self._string_table_elem, group['name'] + '_group',
129                    group['caption'])
130
131  def _AddBaseStrings(self, string_table_elem, build):
132    ''' Adds ADML "string" elements to the string-table that are referenced by
133    the ADMX file but not related to any specific Policy-Group or Policy.
134    '''
135    self._AddString(string_table_elem, self.config['win_supported_os'],
136                    self.messages['win_supported_winxpsp2']['text'])
137    recommended_name = '%s - %s' % \
138        (self.config['app_name'], self.messages['doc_recommended']['text'])
139    if build == 'chrome':
140      self._AddString(string_table_elem,
141                      self.config['win_mandatory_category_path'][0],
142                      'Google')
143      self._AddString(string_table_elem,
144                      self.config['win_mandatory_category_path'][1],
145                      self.config['app_name'])
146      self._AddString(string_table_elem,
147                      self.config['win_recommended_category_path'][1],
148                      recommended_name)
149    elif build == 'chromium':
150      self._AddString(string_table_elem,
151                      self.config['win_mandatory_category_path'][0],
152                      self.config['app_name'])
153      self._AddString(string_table_elem,
154                      self.config['win_recommended_category_path'][0],
155                      recommended_name)
156
157  def BeginTemplate(self):
158    dom_impl = minidom.getDOMImplementation('')
159    self._doc = dom_impl.createDocument(None, 'policyDefinitionResources',
160                                        None)
161    policy_definitions_resources_elem = self._doc.documentElement
162    policy_definitions_resources_elem.attributes['revision'] = '1.0'
163    policy_definitions_resources_elem.attributes['schemaVersion'] = '1.0'
164
165    self.AddElement(policy_definitions_resources_elem, 'displayName')
166    self.AddElement(policy_definitions_resources_elem, 'description')
167    resources_elem = self.AddElement(policy_definitions_resources_elem,
168                                     'resources')
169    self._string_table_elem = self.AddElement(resources_elem, 'stringTable')
170    self._AddBaseStrings(self._string_table_elem, self.config['build'])
171    self._presentation_table_elem = self.AddElement(resources_elem,
172                                                   'presentationTable')
173
174  def GetTemplateText(self):
175    # Using "toprettyxml()" confuses the Windows Group Policy Editor
176    # (gpedit.msc) because it interprets whitespace characters in text between
177    # the "string" tags. This prevents gpedit.msc from displaying the category
178    # names correctly.
179    # TODO(markusheintz): Find a better formatting that works with gpedit.
180    return self._doc.toxml()
181