def ParseRow(self, parser_mediator, query, row, **unused_kwargs):
        """Parses a row from the database.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
          and other components, such as storage and dfvfs.
      query (str): query that created the row.
      row (sqlite3.Row): row.
    """
        query_hash = hash(query)

        event_data = AndroidWebViewCacheEventData()
        event_data.content_length = self._GetRowValue(query_hash, row,
                                                      'contentlength')
        event_data.query = query
        event_data.url = self._GetRowValue(query_hash, row, 'url')

        timestamp = self._GetRowValue(query_hash, row, 'expires')
        if timestamp is not None:
            date_time = dfdatetime_java_time.JavaTime(timestamp=timestamp)
            event = time_events.DateTimeValuesEvent(
                date_time, definitions.TIME_DESCRIPTION_EXPIRATION)
            parser_mediator.ProduceEventWithEventData(event, event_data)

        timestamp = self._GetRowValue(query_hash, row, 'lastmodify')
        if timestamp is not None:
            date_time = dfdatetime_java_time.JavaTime(timestamp=timestamp)
            event = time_events.DateTimeValuesEvent(
                date_time, definitions.TIME_DESCRIPTION_MODIFICATION)
            parser_mediator.ProduceEventWithEventData(event, event_data)
Example #2
0
    def ParseMessageRow(self, parser_mediator, query, row, **unused_kwargs):
        """Parses a message row from the database.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
          and other components, such as storage and dfvfs.
      query (str): query that created the row.
      row (sqlite3.Row): row resulting from query.
    """
        query_hash = hash(query)

        event_data = TangoAndroidMessageEventData()
        event_data.message_identifier = self._GetRowValue(
            query_hash, row, 'msg_id')

        # TODO: payload is a base64 encoded binary blob, we need to find the
        # structure to extract the relevant bits.
        # event_data.payload = self._GetRowValue(query_hash, row, 'payload')

        event_data.direction = self._GetRowValue(query_hash, row, 'direction')

        timestamp = self._GetRowValue(query_hash, row, 'create_time')
        if timestamp:
            date_time = dfdatetime_java_time.JavaTime(timestamp=timestamp)
            event = time_events.DateTimeValuesEvent(
                date_time, definitions.TIME_DESCRIPTION_CREATION)
            parser_mediator.ProduceEventWithEventData(event, event_data)

        timestamp = self._GetRowValue(query_hash, row, 'send_time')
        if timestamp:
            date_time = dfdatetime_java_time.JavaTime(timestamp=timestamp)
            event = time_events.DateTimeValuesEvent(
                date_time, definitions.TIME_DESCRIPTION_SENT)
            parser_mediator.ProduceEventWithEventData(event, event_data)
Example #3
0
  def testProperties(self):
    """Tests the properties."""
    java_time_object = java_time.JavaTime(timestamp=1281643591546)
    self.assertEqual(java_time_object.timestamp, 1281643591546)

    java_time_object = java_time.JavaTime()
    self.assertIsNone(java_time_object.timestamp)
Example #4
0
    def ParseRow(self, parser_mediator, row, query=None, **unused_kwargs):
        """Parses a row from the database.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
          and other components, such as storage and dfvfs.
      row (sqlite3.Row): row.
      query (Optional[str]): query.
    """
        # Note that pysqlite does not accept a Unicode string in row['string']
        # and will raise "IndexError: Index must be int or string". All indexes are
        # thus raw strings.
        event_data = AndroidWebViewCacheEventData()
        event_data.content_length = row['contentlength']
        event_data.query = query
        event_data.url = row['url']

        if row['expires'] is not None:
            date_time = dfdatetime_java_time.JavaTime(timestamp=row['expires'])
            event = time_events.DateTimeValuesEvent(
                date_time, definitions.TIME_DESCRIPTION_EXPIRATION)
            parser_mediator.ProduceEventWithEventData(event, event_data)

        if row['lastmodify'] is not None:
            date_time = dfdatetime_java_time.JavaTime(
                timestamp=row['lastmodify'])
            event = time_events.DateTimeValuesEvent(
                date_time, definitions.TIME_DESCRIPTION_MODIFICATION)
            parser_mediator.ProduceEventWithEventData(event, event_data)
Example #5
0
  def testCopyToDateTimeString(self):
    """Tests the CopyToDateTimeString function."""
    java_time_object = java_time.JavaTime(timestamp=1281643591546)

    date_time_string = java_time_object.CopyToDateTimeString()
    self.assertEqual(date_time_string, '2010-08-12 20:06:31.546')

    java_time_object = java_time.JavaTime()

    date_time_string = java_time_object.CopyToDateTimeString()
    self.assertIsNone(date_time_string)
Example #6
0
  def testGetNormalizedTimestamp(self):
    """Tests the _GetNormalizedTimestamp function."""
    java_time_object = java_time.JavaTime(timestamp=1281643591546)

    normalized_timestamp = java_time_object._GetNormalizedTimestamp()
    self.assertEqual(normalized_timestamp, decimal.Decimal('1281643591.546'))

    java_time_object = java_time.JavaTime()

    normalized_timestamp = java_time_object._GetNormalizedTimestamp()
    self.assertIsNone(normalized_timestamp)
Example #7
0
    def testGetTimeOfDay(self):
        """Tests the GetTimeOfDay function."""
        java_time_object = java_time.JavaTime(timestamp=1281643591546)

        time_of_day_tuple = java_time_object.GetTimeOfDay()
        self.assertEqual(time_of_day_tuple, (20, 6, 31))

        java_time_object = java_time.JavaTime()

        time_of_day_tuple = java_time_object.GetTimeOfDay()
        self.assertEqual(time_of_day_tuple, (None, None, None))
Example #8
0
    def testGetDate(self):
        """Tests the GetDate function."""
        java_time_object = java_time.JavaTime(timestamp=1281643591546)

        date_tuple = java_time_object.GetDate()
        self.assertEqual(date_tuple, (2010, 8, 12))

        java_time_object = java_time.JavaTime()

        date_tuple = java_time_object.GetDate()
        self.assertEqual(date_tuple, (None, None, None))
Example #9
0
    def testGetDateWithTimeOfDay(self):
        """Tests the GetDateWithTimeOfDay function."""
        java_time_object = java_time.JavaTime(timestamp=1281643591546)

        date_with_time_of_day_tuple = java_time_object.GetDateWithTimeOfDay()
        self.assertEqual(date_with_time_of_day_tuple, (2010, 8, 12, 20, 6, 31))

        java_time_object = java_time.JavaTime()

        date_with_time_of_day_tuple = java_time_object.GetDateWithTimeOfDay()
        self.assertEqual(date_with_time_of_day_tuple,
                         (None, None, None, None, None, None))
Example #10
0
    def testGetPlasoTimestamp(self):
        """Tests the GetPlasoTimestamp function."""
        java_time_object = java_time.JavaTime(timestamp=1281643591546)

        expected_micro_posix_timestamp = 1281643591546000
        micro_posix_timestamp = java_time_object.GetPlasoTimestamp()
        self.assertEqual(micro_posix_timestamp, expected_micro_posix_timestamp)

        java_time_object = java_time.JavaTime()

        micro_posix_timestamp = java_time_object.GetPlasoTimestamp()
        self.assertIsNone(micro_posix_timestamp)
Example #11
0
    def testCopyToStatTimeTuple(self):
        """Tests the CopyToStatTimeTuple function."""
        java_time_object = java_time.JavaTime(timestamp=1281643591546)

        expected_stat_time_tuple = (1281643591, 5460000)
        stat_time_tuple = java_time_object.CopyToStatTimeTuple()
        self.assertEqual(stat_time_tuple, expected_stat_time_tuple)

        java_time_object = java_time.JavaTime()

        expected_stat_time_tuple = (None, None)
        stat_time_tuple = java_time_object.CopyToStatTimeTuple()
        self.assertEqual(stat_time_tuple, expected_stat_time_tuple)
Example #12
0
    def ParseStatusRow(self, parser_mediator, query, row, **unused_kwargs):
        """Parses a status row from the database.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
          and other components, such as storage and dfvfs.
      query (str): query that created the row.
      row (sqlite3.Row): row resulting from query.
    """
        query_hash = hash(query)

        event_data = TwitterAndroidStatusEventData()
        event_data.query = query
        event_data.identifier = self._GetRowValue(query_hash, row, '_id')
        event_data.author_identifier = self._GetRowValue(
            query_hash, row, 'author_id')
        event_data.username = self._GetRowValue(query_hash, row, 'username')
        event_data.content = self._GetRowValue(query_hash, row, 'content')
        event_data.favorited = self._GetRowValue(query_hash, row, 'favorited')
        event_data.retweeted = self._GetRowValue(query_hash, row, 'retweeted')

        timestamp = self._GetRowValue(query_hash, row, 'time')
        if timestamp:
            date_time = dfdatetime_java_time.JavaTime(timestamp=timestamp)
            event = time_events.DateTimeValuesEvent(
                date_time, definitions.TIME_DESCRIPTION_CREATION)
            parser_mediator.ProduceEventWithEventData(event, event_data)
Example #13
0
    def testCopyFromDateTimeString(self):
        """Tests the CopyFromDateTimeString function."""
        java_time_object = java_time.JavaTime()

        java_time_object.CopyFromDateTimeString('2010-08-12')
        self.assertEqual(java_time_object._timestamp, 1281571200000)
        self.assertEqual(java_time_object._time_zone_offset, 0)

        java_time_object.CopyFromDateTimeString('2010-08-12 21:06:31')
        self.assertEqual(java_time_object._timestamp, 1281647191000)
        self.assertEqual(java_time_object._time_zone_offset, 0)

        java_time_object.CopyFromDateTimeString('2010-08-12 21:06:31.546875')
        self.assertEqual(java_time_object._timestamp, 1281647191546)
        self.assertEqual(java_time_object._time_zone_offset, 0)

        java_time_object.CopyFromDateTimeString(
            '2010-08-12 21:06:31.546875-01:00')
        self.assertEqual(java_time_object._timestamp, 1281647191546)
        self.assertEqual(java_time_object._time_zone_offset, -60)

        java_time_object.CopyFromDateTimeString(
            '2010-08-12 21:06:31.546875+01:00')
        self.assertEqual(java_time_object._timestamp, 1281647191546)
        self.assertEqual(java_time_object._time_zone_offset, 60)

        java_time_object.CopyFromDateTimeString('1601-01-02 00:00:00')
        self.assertEqual(java_time_object._timestamp, -11644387200000)
        self.assertEqual(java_time_object._time_zone_offset, 0)
Example #14
0
    def ParseSmsRow(self, parser_mediator, query, row, **unused_kwargs):
        """Parses an SMS row.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
          and other components, such as storage and dfvfs.
      query (str): query that created the row.
      row (sqlite3.Row): row.
    """
        query_hash = hash(query)

        sms_read = self._GetRowValue(query_hash, row, 'read')
        sms_type = self._GetRowValue(query_hash, row, 'type')

        event_data = AndroidSMSEventData()
        event_data.address = self._GetRowValue(query_hash, row, 'address')
        event_data.body = self._GetRowValue(query_hash, row, 'body')
        event_data.offset = self._GetRowValue(query_hash, row, 'id')
        event_data.query = query
        event_data.sms_read = self.SMS_READ.get(sms_read, 'UNKNOWN')
        event_data.sms_type = self.SMS_TYPE.get(sms_type, 'UNKNOWN')

        timestamp = self._GetRowValue(query_hash, row, 'date')
        date_time = dfdatetime_java_time.JavaTime(timestamp=timestamp)
        event = time_events.DateTimeValuesEvent(
            date_time, definitions.TIME_DESCRIPTION_CREATION)
        parser_mediator.ProduceEventWithEventData(event, event_data)
Example #15
0
  def ParseCookieRow(self, parser_mediator, query, row, **unused_kwargs):
    """Parses a row from the database.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
          and other components, such as storage and dfvfs.
      query (str): query that created the row.
      row (sqlite3.Row): row.
    """
    query_hash = hash(query)

    cookie_name = self._GetRowValue(query_hash, row, 'name')
    cookie_value = self._GetRowValue(query_hash, row, 'value')
    path = self._GetRowValue(query_hash, row, 'path')

    hostname = self._GetRowValue(query_hash, row, 'domain')
    if hostname.startswith('.'):
      hostname = hostname[1:]

    secure = self._GetRowValue(query_hash, row, 'secure')
    # The WebView database stores the secure flag as a integer type,
    # but we represent it as a boolean.
    secure = secure != 0

    if secure:
      scheme = 'https'
    else:
      scheme = 'http'

    url = '{0:s}://{1:s}{2:s}'.format(scheme, hostname, path)

    event_data = WebViewCookieEventData()
    event_data.cookie_name = cookie_name
    event_data.data = cookie_value
    event_data.host = hostname
    event_data.offset = self._GetRowValue(query_hash, row, '_id')
    event_data.path = path
    event_data.query = query
    event_data.secure = secure
    event_data.url = url

    timestamp = self._GetRowValue(query_hash, row, 'expires')
    if timestamp:
      date_time = dfdatetime_java_time.JavaTime(timestamp=timestamp)
    else:
      date_time = dfdatetime_semantic_time.SemanticTime('Infinity')

    event = time_events.DateTimeValuesEvent(
        date_time, definitions.TIME_DESCRIPTION_EXPIRATION)
    parser_mediator.ProduceEventWithEventData(event, event_data)

    # Go through all cookie plugins to see if there are is any specific parsing
    # needed.
    for cookie_plugin in self._cookie_plugins:
      try:
        cookie_plugin.UpdateChainAndProcess(
            parser_mediator, cookie_name=cookie_name,
            cookie_data=cookie_value, url=url)
      except errors.WrongPlugin:
        pass
Example #16
0
    def testCopyFromString(self):
        """Tests the CopyFromString function."""
        java_time_object = java_time.JavaTime()

        expected_timestamp = 1281571200000
        java_time_object.CopyFromString(u'2010-08-12')
        self.assertEqual(java_time_object.timestamp, expected_timestamp)

        expected_timestamp = 1281647191000
        java_time_object.CopyFromString(u'2010-08-12 21:06:31')
        self.assertEqual(java_time_object.timestamp, expected_timestamp)

        expected_timestamp = 1281647191546
        java_time_object.CopyFromString(u'2010-08-12 21:06:31.546875')
        self.assertEqual(java_time_object.timestamp, expected_timestamp)

        expected_timestamp = 1281650791546
        java_time_object.CopyFromString(u'2010-08-12 21:06:31.546875-01:00')
        self.assertEqual(java_time_object.timestamp, expected_timestamp)

        expected_timestamp = 1281643591546
        java_time_object.CopyFromString(u'2010-08-12 21:06:31.546875+01:00')
        self.assertEqual(java_time_object.timestamp, expected_timestamp)

        expected_timestamp = -11644387200000
        java_time_object.CopyFromString(u'1601-01-02 00:00:00')
        self.assertEqual(java_time_object.timestamp, expected_timestamp)
Example #17
0
    def ParseZeitgeistEventRow(self,
                               parser_mediator,
                               row,
                               query=None,
                               **unused_kwargs):
        """Parses zeitgeist event row.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
          and other components, such as storage and dfvfs.
      row (sqlite3.Row): row.
      query (Optional[str]): query.
    """
        # Note that pysqlite does not accept a Unicode string in row['string'] and
        # will raise "IndexError: Index must be int or string".

        event_data = ZeitgeistActivityEventData()
        event_data.offset = row['id']
        event_data.query = query
        event_data.subject_uri = row['subj_uri']

        date_time = dfdatetime_java_time.JavaTime(timestamp=row['timestamp'])
        event = time_events.DateTimeValuesEvent(
            date_time, eventdata.EventTimestamp.UNKNOWN)
        parser_mediator.ProduceEventWithEventData(event, event_data)
Example #18
0
    def ParseContactRow(self, parser_mediator, query, row, **unused_kwargs):
        """Parses a status row from the database.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
          and other components, such as storage and dfvfs.
      query (str): query that created the row.
      row (sqlite3.Row): row resulting from query.
    """
        query_hash = hash(query)

        event_data = TwitterAndroidContactEventData()
        event_data.query = query
        event_data.identifier = self._GetRowValue(query_hash, row, '_id')
        event_data.user_identifier = self._GetRowValue(query_hash, row,
                                                       'user_id')
        event_data.username = self._GetRowValue(query_hash, row, 'username')
        event_data.name = self._GetRowValue(query_hash, row, 'name')
        event_data.description = self._GetRowValue(query_hash, row,
                                                   'description')
        event_data.web_url = self._GetRowValue(query_hash, row, 'web_url')
        event_data.location = self._GetRowValue(query_hash, row, 'location')
        event_data.followers = self._GetRowValue(query_hash, row, 'followers')
        event_data.friends = self._GetRowValue(query_hash, row, 'friends')
        event_data.statuses = self._GetRowValue(query_hash, row, 'statuses')
        event_data.image_url = self._GetRowValue(query_hash, row, 'image_url')

        timestamp = self._GetRowValue(query_hash, row, 'profile_created')
        if timestamp:
            date_time = dfdatetime_java_time.JavaTime(timestamp=timestamp)
            event = time_events.DateTimeValuesEvent(
                date_time, definitions.TIME_DESCRIPTION_CREATION)
            parser_mediator.ProduceEventWithEventData(event, event_data)

        timestamp = self._GetRowValue(query_hash, row, 'updated')
        if timestamp:
            date_time = dfdatetime_java_time.JavaTime(timestamp=timestamp)
            event = time_events.DateTimeValuesEvent(
                date_time, definitions.TIME_DESCRIPTION_UPDATE)
            parser_mediator.ProduceEventWithEventData(event, event_data)

        timestamp = self._GetRowValue(query_hash, row, 'friendship_time')
        if timestamp:
            date_time = dfdatetime_java_time.JavaTime(timestamp=timestamp)
            event = time_events.DateTimeValuesEvent(
                date_time, definitions.TIME_DESCRIPTION_MODIFICATION)
            parser_mediator.ProduceEventWithEventData(event, event_data)
Example #19
0
    def ParseFileObject(self, parser_mediator, file_object):
        """Parses an Android usage-history file-like object.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
          and other components, such as storage and dfvfs.
      file_object (dfvfs.FileIO): file-like object.

    Raises:
      UnableToParseFile: when the file cannot be parsed.
    """
        data = file_object.read(self._HEADER_READ_SIZE)
        if not data.startswith(b'<?xml'):
            raise errors.UnableToParseFile(
                'Not an Android usage history file [not XML]')

        _, _, data = data.partition(b'\n')
        if not data.startswith(b'<usage-history'):
            raise errors.UnableToParseFile(
                'Not an Android usage history file [wrong XML root key]')

        # The current offset of the file-like object needs to point at
        # the start of the file for ElementTree to parse the XML data correctly.
        file_object.seek(0, os.SEEK_SET)

        xml = ElementTree.parse(file_object)
        root_node = xml.getroot()

        for application_node in root_node:
            package_name = application_node.get('name', None)

            for part_node in application_node.iter():
                if part_node.tag != 'comp':
                    continue

                last_resume_time = part_node.get('lrt', None)
                if last_resume_time is None:
                    parser_mediator.ProduceExtractionWarning(
                        'missing last resume time.')
                    continue

                try:
                    last_resume_time = int(last_resume_time, 10)
                except ValueError:
                    parser_mediator.ProduceExtractionWarning(
                        'unsupported last resume time: {0:s}.'.format(
                            last_resume_time))
                    continue

                event_data = AndroidAppUsageEventData()
                event_data.component = part_node.get('name', None)
                event_data.package = package_name

                date_time = dfdatetime_java_time.JavaTime(
                    timestamp=last_resume_time)
                event = time_events.DateTimeValuesEvent(
                    date_time, definitions.TIME_DESCRIPTION_LAST_RESUME)
                parser_mediator.ProduceEventWithEventData(event, event_data)
Example #20
0
    def ParseCallsRow(self, parser_mediator, query, row, **unused_kwargs):
        """Parses a Call record row.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
          and other components, such as storage and dfvfs.
      query (str): query that created the row.
      row (sqlite3.Row): row.
    """
        query_hash = hash(query)

        call_type = self._GetRowValue(query_hash, row, 'type')
        call_type = self.CALL_TYPE.get(call_type, 'UNKNOWN')
        duration = self._GetRowValue(query_hash, row, 'duration')
        timestamp = self._GetRowValue(query_hash, row, 'date')

        event_data = AndroidCallEventData()
        event_data.call_type = call_type
        event_data.duration = self._GetRowValue(query_hash, row, 'duration')
        event_data.name = self._GetRowValue(query_hash, row, 'name')
        event_data.number = self._GetRowValue(query_hash, row, 'number')
        event_data.offset = self._GetRowValue(query_hash, row, 'id')
        event_data.query = query

        date_time = dfdatetime_java_time.JavaTime(timestamp=timestamp)
        event = time_events.DateTimeValuesEvent(date_time, 'Call Started')
        parser_mediator.ProduceEventWithEventData(event, event_data)

        if duration:
            if isinstance(duration, str):
                try:
                    duration = int(duration, 10)
                except ValueError:
                    duration = 0

            # The duration is in seconds and the date value in milliseconds.
            timestamp += duration * 1000

            date_time = dfdatetime_java_time.JavaTime(timestamp=timestamp)
            event = time_events.DateTimeValuesEvent(date_time, 'Call Ended')
            parser_mediator.ProduceEventWithEventData(event, event_data)
Example #21
0
    def ParseCallsRow(self, parser_mediator, row, query=None, **unused_kwargs):
        """Parses a Call record row.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
          and other components, such as storage and dfvfs.
      row (sqlite3.Row): row.
      query (Optional[str]): query.
    """
        # Note that pysqlite does not accept a Unicode string in row['string'] and
        # will raise "IndexError: Index must be int or string".

        call_type = self.CALL_TYPE.get(row['type'], u'UNKNOWN')
        duration = row['duration']
        timestamp = row['date']

        event_data = AndroidCallEventData()
        event_data.call_type = call_type
        event_data.duration = row['duration']
        event_data.name = row['name']
        event_data.number = row['number']
        event_data.offset = row['id']
        event_data.query = query

        date_time = dfdatetime_java_time.JavaTime(timestamp=timestamp)
        event = time_events.DateTimeValuesEvent(date_time, u'Call Started')
        parser_mediator.ProduceEventWithEventData(event, event_data)

        if duration:
            if isinstance(duration, py2to3.STRING_TYPES):
                try:
                    duration = int(duration, 10)
                except ValueError:
                    duration = 0

            # The duration is in seconds and the date value in milliseconds.
            timestamp += duration * 1000

            date_time = dfdatetime_java_time.JavaTime(timestamp=timestamp)
            event = time_events.DateTimeValuesEvent(date_time, u'Call Ended')
            parser_mediator.ProduceEventWithEventData(event, event_data)
    def ParseLibrary(self,
                     parser_mediator,
                     cache=None,
                     database=None,
                     table=None,
                     **unused_kwargs):
        """Parses the library table.
    Args:
    """
        if database is None:
            raise ValueError('Missing database value.')

        if table is None:
            raise ValueError('Missing table value.')

        strings = cache.GetResults('strings')
        if not strings:
            esedb_table = database.get_table_by_name('string')
            strings = self._GetDictFromStringsTable(parser_mediator,
                                                    esedb_table)
            cache.StoreDictInCache('string', strings)

        backup_folder_list = ""

        event_data = FileHistoryLibraryEventData()
        for esedb_record in table.records:
            if parser_mediator.abort:
                break

            record_values = self._GetRecordValues(parser_mediator, table.name,
                                                  esedb_record)

            parentid = record_values.get('parentId')
            childid = record_values.get('childId')
            backup_folder_list += str(strings.get(parentid)) + "\\" \
                                  + str(strings.get(childid)) + ","

        event_data.backup_folder = backup_folder_list
        date_time = dfdatetime_java_time.JavaTime(timestamp=0)
        event = time_events.DateTimeValuesEvent(
            date_time, definitions.TIME_DESCRIPTION_NOT_A_TIME)
        parser_mediator.ProduceEventWithEventData(event, event_data)
Example #23
0
    def ParseZeitgeistEventRow(self, parser_mediator, query, row,
                               **unused_kwargs):
        """Parses a zeitgeist event row.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
          and other components, such as storage and dfvfs.
      query (str): query that created the row.
      row (sqlite3.Row): row.
    """
        query_hash = hash(query)

        event_data = ZeitgeistActivityEventData()
        event_data.offset = self._GetRowValue(query_hash, row, 'id')
        event_data.query = query
        event_data.subject_uri = self._GetRowValue(query_hash, row, 'subj_uri')

        timestamp = self._GetRowValue(query_hash, row, 'timestamp')
        date_time = dfdatetime_java_time.JavaTime(timestamp=timestamp)
        event = time_events.DateTimeValuesEvent(
            date_time, definitions.TIME_DESCRIPTION_UNKNOWN)
        parser_mediator.ProduceEventWithEventData(event, event_data)
Example #24
0
    def ParseSmsRow(self, parser_mediator, row, query=None, **unused_kwargs):
        """Parses an SMS row.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
          and other components, such as storage and dfvfs.
      row (sqlite3.Row): row.
      query (Optional[str]): query.
    """
        # Note that pysqlite does not accept a Unicode string in row['string'] and
        # will raise "IndexError: Index must be int or string".

        event_data = AndroidSMSEventData()
        event_data.address = row['address']
        event_data.body = row['body']
        event_data.offset = row['id']
        event_data.query = query
        event_data.sms_read = self.SMS_READ.get(row['read'], u'UNKNOWN')
        event_data.sms_type = self.SMS_TYPE.get(row['type'], u'UNKNOWN')

        date_time = dfdatetime_java_time.JavaTime(timestamp=row['date'])
        event = time_events.DateTimeValuesEvent(
            date_time, definitions.TIME_DESCRIPTION_CREATION)
        parser_mediator.ProduceEventWithEventData(event, event_data)
Example #25
0
    def ParseContactRow(self, parser_mediator, query, row, **unused_kwargs):
        """Parses a contact row from the database.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
          and other components, such as storage and dfvfs.
      query (str): query that created the row.
      row (sqlite3.Row): row resulting from query.
    """
        query_hash = hash(query)

        event_data = TangoAndroidContactEventData()

        first_name = self._GetRowValue(query_hash, row, 'first_name')
        try:
            decoded_text = base64_decode(first_name)
            event_data.first_name = codecs.decode(decoded_text, 'utf-8')
        except ValueError:
            event_data.first_name = first_name
            parser_mediator.ProduceExtractionError(
                'unable to parse first name: {0:s}'.format(first_name))

        last_name = self._GetRowValue(query_hash, row, 'last_name')
        try:
            decoded_text = base64_decode(last_name)
            event_data.last_name = codecs.decode(decoded_text, 'utf-8')
        except ValueError:
            event_data.last_name = last_name
            parser_mediator.ProduceExtractionError(
                'unable to parse last name: {0:s}'.format(last_name))

        event_data.birthday = self._GetRowValue(query_hash, row, 'birthday')
        event_data.gender = self._GetRowValue(query_hash, row, 'gender')

        status = self._GetRowValue(query_hash, row, 'status')
        try:
            decoded_text = base64_decode(status)
            event_data.status = codecs.decode(decoded_text, 'utf-8')
        except ValueError:
            event_data.status = status
            parser_mediator.ProduceExtractionError(
                'unable to parse status: {0:s}'.format(status))

        event_data.distance = self._GetRowValue(query_hash, row, 'distance')

        is_friend = self._GetRowValue(query_hash, row, 'friend')
        event_data.is_friend = False
        if is_friend:
            event_data.is_friend = True

        event_data.friend_request_type = self._GetRowValue(
            query_hash, row, 'friend_request_type')

        friend_request_message = self._GetRowValue(query_hash, row,
                                                   'friend_request_message')
        try:
            decoded_text = base64_decode(friend_request_message)
            event_data.friend_request_message = codecs.decode(
                decoded_text, 'utf-8')
        except ValueError:
            event_data.friend_request_message = friend_request_message
            parser_mediator.ProduceExtractionError(
                'unable to parse status: {0:s}'.format(friend_request_message))

        timestamp = self._GetRowValue(query_hash, row, 'last_active_time')
        if timestamp:
            date_time = dfdatetime_java_time.JavaTime(timestamp=timestamp)
            event = time_events.DateTimeValuesEvent(
                date_time, definitions.TIME_DESCRIPTION_LAST_ACTIVE)
            parser_mediator.ProduceEventWithEventData(event, event_data)

        timestamp = self._GetRowValue(query_hash, row, 'last_access_time')
        if timestamp:
            date_time = dfdatetime_java_time.JavaTime(timestamp=timestamp)
            event = time_events.DateTimeValuesEvent(
                date_time, definitions.TIME_DESCRIPTION_LAST_ACCESS)
            parser_mediator.ProduceEventWithEventData(event, event_data)

        timestamp = self._GetRowValue(query_hash, row, 'friend_request_time')
        if timestamp:
            date_time = dfdatetime_java_time.JavaTime(timestamp=timestamp)
            event = time_events.DateTimeValuesEvent(
                date_time, definitions.TIME_DESCRIPTION_SENT)
            parser_mediator.ProduceEventWithEventData(event, event_data)
Example #26
0
  def ParseReceiverData(
      self, parser_mediator, row, query=None, **unused_kwargs):
    """Parses a single row from the receiver and cache response table.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
          and other components, such as storage and dfvfs.
      row (sqlite3.Row): row.
      query (Optional[str]): query.
    """
    # Note that pysqlite does not accept a Unicode string in row['string'] and
    # will raise "IndexError: Index must be int or string".

    data = {}
    key_url = row['request_key']

    data_dict = {}
    description = u'MacKeeper Entry'
    # Check the URL, since that contains vital information about the type of
    # event we are dealing with.
    if key_url.endswith(u'plist'):
      description = u'Configuration Definition'
      data[u'text'] = u'Plist content added to cache.'

    elif key_url.startswith(u'http://event.zeobit.com'):
      description = u'MacKeeper Event'
      try:
        _, _, part = key_url.partition(u'?')
        data[u'text'] = part.replace(u'&', u' ')
      except UnicodeDecodeError:
        data[u'text'] = u'N/A'

    elif key_url.startswith(u'http://account.zeobit.com'):
      description = u'Account Activity'
      _, _, activity = key_url.partition(u'#')
      if activity:
        data[u'text'] = u'Action started: {0:s}'.format(activity)
      else:
        data[u'text'] = u'Unknown activity.'

    elif key_url.startswith(u'http://support.') and u'chat' in key_url:
      description = u'Chat '
      try:
        jquery = codecs.decode(row['data'], u'utf-8')
      except UnicodeDecodeError:
        jquery = u''

      data_dict = self._ExtractJQuery(jquery)
      data = self._ParseChatData(data_dict)

      data[u'entry_type'] = data_dict.get(u'type', u'')
      if data[u'entry_type'] == u'comment':
        description += u'Comment'
      elif data[u'entry_type'] == u'outgoing':
        description += u'Outgoing Message'
      elif data[u'entry_type'] == u'incoming':
        description += u'Incoming Message'
      else:
        # Empty or not known entry type, generic status message.
        description += u'Entry'
        data[u'text'] = u';'.join(self._DictToListOfStrings(data_dict))
        if not data[u'text']:
          data[u'text'] = u'No additional data.'

    event_data = MacKeeperCacheEventData()
    event_data.description = description
    event_data.event_type = data.get(u'event_type', None)
    event_data.offset = row['id']
    event_data.query = query
    event_data.record_id = data.get(u'id', None)
    event_data.room = data.get(u'room', None)
    event_data.text = data.get(u'text', None)
    event_data.url = key_url
    event_data.user_name = data.get(u'user', None)
    event_data.user_sid = data.get(u'sid', None)

    time_value = row['time_string']
    if isinstance(time_value, py2to3.INTEGER_TYPES):
      date_time = dfdatetime_java_time.JavaTime(timestamp=time_value)
      event = time_events.DateTimeValuesEvent(
          date_time, eventdata.EventTimestamp.ADDED_TIME)

    else:
      try:
        timestamp = timelib.Timestamp.FromTimeString(time_value)
      except errors.TimestampError:
        parser_mediator.ProduceExtractionError(
            u'Unable to parse time string: {0:s}'.format(time_value))
        return

      event = time_events.TimestampEvent(
          timestamp, eventdata.EventTimestamp.ADDED_TIME)

    parser_mediator.ProduceEventWithEventData(event, event_data)
Example #27
0
    def ParseFileObject(self, parser_mediator, file_object):
        """Parses a Java WebStart Cache IDX file-like object.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
          and other components, such as storage and dfvfs.
      file_object (dvfvs.FileIO): a file-like object to parse.

    Raises:
      UnableToParseFile: when the file cannot be parsed.
    """
        file_header_map = self._GetDataTypeMap('java_idx_file_header')

        try:
            file_header, file_offset = self._ReadStructureFromFileObject(
                file_object, 0, file_header_map)
        except (ValueError, errors.ParseError) as exception:
            raise errors.UnableToParseFile(
                'Unable to parse file header with error: {0!s}'.format(
                    exception))

        if not file_header.format_version in self._SUPPORTED_FORMAT_VERSIONS:
            raise errors.UnableToParseFile('Unsupported format version.')

        if file_header.format_version == 602:
            section1_map = self._GetDataTypeMap('java_idx_602_section1')
        elif file_header.format_version in (603, 604):
            section1_map = self._GetDataTypeMap('java_idx_603_section1')
        elif file_header.format_version == 605:
            section1_map = self._GetDataTypeMap('java_idx_605_section1')

        try:
            section1, data_size = self._ReadStructureFromFileObject(
                file_object, file_offset, section1_map)
        except (ValueError, errors.ParseError) as exception:
            raise errors.UnableToParseFile((
                'Unable to parse section 1 (format version: {0:d}) with error: '
                '{1!s}').format(file_header.format_version, exception))

        file_offset += data_size

        if file_header.format_version == 602:
            section2_map = self._GetDataTypeMap('java_idx_602_section2')
        elif file_header.format_version in (603, 604, 605):
            file_offset = 128
            section2_map = self._GetDataTypeMap('java_idx_603_section2')

        try:
            section2, data_size = self._ReadStructureFromFileObject(
                file_object, file_offset, section2_map)
        except (ValueError, errors.ParseError) as exception:
            raise errors.UnableToParseFile((
                'Unable to parse section 2 (format version: {0:d}) with error: '
                '{1!s}').format(file_header.format_version, exception))

        file_offset += data_size

        if not section2.url:
            raise errors.UnableToParseFile('URL not found in file.')

        date_http_header = None
        for _ in range(section2.number_of_http_headers):
            http_header_map = self._GetDataTypeMap('java_idx_http_header')
            try:
                http_header, data_size = self._ReadStructureFromFileObject(
                    file_object, file_offset, http_header_map)
            except (ValueError, errors.ParseError) as exception:
                parser_mediator.ProduceExtractionWarning(
                    'Unable to parse HTTP header value at offset: 0x{0:08x}'.
                    format(file_offset))
                break

            file_offset += data_size

            if http_header.name == 'date':
                date_http_header = http_header
                break

        event_data = JavaIDXEventData()
        event_data.idx_version = file_header.format_version
        event_data.ip_address = getattr(section2, 'ip_address', None)
        event_data.url = section2.url

        date_time = dfdatetime_java_time.JavaTime(
            timestamp=section1.modification_time)
        # TODO: Move the timestamp description into definitions.
        event = time_events.DateTimeValuesEvent(date_time, 'File Hosted Date')
        parser_mediator.ProduceEventWithEventData(event, event_data)

        if section1.expiration_time:
            date_time = dfdatetime_java_time.JavaTime(
                timestamp=section1.expiration_time)
            event = time_events.DateTimeValuesEvent(
                date_time, definitions.TIME_DESCRIPTION_EXPIRATION)
            parser_mediator.ProduceEventWithEventData(event, event_data)

        if date_http_header:
            # A HTTP header date and time should be formatted according to RFC 1123.
            # The date "should" be in UTC or have associated time zone information
            # in the string itself. If that is not the case then there is no reliable
            # method for Plaso to determine the proper time zone, so the assumption
            # is that the date and time is in UTC.
            try:
                date_time = dfdatetime_time_elements.TimeElements()
                date_time.CopyFromStringRFC1123(date_http_header.value)
            except ValueError as exception:
                parser_mediator.ProduceExtractionWarning((
                    'Unable to parse date HTTP header string: {0:s} with error: '
                    '{1!s}').format(date_http_header.value, exception))
                date_time = dfdatetime_semantic_time.InvalidTime()

            event = time_events.DateTimeValuesEvent(
                date_time, definitions.TIME_DESCRIPTION_FILE_DOWNLOADED)
            parser_mediator.ProduceEventWithEventData(event, event_data)
Example #28
0
    def ParseFileObject(self, parser_mediator, file_object, **kwargs):
        """Parses a Java WebStart Cache IDX file-like object.

    Args:
      parser_mediator: A parser mediator object (instance of ParserMediator).
      file_object: A file-like object.

    Raises:
      UnableToParseFile: when the file cannot be parsed.
    """
        file_object.seek(0, os.SEEK_SET)
        try:
            magic = self.IDX_SHORT_STRUCT.parse_stream(file_object)
        except (IOError, construct.FieldError) as exception:
            raise errors.UnableToParseFile(
                'Unable to parse Java IDX file with error: {0:s}.'.format(
                    exception))

        # Fields magic.busy and magic.incomplete are normally 0x00. They
        # are set to 0x01 if the file is currently being downloaded. Logic
        # checks for > 1 to avoid a race condition and still reject any
        # file with other data.
        # Field magic.idx_version is the file version, of which only
        # certain versions are supported.
        if magic.busy > 1 or magic.incomplete > 1:
            raise errors.UnableToParseFile('Not a valid Java IDX file')

        if not magic.idx_version in [602, 603, 604, 605]:
            raise errors.UnableToParseFile('Not a valid Java IDX file')

        # Obtain the relevant values from the file. The last modified date
        # denotes when the file was last modified on the HOST. For example,
        # when the file was uploaded to a web server.
        if magic.idx_version == 602:
            section_one = self.IDX_602_STRUCT.parse_stream(file_object)
            last_modified_date = section_one.last_modified_date
            url = section_one.url
            ip_address = 'Unknown'
            http_header_count = section_one.FieldCount
        elif magic.idx_version in [603, 604, 605]:

            # IDX 6.03 and 6.04 have two unused bytes before the structure.
            if magic.idx_version in [603, 604]:
                file_object.read(2)

            # IDX 6.03, 6.04, and 6.05 files use the same structures for the
            # remaining data.
            section_one = self.IDX_605_SECTION_ONE_STRUCT.parse_stream(
                file_object)
            last_modified_date = section_one.last_modified_date
            if file_object.get_size() > 128:
                file_object.seek(128,
                                 os.SEEK_SET)  # Static offset for section 2.
                section_two = self.IDX_605_SECTION_TWO_STRUCT.parse_stream(
                    file_object)
                url = section_two.url
                ip_address = section_two.ip_address
                http_header_count = section_two.FieldCount
            else:
                url = 'Unknown'
                ip_address = 'Unknown'
                http_header_count = 0

        # File offset is now just prior to HTTP headers. Make sure there
        # are headers, and then parse them to retrieve the download date.
        download_date = None
        for field in range(0, http_header_count):
            field = self.JAVA_READUTF_STRING.parse_stream(file_object)
            value = self.JAVA_READUTF_STRING.parse_stream(file_object)
            if field.string == 'date':
                # Time string "should" be in UTC or have an associated time zone
                # information in the string itself. If that is not the case then
                # there is no reliable method for plaso to determine the proper
                # timezone, so the assumption is that it is UTC.
                try:
                    download_date = timelib.Timestamp.FromTimeString(
                        value.string, gmt_as_timezone=False)
                except errors.TimestampError:
                    download_date = None
                    parser_mediator.ProduceExtractionError(
                        'Unable to parse time value: {0:s}'.format(
                            value.string))

        if not url or not ip_address:
            raise errors.UnableToParseFile(
                'Unexpected Error: URL or IP address not found in file.')

        event_data = JavaIDXEventData()
        event_data.idx_version = magic.idx_version
        event_data.ip_address = ip_address
        event_data.url = url

        date_time = dfdatetime_java_time.JavaTime(timestamp=last_modified_date)
        # TODO: Move the timestamp description into eventdata.
        event = time_events.DateTimeValuesEvent(date_time, 'File Hosted Date')
        parser_mediator.ProduceEventWithEventData(event, event_data)

        if section_one:
            expiration_date = section_one.get('expiration_date', None)
            if expiration_date:
                date_time = dfdatetime_java_time.JavaTime(
                    timestamp=expiration_date)
                event = time_events.DateTimeValuesEvent(
                    date_time, definitions.TIME_DESCRIPTION_EXPIRATION)
                parser_mediator.ProduceEventWithEventData(event, event_data)

        if download_date:
            event = time_events.TimestampEvent(
                download_date, definitions.TIME_DESCRIPTION_FILE_DOWNLOADED)
            parser_mediator.ProduceEventWithEventData(event, event_data)
Example #29
0
    def ParseFileObject(self, parser_mediator, file_object, **kwargs):
        """Parses a Java WebStart Cache IDX file-like object.

    Args:
      parser_mediator: A parser mediator object (instance of ParserMediator).
      file_object: A file-like object.

    Raises:
      UnableToParseFile: when the file cannot be parsed.
    """
        file_header_map = self._GetDataTypeMap('java_idx_file_header')

        try:
            file_header, file_offset = self._ReadStructureFromFileObject(
                file_object, 0, file_header_map)
        except (ValueError, errors.ParseError) as exception:
            raise errors.UnableToParseFile(
                'Unable to parse file header with error: {0!s}'.format(
                    exception))

        if not file_header.format_version in self._SUPPORTED_FORMAT_VERSIONS:
            raise errors.UnableToParseFile('Unsupported format version.')

        if file_header.format_version == 602:
            section1_map = self._GetDataTypeMap('java_idx_602_section1')
        elif file_header.format_version in (603, 604):
            section1_map = self._GetDataTypeMap('java_idx_603_section1')
        elif file_header.format_version == 605:
            section1_map = self._GetDataTypeMap('java_idx_605_section1')

        try:
            section1, data_size = self._ReadStructureFromFileObject(
                file_object, file_offset, section1_map)
        except (ValueError, errors.ParseError) as exception:
            raise errors.UnableToParseFile((
                'Unable to parse section 1 (format version: {0:d}) with error: '
                '{1!s}').format(file_header.format_version, exception))

        file_offset += data_size

        if file_header.format_version == 602:
            section2_map = self._GetDataTypeMap('java_idx_602_section2')
        elif file_header.format_version in (603, 604, 605):
            file_offset = 128
            section2_map = self._GetDataTypeMap('java_idx_603_section2')

        try:
            section2, data_size = self._ReadStructureFromFileObject(
                file_object, file_offset, section2_map)
        except (ValueError, errors.ParseError) as exception:
            raise errors.UnableToParseFile((
                'Unable to parse section 2 (format version: {0:d}) with error: '
                '{1!s}').format(file_header.format_version, exception))

        file_offset += data_size

        if not section2.url:
            raise errors.UnableToParseFile('URL not found in file.')

        date_http_header = None
        for _ in range(section2.number_of_http_headers):
            http_header_map = self._GetDataTypeMap('java_idx_http_header')
            try:
                http_header, data_size = self._ReadStructureFromFileObject(
                    file_object, file_offset, http_header_map)
            except (ValueError, errors.ParseError) as exception:
                parser_mediator.ProduceExtractionError(
                    'Unable to parse HTTP header value at offset: 0x{0:08x}'.
                    format(file_offset))
                break

            file_offset += data_size

            if http_header.name == 'date':
                date_http_header = http_header
                break

        event_data = JavaIDXEventData()
        event_data.idx_version = file_header.format_version
        event_data.ip_address = getattr(section2, 'ip_address', None)
        event_data.url = section2.url

        date_time = dfdatetime_java_time.JavaTime(
            timestamp=section1.modification_time)
        # TODO: Move the timestamp description into definitions.
        event = time_events.DateTimeValuesEvent(date_time, 'File Hosted Date')
        parser_mediator.ProduceEventWithEventData(event, event_data)

        if section1.expiration_time:
            date_time = dfdatetime_java_time.JavaTime(
                timestamp=section1.expiration_time)
            event = time_events.DateTimeValuesEvent(
                date_time, definitions.TIME_DESCRIPTION_EXPIRATION)
            parser_mediator.ProduceEventWithEventData(event, event_data)

        if date_http_header:
            # A HTTP header date and string "should" be in UTC or have an associated
            # time zone information in the string itself. If that is not the case
            # then there is no reliable method for plaso to determine the proper
            # time zone, so the assumption is that it is UTC.
            try:
                download_date = timelib.Timestamp.FromTimeString(
                    date_http_header.value, gmt_as_timezone=False)
            except errors.TimestampError:
                parser_mediator.ProduceExtractionError(
                    'Unable to parse date HTTP header value: {0:s}'.format(
                        date_http_header.value))

            if download_date:
                event = time_events.TimestampEvent(
                    download_date,
                    definitions.TIME_DESCRIPTION_FILE_DOWNLOADED)
                parser_mediator.ProduceEventWithEventData(event, event_data)
Example #30
0
  def ParseReceiverData(
      self, parser_mediator, query, row, **unused_kwargs):
    """Parses a single row from the receiver and cache response table.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
          and other components, such as storage and dfvfs.
      query (str): query that created the row.
      row (sqlite3.Row): row.
    """
    query_hash = hash(query)

    data = {}
    key_url = self._GetRowValue(query_hash, row, 'request_key')

    data_dict = {}
    description = 'MacKeeper Entry'
    # Check the URL, since that contains vital information about the type of
    # event we are dealing with.
    if key_url.endswith('plist'):
      description = 'Configuration Definition'
      data['text'] = 'Plist content added to cache.'

    elif key_url.startswith('http://event.zeobit.com'):
      description = 'MacKeeper Event'
      try:
        _, _, part = key_url.partition('?')
        data['text'] = part.replace('&', ' ')
      except UnicodeDecodeError:
        data['text'] = 'N/A'

    elif key_url.startswith('http://account.zeobit.com'):
      description = 'Account Activity'
      _, _, activity = key_url.partition('#')
      if activity:
        data['text'] = 'Action started: {0:s}'.format(activity)
      else:
        data['text'] = 'Unknown activity.'

    elif key_url.startswith('http://support.') and 'chat' in key_url:
      description = 'Chat '
      try:
        jquery = self._GetRowValue(query_hash, row, 'data')
        jquery = codecs.decode(jquery, 'utf-8')
      except UnicodeDecodeError:
        jquery = ''

      data_dict = self._ExtractJQuery(jquery)
      data = self._ParseChatData(data_dict)

      data['entry_type'] = data_dict.get('type', '')
      if data['entry_type'] == 'comment':
        description += 'Comment'
      elif data['entry_type'] == 'outgoing':
        description += 'Outgoing Message'
      elif data['entry_type'] == 'incoming':
        description += 'Incoming Message'
      else:
        # Empty or not known entry type, generic status message.
        description += 'Entry'
        data['text'] = ';'.join(self._DictToListOfStrings(data_dict))
        if not data['text']:
          data['text'] = 'No additional data.'

    event_data = MacKeeperCacheEventData()
    event_data.description = description
    event_data.event_type = data.get('event_type', None)
    event_data.offset = self._GetRowValue(query_hash, row, 'id')
    event_data.query = query
    event_data.record_id = data.get('id', None)
    event_data.room = data.get('room', None)
    event_data.text = data.get('text', None)
    event_data.url = key_url
    event_data.user_name = data.get('user', None)
    event_data.user_sid = data.get('sid', None)

    time_value = self._GetRowValue(query_hash, row, 'time_string')
    if isinstance(time_value, py2to3.INTEGER_TYPES):
      date_time = dfdatetime_java_time.JavaTime(timestamp=time_value)
      event = time_events.DateTimeValuesEvent(
          date_time, definitions.TIME_DESCRIPTION_ADDED)

    else:
      try:
        timestamp = timelib.Timestamp.FromTimeString(time_value)
      except errors.TimestampError:
        parser_mediator.ProduceExtractionWarning(
            'Unable to parse time string: {0:s}'.format(time_value))
        return

      event = time_events.TimestampEvent(
          timestamp, definitions.TIME_DESCRIPTION_ADDED)

    parser_mediator.ProduceEventWithEventData(event, event_data)