This file is indexed.

/usr/share/pyshared/xdg/IniFile.py is in python-xdg 0.25-4.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
"""
Base Class for DesktopEntry, IconTheme and IconData
"""

import re, os, stat, io
from xdg.Exceptions import (ParsingError, DuplicateGroupError, NoGroupError,
                            NoKeyError, DuplicateKeyError, ValidationError,
                            debug)
import xdg.Locale
from xdg.util import u
import gettext

def is_ascii(s):
    """Return True if a string consists entirely of ASCII characters."""
    try:
        s.encode('ascii', 'strict')
        return True
    except UnicodeError:
        return False

class IniFile:
    defaultGroup = ''
    fileExtension = ''

    filename = ''
    gettext_domain = None

    tainted = False

    def __init__(self, filename=None):
        self.content = dict()
        if filename:
            self.parse(filename)

    def __cmp__(self, other):
        return cmp(self.content, other.content)

    def parse(self, filename, headers=None):
        '''Parse an INI file.
        
        headers -- list of headers the parser will try to select as a default header
        '''
        # for performance reasons
        content = self.content

        if not os.path.isfile(filename):
            raise ParsingError("File not found", filename)

        try:
            # The content should be UTF-8, but legacy files can have other
            # encodings, including mixed encodings in one file. We don't attempt
            # to decode them, but we silence the errors.
            fd = io.open(filename, 'r', encoding='utf-8', errors='replace')
        except IOError as e:
            if debug:
                raise e
            else:
                return

        # parse file
        for line in fd:
            line = line.strip()
            # empty line
            if not line:
                continue
            # comment
            elif line[0] == '#':
                continue
            # new group
            elif line[0] == '[':
                currentGroup = line.lstrip("[").rstrip("]")
                if debug and self.hasGroup(currentGroup):
                    raise DuplicateGroupError(currentGroup, filename)
                else:
                    content[currentGroup] = {}
            # key
            else:
                try:
                    key, value = line.split("=", 1)
                except ValueError:
                    raise ParsingError("Invalid line: " + line, filename)
                
                key = key.strip() # Spaces before/after '=' should be ignored
                try:
                    if debug and self.hasKey(key, currentGroup):
                        raise DuplicateKeyError(key, currentGroup, filename)
                    else:
                        content[currentGroup][key] = value.strip()
                except (IndexError, UnboundLocalError):
                    raise ParsingError("Parsing error on key, group missing", filename)

        fd.close()

        self.filename = filename
        self.tainted = False

        # check header
        if headers:
            for header in headers:
                if header in content:
                    self.defaultGroup = header
                    break
            else:
                raise ParsingError("[%s]-Header missing" % headers[0], filename)

        # check for gettext domain
        e = self.content.get('Desktop Entry', {})
        self.gettext_domain = e.get('X-GNOME-Gettext-Domain',
            e.get('X-Ubuntu-Gettext-Domain', None))

    # start stuff to access the keys
    def get(self, key, group=None, locale=False, type="string", list=False):
        # set default group
        if not group:
            group = self.defaultGroup

        # return key (with locale)
        if (group in self.content) and (key in self.content[group]):
            if locale:
                key = self.__addLocale(key, group)
                if key.endswith(']') or not self.gettext_domain:
                    # inline translations
                    value = self.content[group][key]
                else:
                    value = gettext.dgettext(self.gettext_domain, self.content[group][key])
            else:
                value = self.content[group][key]
        else:
            if debug:
                if group not in self.content:
                    raise NoGroupError(group, self.filename)
                elif key not in self.content[group]:
                    raise NoKeyError(key, group, self.filename)
            else:
                value = ""

        if list == True:
            values = self.getList(value)
            result = []
        else:
            values = [value]

        for value in values:
            if type == "boolean":
                value = self.__getBoolean(value)
            elif type == "integer":
                try:
                    value = int(value)
                except ValueError:
                    value = 0
            elif type == "numeric":
                try:
                    value = float(value)
                except ValueError:
                    value = 0.0
            elif type == "regex":
                value = re.compile(value)
            elif type == "point":
                x, y = value.split(",")
                value = int(x), int(y)

            if list == True:
                result.append(value)
            else:
                result = value

        return result
    # end stuff to access the keys

    # start subget
    def getList(self, string):
        if re.search(r"(?<!\\)\;", string):
            list = re.split(r"(?<!\\);", string)
        elif re.search(r"(?<!\\)\|", string):
            list = re.split(r"(?<!\\)\|", string)
        elif re.search(r"(?<!\\),", string):
            list = re.split(r"(?<!\\),", string)
        else:
            list = [string]
        if list[-1] == "":
            list.pop()
        return list

    def __getBoolean(self, boolean):
        if boolean == 1 or boolean == "true" or boolean == "True":
            return True
        elif boolean == 0 or boolean == "false" or boolean == "False":
            return False
        return False
    # end subget

    def __addLocale(self, key, group=None):
        "add locale to key according the current lc_messages"
        # set default group
        if not group:
            group = self.defaultGroup

        for lang in xdg.Locale.langs:
            langkey = "%s[%s]" % (key, lang)
            if langkey in self.content[group]:
                return langkey

        return key

    # start validation stuff
    def validate(self, report="All"):
        """Validate the contents, raising ``ValidationError`` if there
        is anything amiss.
        
        report can be 'All' / 'Warnings' / 'Errors'
        """

        self.warnings = []
        self.errors = []

        # get file extension
        self.fileExtension = os.path.splitext(self.filename)[1]

        # overwrite this for own checkings
        self.checkExtras()

        # check all keys
        for group in self.content:
            self.checkGroup(group)
            for key in self.content[group]:
                self.checkKey(key, self.content[group][key], group)
                # check if value is empty
                if self.content[group][key] == "":
                    self.warnings.append("Value of Key '%s' is empty" % key)

        # raise Warnings / Errors
        msg = ""

        if report == "All" or report == "Warnings":
            for line in self.warnings:
                msg += "\n- " + line

        if report == "All" or report == "Errors":
            for line in self.errors:
                msg += "\n- " + line

        if msg:
            raise ValidationError(msg, self.filename)

    # check if group header is valid
    def checkGroup(self, group):
        pass

    # check if key is valid
    def checkKey(self, key, value, group):
        pass

    # check random stuff
    def checkValue(self, key, value, type="string", list=False):
        if list == True:
            values = self.getList(value)
        else:
            values = [value]

        for value in values:
            if type == "string":
                code = self.checkString(value)
            if type == "localestring":
                continue
            elif type == "boolean":
                code = self.checkBoolean(value)
            elif type == "numeric":
                code = self.checkNumber(value)
            elif type == "integer":
                code = self.checkInteger(value)
            elif type == "regex":
                code = self.checkRegex(value)
            elif type == "point":
                code = self.checkPoint(value)
            if code == 1:
                self.errors.append("'%s' is not a valid %s" % (value, type))
            elif code == 2:
                self.warnings.append("Value of key '%s' is deprecated" % key)

    def checkExtras(self):
        pass

    def checkBoolean(self, value):
        # 1 or 0 : deprecated
        if (value == "1" or value == "0"):
            return 2
        # true or false: ok
        elif not (value == "true" or value == "false"):
            return 1

    def checkNumber(self, value):
        # float() ValueError
        try:
            float(value)
        except:
            return 1

    def checkInteger(self, value):
        # int() ValueError
        try:
            int(value)
        except:
            return 1

    def checkPoint(self, value):
        if not re.match("^[0-9]+,[0-9]+$", value):
            return 1

    def checkString(self, value):
        return 0 if is_ascii(value) else 1

    def checkRegex(self, value):
        try:
            re.compile(value)
        except:
            return 1

    # write support
    def write(self, filename=None, trusted=False):
        if not filename and not self.filename:
            raise ParsingError("File not found", "")

        if filename:
            self.filename = filename
        else:
            filename = self.filename

        if os.path.dirname(filename) and not os.path.isdir(os.path.dirname(filename)):
            os.makedirs(os.path.dirname(filename))

        with io.open(filename, 'w', encoding='utf-8') as fp:

            # An executable bit signifies that the desktop file is
            # trusted, but then the file can be executed. Add hashbang to
            # make sure that the file is opened by something that
            # understands desktop files.
            if trusted:
                fp.write(u("#!/usr/bin/env xdg-open\n"))

            if self.defaultGroup:
                fp.write(u("[%s]\n") % self.defaultGroup)
                for (key, value) in self.content[self.defaultGroup].items():
                    fp.write(u("%s=%s\n") % (key, value))
                fp.write(u("\n"))
            for (name, group) in self.content.items():
                if name != self.defaultGroup:
                    fp.write(u("[%s]\n") % name)
                    for (key, value) in group.items():
                        fp.write(u("%s=%s\n") % (key, value))
                    fp.write(u("\n"))

        # Add executable bits to the file to show that it's trusted.
        if trusted:
            oldmode = os.stat(filename).st_mode
            mode = oldmode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
            os.chmod(filename, mode)

        self.tainted = False

    def set(self, key, value, group=None, locale=False):
        # set default group
        if not group:
            group = self.defaultGroup

        if locale == True and len(xdg.Locale.langs) > 0:
            key = key + "[" + xdg.Locale.langs[0] + "]"

        try:
            self.content[group][key] = value
        except KeyError:
            raise NoGroupError(group, self.filename)
            
        self.tainted = (value == self.get(key, group))

    def addGroup(self, group):
        if self.hasGroup(group):
            if debug:
                raise DuplicateGroupError(group, self.filename)
        else:
            self.content[group] = {}
            self.tainted = True

    def removeGroup(self, group):
        existed = group in self.content
        if existed:
            del self.content[group]
            self.tainted = True
        else:
            if debug:
                raise NoGroupError(group, self.filename)
        return existed

    def removeKey(self, key, group=None, locales=True):
        # set default group
        if not group:
            group = self.defaultGroup

        try:
            if locales:
                for name in list(self.content[group]):
                    if re.match("^" + key + xdg.Locale.regex + "$", name) and name != key:
                        del self.content[group][name]
            value = self.content[group].pop(key)
            self.tainted = True
            return value
        except KeyError as e:
            if debug:
                if e == group:
                    raise NoGroupError(group, self.filename)
                else:
                    raise NoKeyError(key, group, self.filename)
            else:
                return ""

    # misc
    def groups(self):
        return self.content.keys()

    def hasGroup(self, group):
        return group in self.content

    def hasKey(self, key, group=None):
        # set default group
        if not group:
            group = self.defaultGroup

        return key in self.content[group]

    def getFileName(self):
        return self.filename