<commit_before>"""
The default styling.
"""
from __future__ import unicode_literals, absolute_import
from .style import Style, merge_styles
from .base import ANSI_COLOR_NAMES
from .named_colors import NAMED_COLORS
from prompt_toolkit.cache import memoized

__all__ = [
    'default_ui_style',
    'default_pygments_style',
]

#: Default styling. Mapping from classnames to their style definition.
PROMPT_TOOLKIT_STYLE = [
    # Highlighting of search matches in document.
    ('search',                             'bg:ansibrightyellow'),
    ('search.current',                     ''),

    # Incremental search.
    ('incsearch',                          ''),
    ('incsearch.current',                  'reverse'),

    # Highlighting of select text in document.
    ('selected',                                'reverse'),

    ('cursor-column',                           'bg:#dddddd'),
    ('cursor-line',                             'underline'),
    ('color-column',                            'bg:#ccaacc'),

    # Highlighting of matching brackets.
    ('matching-bracket',                        ''),
    ('matching-bracket.other',                  '#000000 bg:#aacccc'),
    ('matching-bracket.cursor',                 '#ff8888 bg:#880000'),

    # Styling of other cursors, in case of block editing.
    ('multiple-cursors',                        '#000000 bg:#ccccaa'),

    # Line numbers.
    ('line-number',                             '#888888'),
    ('line-number.current',                     'bold'),
    ('tilde',                                   '#8888ff'),

    # Default prompt.
    ('prompt',                                  ''),
    ('prompt.arg',                              'noinherit'),
    ('prompt.arg.text',                         ''),
    ('prompt.search',                           'noinherit'),
    ('prompt.search.text',                      ''),

    # Search toolbar.
    ('search-toolbar',                          'bold'),
    ('search-toolbar.text',                     'nobold'),

    # System toolbar
    ('system-toolbar',                          'bold'),
    ('system-toolbar.text',                     'nobold'),

    # "arg" toolbar.
    ('arg-toolbar',                             'bold'),
    ('arg-toolbar.text',                        'nobold'),

    # Validation toolbar.
    ('validation-toolbar',                      'bg:#550000 #ffffff'),
    ('window-too-small',                        'bg:#550000 #ffffff'),

    # Completions toolbar.
    ('completion-toolbar',                     'bg:#bbbbbb #000000'),
    ('completion-toolbar.arrow',               'bg:#bbbbbb #000000 bold'),
    ('completion-toolbar.completion',          'bg:#bbbbbb #000000'),
    ('completion-toolbar.completion.current',  'bg:#444444 #ffffff'),

    # Completions menu.
    ('completion-menu',                         'bg:#bbbbbb #000000'),
    ('completion-menu.completion',              ''),
    ('completion-menu.completion.current',      'bg:#888888 #ffffff'),
    ('completion-menu.meta.completion',         'bg:#999999 #000000'),
    ('completion-menu.meta.completion.current', 'bg:#aaaaaa #000000'),
    ('completion-menu.multi-column-meta',       'bg:#aaaaaa #000000'),

    # Scrollbars.
    ('scrollbar.background',                     ''),
    ('scrollbar.button',                         'bg:#888888'),
    ('scrollbar.arrow',                          'noinherit bold'),

    # Start/end of scrollbars. Adding 'underline' here provides a nice little
    # detail to the progress bar, but it doesn't look good on all terminals.
    # ('scrollbar.start',                          'underline #ffffff'),
    # ('scrollbar.end',                            'underline #000000'),

    # Auto suggestion text.
    ('auto-suggestion',                         '#666666'),

    # Trailing whitespace and tabs.
    ('trailing-whitespace',                     '#999999'),
    ('tab',                                     '#999999'),

    # When Control-C/D has been pressed. Grayed.
    ('aborting',  '#888888 bg:default noreverse noitalic nounderline noblink'),
    ('exiting',   '#888888 bg:default noreverse noitalic nounderline noblink'),

    # Entering a Vi digraph.
    ('digraph',                                 '#4444ff'),

    # Control characters, like ^C, ^X.
    ('control-character',                       'ansiblue'),

    # Default styling of HTML elements.
    ('i',                                       'italic'),
    ('u',                                       'underline'),
    ('b',                                       'bold'),
    ('em',                                      'italic'),
    ('strong',                                  'bold'),
    ('hidden',                                  'hidden'),

    # It should be possible to use the style names in HTML.
    # <reverse>...</reverse>  or <noreverse>...</noreverse>.
    ('italic',                                  'italic'),
    ('underline',                               'underline'),
    ('bold',                                    'bold'),
    ('reverse',                                 'reverse'),
    ('noitalic',                                'noitalic'),
    ('nounderline',                             'nounderline'),
    ('nobold',                                  'nobold'),
    ('noreverse',                               'noreverse'),

    # Prompt bottom toolbar
    ('bottom-toolbar',                          'reverse'),
]

# Style that will turn for instance the class 'red' into 'red'.
COLORS_STYLE = [
    (name, 'fg:' + name) for name in ANSI_COLOR_NAMES
] + [
    (name.lower(), 'fg:' + name) for name in NAMED_COLORS
]

WIDGETS_STYLE = [
    # Dialog windows.
    ('dialog',                                  'bg:#4444ff'),
    ('dialog.body',                             'bg:#ffffff #000000'),
    ('dialog.body text-area',                    'bg:#cccccc'),
    ('dialog.body text-area last-line',          'underline'),

    ('dialog frame.label',                      '#ff0000 bold'),

    # Scrollbars in dialogs.
    ('dialog.body scrollbar.background',        ''),
    ('dialog.body scrollbar.button',            'bg:#000000'),
    ('dialog.body scrollbar.arrow',             ''),
    ('dialog.body scrollbar.start',             'nounderline'),
    ('dialog.body scrollbar.end',               'nounderline'),

    # Buttons.
    ('button',                                  ''),
    ('button.arrow',                            'bold'),
    ('button.focused',                          'bg:#aa0000 #ffffff'),

    # Menu bars.
    ('menu-bar',                                'bg:#aaaaaa #000000'),
    ('menu-bar.selected-item',                  'bg:#ffffff #000000'),
    ('menu',                                    'bg:#888888 #ffffff'),
    ('menu.border',                             '#aaaaaa'),
    ('menu.border shadow',                      '#444444'),

    # Shadows.
    ('dialog shadow',                           'bg:#000088'),
    ('dialog.body shadow',                      'bg:#aaaaaa'),

    ('progress-bar',                             'bg:#000088'),
    ('progress-bar.used',                        'bg:#ff0000'),
]

# The default Pygments style, include this by default in case a Pygments lexer
# is used.
PYGMENTS_DEFAULT_STYLE = {
    'pygments.whitespace':                "#bbbbbb",
    'pygments.comment':                   "italic #408080",
    'pygments.comment.preproc':           "noitalic #bc7a00",

    'pygments.keyword':                   "bold #008000",
    'pygments.keyword.pseudo':            "nobold",
    'pygments.keyword.type':              "nobold #b00040",

    'pygments.operator':                  "#666666",
    'pygments.operator.word':             "bold #aa22ff",

    'pygments.name.builtin':              "#008000",
    'pygments.name.function':             "#0000ff",
    'pygments.name.class':                "bold #0000ff",
    'pygments.name.namespace':            "bold #0000ff",
    'pygments.name.exception':            "bold #d2413a",
    'pygments.name.variable':             "#19177c",
    'pygments.name.constant':             "#880000",
    'pygments.name.label':                "#a0a000",
    'pygments.name.entity':               "bold #999999",
    'pygments.name.attribute':            "#7d9029",
    'pygments.name.tag':                  "bold #008000",
    'pygments.name.decorator':            "#aa22ff",

    # Note: In Pygments, Token.String is an alias for Token.Literal.String,
    #       and Token.Number as an alias for Token.Literal.Number.
    'pygments.literal.string':            "#ba2121",
    'pygments.literal.string.doc':        "italic",
    'pygments.literal.string.interpol':   "bold #bb6688",
    'pygments.literal.string.escape':     "bold #bb6622",
    'pygments.literal.string.regex':      "#bb6688",
    'pygments.literal.string.symbol':     "#19177c",
    'pygments.literal.string.other':      "#008000",
    'pygments.literal.number':            "#666666",

    'pygments.generic.heading':           "bold #000080",
    'pygments.generic.subheading':        "bold #800080",
    'pygments.generic.deleted':           "#a00000",
    'pygments.generic.inserted':          "#00a000",
    'pygments.generic.error':             "#ff0000",
    'pygments.generic.emph':              "italic",
    'pygments.generic.strong':            "bold",
    'pygments.generic.prompt':            "bold #000080",
    'pygments.generic.output':            "#888",
    'pygments.generic.traceback':         "#04d",

    'pygments.error':                     "border:#ff0000",
}

@memoized()
def default_ui_style():
    """
    Create a default `Style` object.
    """
    return merge_styles([
        Style(PROMPT_TOOLKIT_STYLE),
        Style(COLORS_STYLE),
        Style(WIDGETS_STYLE),
    ])

@memoized()
def default_pygments_style():
    """
    Create a `Style` object that contains the default Pygments style.
    """
    return Style.from_dict(PYGMENTS_DEFAULT_STYLE)
<commit_msg>Better styling for scrollbar button (don't use the same color as the selected item).<commit_after>"""
The default styling.
"""
from __future__ import unicode_literals, absolute_import
from .style import Style, merge_styles
from .base import ANSI_COLOR_NAMES
from .named_colors import NAMED_COLORS
from prompt_toolkit.cache import memoized

__all__ = [
    'default_ui_style',
    'default_pygments_style',
]

#: Default styling. Mapping from classnames to their style definition.
PROMPT_TOOLKIT_STYLE = [
    # Highlighting of search matches in document.
    ('search',                             'bg:ansibrightyellow'),
    ('search.current',                     ''),

    # Incremental search.
    ('incsearch',                          ''),
    ('incsearch.current',                  'reverse'),

    # Highlighting of select text in document.
    ('selected',                                'reverse'),

    ('cursor-column',                           'bg:#dddddd'),
    ('cursor-line',                             'underline'),
    ('color-column',                            'bg:#ccaacc'),

    # Highlighting of matching brackets.
    ('matching-bracket',                        ''),
    ('matching-bracket.other',                  '#000000 bg:#aacccc'),
    ('matching-bracket.cursor',                 '#ff8888 bg:#880000'),

    # Styling of other cursors, in case of block editing.
    ('multiple-cursors',                        '#000000 bg:#ccccaa'),

    # Line numbers.
    ('line-number',                             '#888888'),
    ('line-number.current',                     'bold'),
    ('tilde',                                   '#8888ff'),

    # Default prompt.
    ('prompt',                                  ''),
    ('prompt.arg',                              'noinherit'),
    ('prompt.arg.text',                         ''),
    ('prompt.search',                           'noinherit'),
    ('prompt.search.text',                      ''),

    # Search toolbar.
    ('search-toolbar',                          'bold'),
    ('search-toolbar.text',                     'nobold'),

    # System toolbar
    ('system-toolbar',                          'bold'),
    ('system-toolbar.text',                     'nobold'),

    # "arg" toolbar.
    ('arg-toolbar',                             'bold'),
    ('arg-toolbar.text',                        'nobold'),

    # Validation toolbar.
    ('validation-toolbar',                      'bg:#550000 #ffffff'),
    ('window-too-small',                        'bg:#550000 #ffffff'),

    # Completions toolbar.
    ('completion-toolbar',                     'bg:#bbbbbb #000000'),
    ('completion-toolbar.arrow',               'bg:#bbbbbb #000000 bold'),
    ('completion-toolbar.completion',          'bg:#bbbbbb #000000'),
    ('completion-toolbar.completion.current',  'bg:#444444 #ffffff'),

    # Completions menu.
    ('completion-menu',                         'bg:#bbbbbb #000000'),
    ('completion-menu.completion',              ''),
    ('completion-menu.completion.current',      'bg:#888888 #ffffff'),
    ('completion-menu.meta.completion',         'bg:#999999 #000000'),
    ('completion-menu.meta.completion.current', 'bg:#aaaaaa #000000'),
    ('completion-menu.multi-column-meta',       'bg:#aaaaaa #000000'),

    # Scrollbars.
    ('scrollbar.background',                     ''),
    ('scrollbar.button',                         'bg:#444444'),
    ('scrollbar.arrow',                          'noinherit bold'),

    # Start/end of scrollbars. Adding 'underline' here provides a nice little
    # detail to the progress bar, but it doesn't look good on all terminals.
    # ('scrollbar.start',                          'underline #ffffff'),
    # ('scrollbar.end',                            'underline #000000'),

    # Auto suggestion text.
    ('auto-suggestion',                         '#666666'),

    # Trailing whitespace and tabs.
    ('trailing-whitespace',                     '#999999'),
    ('tab',                                     '#999999'),

    # When Control-C/D has been pressed. Grayed.
    ('aborting',  '#888888 bg:default noreverse noitalic nounderline noblink'),
    ('exiting',   '#888888 bg:default noreverse noitalic nounderline noblink'),

    # Entering a Vi digraph.
    ('digraph',                                 '#4444ff'),

    # Control characters, like ^C, ^X.
    ('control-character',                       'ansiblue'),

    # Default styling of HTML elements.
    ('i',                                       'italic'),
    ('u',                                       'underline'),
    ('b',                                       'bold'),
    ('em',                                      'italic'),
    ('strong',                                  'bold'),
    ('hidden',                                  'hidden'),

    # It should be possible to use the style names in HTML.
    # <reverse>...</reverse>  or <noreverse>...</noreverse>.
    ('italic',                                  'italic'),
    ('underline',                               'underline'),
    ('bold',                                    'bold'),
    ('reverse',                                 'reverse'),
    ('noitalic',                                'noitalic'),
    ('nounderline',                             'nounderline'),
    ('nobold',                                  'nobold'),
    ('noreverse',                               'noreverse'),

    # Prompt bottom toolbar
    ('bottom-toolbar',                          'reverse'),
]

# Style that will turn for instance the class 'red' into 'red'.
COLORS_STYLE = [
    (name, 'fg:' + name) for name in ANSI_COLOR_NAMES
] + [
    (name.lower(), 'fg:' + name) for name in NAMED_COLORS
]

WIDGETS_STYLE = [
    # Dialog windows.
    ('dialog',                                  'bg:#4444ff'),
    ('dialog.body',                             'bg:#ffffff #000000'),
    ('dialog.body text-area',                    'bg:#cccccc'),
    ('dialog.body text-area last-line',          'underline'),

    ('dialog frame.label',                      '#ff0000 bold'),

    # Scrollbars in dialogs.
    ('dialog.body scrollbar.background',        ''),
    ('dialog.body scrollbar.button',            'bg:#000000'),
    ('dialog.body scrollbar.arrow',             ''),
    ('dialog.body scrollbar.start',             'nounderline'),
    ('dialog.body scrollbar.end',               'nounderline'),

    # Buttons.
    ('button',                                  ''),
    ('button.arrow',                            'bold'),
    ('button.focused',                          'bg:#aa0000 #ffffff'),

    # Menu bars.
    ('menu-bar',                                'bg:#aaaaaa #000000'),
    ('menu-bar.selected-item',                  'bg:#ffffff #000000'),
    ('menu',                                    'bg:#888888 #ffffff'),
    ('menu.border',                             '#aaaaaa'),
    ('menu.border shadow',                      '#444444'),

    # Shadows.
    ('dialog shadow',                           'bg:#000088'),
    ('dialog.body shadow',                      'bg:#aaaaaa'),

    ('progress-bar',                             'bg:#000088'),
    ('progress-bar.used',                        'bg:#ff0000'),
]

# The default Pygments style, include this by default in case a Pygments lexer
# is used.
PYGMENTS_DEFAULT_STYLE = {
    'pygments.whitespace':                "#bbbbbb",
    'pygments.comment':                   "italic #408080",
    'pygments.comment.preproc':           "noitalic #bc7a00",

    'pygments.keyword':                   "bold #008000",
    'pygments.keyword.pseudo':            "nobold",
    'pygments.keyword.type':              "nobold #b00040",

    'pygments.operator':                  "#666666",
    'pygments.operator.word':             "bold #aa22ff",

    'pygments.name.builtin':              "#008000",
    'pygments.name.function':             "#0000ff",
    'pygments.name.class':                "bold #0000ff",
    'pygments.name.namespace':            "bold #0000ff",
    'pygments.name.exception':            "bold #d2413a",
    'pygments.name.variable':             "#19177c",
    'pygments.name.constant':             "#880000",
    'pygments.name.label':                "#a0a000",
    'pygments.name.entity':               "bold #999999",
    'pygments.name.attribute':            "#7d9029",
    'pygments.name.tag':                  "bold #008000",
    'pygments.name.decorator':            "#aa22ff",

    # Note: In Pygments, Token.String is an alias for Token.Literal.String,
    #       and Token.Number as an alias for Token.Literal.Number.
    'pygments.literal.string':            "#ba2121",
    'pygments.literal.string.doc':        "italic",
    'pygments.literal.string.interpol':   "bold #bb6688",
    'pygments.literal.string.escape':     "bold #bb6622",
    'pygments.literal.string.regex':      "#bb6688",
    'pygments.literal.string.symbol':     "#19177c",
    'pygments.literal.string.other':      "#008000",
    'pygments.literal.number':            "#666666",

    'pygments.generic.heading':           "bold #000080",
    'pygments.generic.subheading':        "bold #800080",
    'pygments.generic.deleted':           "#a00000",
    'pygments.generic.inserted':          "#00a000",
    'pygments.generic.error':             "#ff0000",
    'pygments.generic.emph':              "italic",
    'pygments.generic.strong':            "bold",
    'pygments.generic.prompt':            "bold #000080",
    'pygments.generic.output':            "#888",
    'pygments.generic.traceback':         "#04d",

    'pygments.error':                     "border:#ff0000",
}

@memoized()
def default_ui_style():
    """
    Create a default `Style` object.
    """
    return merge_styles([
        Style(PROMPT_TOOLKIT_STYLE),
        Style(COLORS_STYLE),
        Style(WIDGETS_STYLE),
    ])

@memoized()
def default_pygments_style():
    """
    Create a `Style` object that contains the default Pygments style.
    """
    return Style.from_dict(PYGMENTS_DEFAULT_STYLE)
<|endoftext|>


<commit_before>"""
Created on 11 févr. 2014

@author: inso
"""

import logging
import time
import asyncio
from enum import Enum

from ucoinpy.documents.certification import SelfCertification
from ucoinpy.api import bma as bma
from ucoinpy.api.bma import PROTOCOL_VERSION

from ...tools.exceptions import Error, NoPeerAvailable,\
                                        MembershipNotFoundError
from PyQt5.QtCore import QObject, pyqtSignal

class LocalState(Enum):
    """
    The local state describes how the identity exists locally :
    COMPLETED means all its related datas (certifiers, certified...)
    were succefully downloaded
    PARTIAL means not all data are present locally
    NOT_FOUND means it could not be found anywhere
    """
    NOT_FOUND = 0
    PARTIAL = 1
    COMPLETED = 2

class BlockchainState(Enum):
    """
    The blockchain state describes how the identity
    was found :
    VALIDATED means it was found in the blockchain
    BUFFERED means it was found via a lookup but not in the
    blockchain
    NOT_FOUND means it could not be found anywhere
    """
    NOT_FOUND = 0
    BUFFERED = 1
    VALIDATED = 2

class Identity(QObject):
    """
    A person with a uid and a pubkey
    """
    def __init__(self, uid, pubkey, local_state, blockchain_state):
        """
        Initializing a person object.

        :param str uid: The person uid, also known as its uid on the network
        :param str pubkey: The person pubkey
        :param LocalState local_state: The local status of the identity
        :param BlockchainState blockchain_state: The blockchain status of the identity
        """
        super().__init__()
        self.uid = uid
        self.pubkey = pubkey
        self.local_state = local_state
        self.blockchain_state = blockchain_state

    @classmethod
    def empty(cls, pubkey):
        return cls("", pubkey, LocalState.NOT_FOUND, BlockchainState.NOT_FOUND)

    @classmethod
    def from_handled_data(cls, uid, pubkey, blockchain_state):
        return cls(uid, pubkey, LocalState.COMPLETED, blockchain_state)

    @classmethod
    def from_json(cls, json_data):
        """
        Create a person from json data

        :param dict json_data: The person as a dict in json format
        :return: A new person if pubkey wasn't known, else a new person instance.
        """
        pubkey = json_data['pubkey']
        uid = json_data['uid']
        local_state = LocalState[json_data['local_state']]
        blockchain_state = BlockchainState[json_data['blockchain_state']]

        return cls(uid, pubkey, local_state, blockchain_state)

    @asyncio.coroutine
    def selfcert(self, community):
        """
        Get the identity self certification.
        This request is not cached in the person object.

        :param cutecoin.core.community.Community community: The community target to request the self certification
        :return: A SelfCertification ucoinpy object
        :rtype: ucoinpy.documents.certification.SelfCertification
        """
        timestamp = 0
        lookup_data = yield from community.bma_access.future_request(bma.wot.Lookup, req_args={'search': self.pubkey})
        for result in lookup_data['results']:
            if result["pubkey"] == self.pubkey:
                uids = result['uids']
                for uid_data in uids:
                    if uid_data["meta"]["timestamp"] > timestamp:
                        timestamp = uid_data["meta"]["timestamp"]
                        uid = uid_data["uid"]
                        signature = uid_data["self"]

                return SelfCertification(PROTOCOL_VERSION,
                                         community.currency,
                                         self.pubkey,
                                         timestamp,
                                         uid,
                                         signature)
        return None

    @asyncio.coroutine
    def get_join_date(self, community):
        """
        Get the person join date.
        This request is not cached in the person object.

        :param cutecoin.core.community.Community community: The community target to request the join date
        :return: A datetime object
        """
        try:
            search = yield from community.bma_access.future_request(bma.blockchain.Membership,
                                                                    {'search': self.pubkey})
            if len(search['memberships']) > 0:
                membership_data = search['memberships'][0]
                block = yield from community.bma_access.future_request(bma.blockchain.Block,
                                req_args={'number': membership_data['blockNumber']})
                return block['medianTime']
        except ValueError as e:
            if '404' in str(e) or '400' in str(e):
                raise MembershipNotFoundError(self.pubkey, community.name)
        except NoPeerAvailable as e:
            logging.debug(str(e))
            raise MembershipNotFoundError(self.pubkey, community.name)

    @asyncio.coroutine
    def get_expiration_date(self, community):
        try:
            membership = yield from self.membership(community)
            join_block_number = membership['blockNumber']
            try:
                join_block = yield from community.bma_access.future_request(bma.blockchain.Block,
                                req_args={'number': join_block_number})

                parameters = yield from community.bma_access.future_request(bma.blockchain.Parameters)
                join_date = join_block['medianTime']
                expiration_date = join_date + parameters['sigValidity']
            except NoPeerAvailable:
                expiration_date = None
            except ValueError as e:
                logging.debug("Expiration date not found")
                expiration_date = None
        except MembershipNotFoundError:
            expiration_date = None
        return expiration_date

#TODO: Manage 'OUT' memberships ? Maybe ?
    @asyncio.coroutine
    def membership(self, community):
        """
        Get the person last membership document.

        :param cutecoin.core.community.Community community: The community target to request the join date
        :return: The membership data in BMA json format
        :rtype: dict
        """
        try:
            search = yield from community.bma_access.future_request(bma.blockchain.Membership,
                                           {'search': self.pubkey})
            block_number = -1
            membership_data = None
            for ms in search['memberships']:
                if ms['blockNumber'] > block_number:
                    block_number = ms['blockNumber']
                    if 'type' in ms:
                        if ms['type'] is 'IN':
                            membership_data = ms
                    else:
                        membership_data = ms
            if membership_data:
                return membership_data
            else:
                raise MembershipNotFoundError(self.pubkey, community.name)

        except ValueError as e:
            if '404' in str(e) or '400' in str(e):
                raise MembershipNotFoundError(self.pubkey, community.name)
        except NoPeerAvailable as e:
            logging.debug(str(e))
            raise MembershipNotFoundError(self.pubkey, community.name)
        except UnboundLocalError:
            raise

    @asyncio.coroutine
    def published_uid(self, community):
        try:
            data = yield from community.bma_access.future_request(bma.wot.Lookup,
                                 req_args={'search': self.pubkey})
        except ValueError as e:
            if '404' in str(e):
                timestamp = 0

                for result in data['results']:
                    if result["pubkey"] == self.pubkey:
                        uids = result['uids']
                        person_uid = ""
                        for uid_data in uids:
                            if uid_data["meta"]["timestamp"] > timestamp:
                                timestamp = uid_data["meta"]["timestamp"]
                                person_uid = uid_data["uid"]
                            if person_uid == self.uid:
                                return True
        except NoPeerAvailable as e:
            logging.debug(str(e))
        return False

    @asyncio.coroutine
    def is_member(self, community):
        """
        Check if the person is a member of a community

        :param cutecoin.core.community.Community community: The community target to request the join date
        :return: True if the person is a member of a community
        """
        try:
            certifiers = yield from community.bma_access.future_request(bma.wot.CertifiersOf,
                                                                        {'search': self.pubkey})
            return certifiers['isMember']
        except ValueError as e:
            if '404' in str(e) or '400' in str(e):
                pass
            else:
                raise
        except NoPeerAvailable as e:
            logging.debug(str(e))
        return False

    @asyncio.coroutine
    def certifiers_of(self, identities_registry, community):
        """
        Get the list of this person certifiers

        :param cutecoin.core.registry.identities.IdentitiesRegistry identities_registry: The identities registry
        :param cutecoin.core.community.Community community: The community target to request the join date
        :return: The list of the certifiers of this community
        :rtype: list
        """
        certifiers = list()
        try:
            data = yield from community.bma_access.future_request(bma.wot.CertifiersOf,
                                                                  {'search': self.pubkey})

            for certifier_data in data['certifications']:
                certifier = {}
                certifier['identity'] = identities_registry.from_handled_data(certifier_data['uid'],
                                                                              certifier_data['pubkey'],
                                                                              BlockchainState.VALIDATED,
                                                                              community)
                certifier['cert_time'] = certifier_data['cert_time']['medianTime']
                if 'written' in certifier_data and certifier_data['written'] and 'number' in certifier_data['written']:
                    certifier['block_number'] = certifier_data['written']['number']
                else:
                    certifier['block_number'] = certifier_data['cert_time']['block']

                certifiers.append(certifier)
        except ValueError as e:
            if '404' in str(e):
                logging.debug('bma.wot.CertifiersOf request error: {0}'.format(str(e)))
            else:
                logging.debug(str(e))
        except NoPeerAvailable as e:
            logging.debug(str(e))

        try:
            data = yield from community.bma_access.future_request(bma.wot.Lookup, {'search': self.pubkey})
            for result in data['results']:
                if result["pubkey"] == self.pubkey:
                    self._refresh_uid(result['uids'])
                    for uid_data in result['uids']:
                        for certifier_data in uid_data['others']:
                            for uid in certifier_data['uids']:
                                # add a certifier
                                certifier = {}
                                certifier['identity'] = identities_registry.\
                                    from_handled_data(uid,
                                                      certifier_data['pubkey'],
                                                      BlockchainState.BUFFERED,
                                                      community)
                                if certifier['identity'] not in certifiers:
                                    block = yield from community.bma_access.future_request(bma.blockchain.Block,
                                                                         {'number': certifier_data['meta']['block_number']})
                                    certifier['cert_time'] = block['medianTime']
                                    certifier['block_number'] = None

                                    certifiers.append(certifier)
        except ValueError as e:
            logging.debug("Lookup error : {0}".format(str(e)))
        except NoPeerAvailable as e:
            logging.debug(str(e))
        return certifiers

    @asyncio.coroutine
    def unique_valid_certifiers_of(self, identities_registry, community):
        certifier_list = yield from self.certifiers_of(identities_registry, community)
        unique_valid = []
        #  add certifiers of uid
        for certifier in tuple(certifier_list):
            # add only valid certification...
            try:
                cert_expired = yield from community.certification_expired(certifier['cert_time'])
            except NoPeerAvailable:
                logging.debug("No peer available")
                cert_expired = True

            if not cert_expired:
                # keep only the latest certification
                already_found = [c['identity'].pubkey for c in unique_valid]
                if certifier['identity'].pubkey in already_found:
                    index = already_found.index(certifier['identity'].pubkey)
                    if certifier['cert_time'] > unique_valid[index]['cert_time']:
                        unique_valid[index] = certifier
                else:
                    unique_valid.append(certifier)
        return unique_valid

    @asyncio.coroutine
    def certified_by(self, identities_registry, community):
        """
        Get the list of persons certified by this person
        :param cutecoin.core.registry.IdentitiesRegistry identities_registry: The registry
        :param cutecoin.core.Community community: The community

        :param cutecoin.core.community.Community community: The community target to request the join date
        :return: The list of the certified persons of this community in BMA json format
        :rtype: list
        """
        certified_list = list()
        try:
            data = yield from community.bma_access.future_request(bma.wot.CertifiedBy, {'search': self.pubkey})
            for certified_data in data['certifications']:
                certified = {}
                certified['identity'] = identities_registry.from_handled_data(certified_data['uid'],
                                                                              certified_data['pubkey'],
                                                                              BlockchainState.VALIDATED,
                                                                              community)
                certified['cert_time'] = certified_data['cert_time']['medianTime']
                if 'written' in certified_data and certified_data['written'] and 'number' in certified_data['written']:
                    certified['block_number'] = certified_data['written']['number']
                else:
                    certified['block_number'] = certified_data['cert_time']['block']
                certified_list.append(certified)
        except ValueError as e:
            if '404' in str(e):
                logging.debug('bma.wot.CertifiersOf request error')
        except NoPeerAvailable as e:
            logging.debug(str(e))

        try:
            data = yield from community.bma_access.future_request(bma.wot.Lookup, {'search': self.pubkey})
            for result in data['results']:
                if result["pubkey"] == self.pubkey:
                    self._refresh_uid(result['uids'])
                    for certified_data in result['signed']:
                        certified = {}
                        certified['identity'] = identities_registry.from_handled_data(certified_data['uid'],
                                                                          certified_data['pubkey'],
                                                                          BlockchainState.BUFFERED,
                                                                          community)
                        if certified['identity'] not in certified_list:
                            certified['cert_time'] = certified_data['meta']['timestamp']
                            certified['block_number'] = None
                            certified_list.append(certified)
        except ValueError as e:
            if '404' in str(e):
                logging.debug('bma.wot.Lookup request error')
        except NoPeerAvailable as e:
            logging.debug(str(e))
        return certified_list

    @asyncio.coroutine
    def unique_valid_certified_by(self, identities_registry, community):
        certified_list = yield from self.certified_by(identities_registry, community)
        unique_valid = []
        #  add certifiers of uid
        for certified in tuple(certified_list):
            # add only valid certification...
            try:
                cert_expired = yield from community.certification_expired(certified['cert_time'])
            except NoPeerAvailable:
                logging.debug("No peer available")
                cert_expired = True

            if not cert_expired:
                # keep only the latest certification
                already_found = [c['identity'].pubkey for c in unique_valid]
                if certified['identity'].pubkey in already_found:
                    index = already_found.index(certified['identity'].pubkey)
                    if certified['cert_time'] > unique_valid[index]['cert_time']:
                        unique_valid[index] = certified
                else:
                    unique_valid.append(certified)
        return unique_valid

    @asyncio.coroutine
    def membership_expiration_time(self, community):
        membership = yield from self.membership(community)
        join_block = membership['blockNumber']
        block = yield from community.get_block(join_block)
        join_date = block['medianTime']
        parameters = yield from community.parameters()
        expiration_date = join_date + parameters['sigValidity']
        current_time = time.time()
        return expiration_date - current_time

    def _refresh_uid(self, uids):
        """
        Refresh UID from uids list, got from a successful lookup request
        :param list uids: UIDs got from a lookup request
        """
        timestamp = 0
        if self.local_state == LocalState.NOT_FOUND:
            for uid_data in uids:
                if uid_data["meta"]["timestamp"] > timestamp:
                    timestamp = uid_data["meta"]["timestamp"]
                    identity_uid = uid_data["uid"]
                    self.uid = identity_uid
                    self.blockchain_state = BlockchainState.BUFFERED
                    self.local_state = LocalState.PARTIAL

    def jsonify(self):
        """
        Get the community as dict in json format.
        :return: The community as a dict in json format
        """
        data = {'uid': self.uid,
                'pubkey': self.pubkey,
                'local_state': self.local_state.name,
                'blockchain_state': self.blockchain_state.name}
        return data

    def __str__(self):
        return "{0} - {1} - {2} - {3}".format(self.uid,
                                        self.pubkey,
                                        self.local_state,
                                        self.blockchain_state)
<commit_msg>Fix bug with certifiers-of and by<commit_after>"""
Created on 11 févr. 2014

@author: inso
"""

import logging
import time
import asyncio
from enum import Enum

from ucoinpy.documents.certification import SelfCertification
from ucoinpy.api import bma as bma
from ucoinpy.api.bma import PROTOCOL_VERSION

from ...tools.exceptions import Error, NoPeerAvailable,\
                                        MembershipNotFoundError
from PyQt5.QtCore import QObject, pyqtSignal

class LocalState(Enum):
    """
    The local state describes how the identity exists locally :
    COMPLETED means all its related datas (certifiers, certified...)
    were succefully downloaded
    PARTIAL means not all data are present locally
    NOT_FOUND means it could not be found anywhere
    """
    NOT_FOUND = 0
    PARTIAL = 1
    COMPLETED = 2

class BlockchainState(Enum):
    """
    The blockchain state describes how the identity
    was found :
    VALIDATED means it was found in the blockchain
    BUFFERED means it was found via a lookup but not in the
    blockchain
    NOT_FOUND means it could not be found anywhere
    """
    NOT_FOUND = 0
    BUFFERED = 1
    VALIDATED = 2

class Identity(QObject):
    """
    A person with a uid and a pubkey
    """
    def __init__(self, uid, pubkey, local_state, blockchain_state):
        """
        Initializing a person object.

        :param str uid: The person uid, also known as its uid on the network
        :param str pubkey: The person pubkey
        :param LocalState local_state: The local status of the identity
        :param BlockchainState blockchain_state: The blockchain status of the identity
        """
        super().__init__()
        self.uid = uid
        self.pubkey = pubkey
        self.local_state = local_state
        self.blockchain_state = blockchain_state

    @classmethod
    def empty(cls, pubkey):
        return cls("", pubkey, LocalState.NOT_FOUND, BlockchainState.NOT_FOUND)

    @classmethod
    def from_handled_data(cls, uid, pubkey, blockchain_state):
        return cls(uid, pubkey, LocalState.COMPLETED, blockchain_state)

    @classmethod
    def from_json(cls, json_data):
        """
        Create a person from json data

        :param dict json_data: The person as a dict in json format
        :return: A new person if pubkey wasn't known, else a new person instance.
        """
        pubkey = json_data['pubkey']
        uid = json_data['uid']
        local_state = LocalState[json_data['local_state']]
        blockchain_state = BlockchainState[json_data['blockchain_state']]

        return cls(uid, pubkey, local_state, blockchain_state)

    @asyncio.coroutine
    def selfcert(self, community):
        """
        Get the identity self certification.
        This request is not cached in the person object.

        :param cutecoin.core.community.Community community: The community target to request the self certification
        :return: A SelfCertification ucoinpy object
        :rtype: ucoinpy.documents.certification.SelfCertification
        """
        timestamp = 0
        lookup_data = yield from community.bma_access.future_request(bma.wot.Lookup, req_args={'search': self.pubkey})
        for result in lookup_data['results']:
            if result["pubkey"] == self.pubkey:
                uids = result['uids']
                for uid_data in uids:
                    if uid_data["meta"]["timestamp"] > timestamp:
                        timestamp = uid_data["meta"]["timestamp"]
                        uid = uid_data["uid"]
                        signature = uid_data["self"]

                return SelfCertification(PROTOCOL_VERSION,
                                         community.currency,
                                         self.pubkey,
                                         timestamp,
                                         uid,
                                         signature)
        return None

    @asyncio.coroutine
    def get_join_date(self, community):
        """
        Get the person join date.
        This request is not cached in the person object.

        :param cutecoin.core.community.Community community: The community target to request the join date
        :return: A datetime object
        """
        try:
            search = yield from community.bma_access.future_request(bma.blockchain.Membership,
                                                                    {'search': self.pubkey})
            if len(search['memberships']) > 0:
                membership_data = search['memberships'][0]
                block = yield from community.bma_access.future_request(bma.blockchain.Block,
                                req_args={'number': membership_data['blockNumber']})
                return block['medianTime']
        except ValueError as e:
            if '404' in str(e) or '400' in str(e):
                raise MembershipNotFoundError(self.pubkey, community.name)
        except NoPeerAvailable as e:
            logging.debug(str(e))
            raise MembershipNotFoundError(self.pubkey, community.name)

    @asyncio.coroutine
    def get_expiration_date(self, community):
        try:
            membership = yield from self.membership(community)
            join_block_number = membership['blockNumber']
            try:
                join_block = yield from community.bma_access.future_request(bma.blockchain.Block,
                                req_args={'number': join_block_number})

                parameters = yield from community.bma_access.future_request(bma.blockchain.Parameters)
                join_date = join_block['medianTime']
                expiration_date = join_date + parameters['sigValidity']
            except NoPeerAvailable:
                expiration_date = None
            except ValueError as e:
                logging.debug("Expiration date not found")
                expiration_date = None
        except MembershipNotFoundError:
            expiration_date = None
        return expiration_date

#TODO: Manage 'OUT' memberships ? Maybe ?
    @asyncio.coroutine
    def membership(self, community):
        """
        Get the person last membership document.

        :param cutecoin.core.community.Community community: The community target to request the join date
        :return: The membership data in BMA json format
        :rtype: dict
        """
        try:
            search = yield from community.bma_access.future_request(bma.blockchain.Membership,
                                           {'search': self.pubkey})
            block_number = -1
            membership_data = None
            for ms in search['memberships']:
                if ms['blockNumber'] > block_number:
                    block_number = ms['blockNumber']
                    if 'type' in ms:
                        if ms['type'] is 'IN':
                            membership_data = ms
                    else:
                        membership_data = ms
            if membership_data:
                return membership_data
            else:
                raise MembershipNotFoundError(self.pubkey, community.name)

        except ValueError as e:
            if '404' in str(e) or '400' in str(e):
                raise MembershipNotFoundError(self.pubkey, community.name)
        except NoPeerAvailable as e:
            logging.debug(str(e))
            raise MembershipNotFoundError(self.pubkey, community.name)
        except UnboundLocalError:
            raise

    @asyncio.coroutine
    def published_uid(self, community):
        try:
            data = yield from community.bma_access.future_request(bma.wot.Lookup,
                                 req_args={'search': self.pubkey})
        except ValueError as e:
            if '404' in str(e):
                timestamp = 0

                for result in data['results']:
                    if result["pubkey"] == self.pubkey:
                        uids = result['uids']
                        person_uid = ""
                        for uid_data in uids:
                            if uid_data["meta"]["timestamp"] > timestamp:
                                timestamp = uid_data["meta"]["timestamp"]
                                person_uid = uid_data["uid"]
                            if person_uid == self.uid:
                                return True
        except NoPeerAvailable as e:
            logging.debug(str(e))
        return False

    @asyncio.coroutine
    def is_member(self, community):
        """
        Check if the person is a member of a community

        :param cutecoin.core.community.Community community: The community target to request the join date
        :return: True if the person is a member of a community
        """
        try:
            certifiers = yield from community.bma_access.future_request(bma.wot.CertifiersOf,
                                                                        {'search': self.pubkey})
            return certifiers['isMember']
        except ValueError as e:
            if '404' in str(e) or '400' in str(e):
                pass
            else:
                raise
        except NoPeerAvailable as e:
            logging.debug(str(e))
        return False

    @asyncio.coroutine
    def certifiers_of(self, identities_registry, community):
        """
        Get the list of this person certifiers

        :param cutecoin.core.registry.identities.IdentitiesRegistry identities_registry: The identities registry
        :param cutecoin.core.community.Community community: The community target to request the join date
        :return: The list of the certifiers of this community
        :rtype: list
        """
        certifiers = list()
        try:
            data = yield from community.bma_access.future_request(bma.wot.CertifiersOf,
                                                                  {'search': self.pubkey})

            for certifier_data in data['certifications']:
                certifier = {}
                certifier['identity'] = identities_registry.from_handled_data(certifier_data['uid'],
                                                                              certifier_data['pubkey'],
                                                                              BlockchainState.VALIDATED,
                                                                              community)
                certifier['cert_time'] = certifier_data['cert_time']['medianTime']
                if 'written' in certifier_data and type(certifier_data['written']) is dict:
                    certifier['block_number'] = certifier_data['written']['number']
                else:
                    certifier['block_number'] = certifier_data['cert_time']['block']

                certifiers.append(certifier)
        except ValueError as e:
            if '404' in str(e):
                logging.debug('bma.wot.CertifiersOf request error: {0}'.format(str(e)))
            else:
                logging.debug(str(e))
        except NoPeerAvailable as e:
            logging.debug(str(e))

        try:
            data = yield from community.bma_access.future_request(bma.wot.Lookup, {'search': self.pubkey})
            for result in data['results']:
                if result["pubkey"] == self.pubkey:
                    self._refresh_uid(result['uids'])
                    for uid_data in result['uids']:
                        for certifier_data in uid_data['others']:
                            for uid in certifier_data['uids']:
                                # add a certifier
                                certifier = {}
                                certifier['identity'] = identities_registry.\
                                    from_handled_data(uid,
                                                      certifier_data['pubkey'],
                                                      BlockchainState.BUFFERED,
                                                      community)
                                if certifier['identity'] not in certifiers:
                                    block = yield from community.bma_access.future_request(bma.blockchain.Block,
                                                                         {'number': certifier_data['meta']['block_number']})
                                    certifier['cert_time'] = block['medianTime']
                                    certifier['block_number'] = None

                                    certifiers.append(certifier)
        except ValueError as e:
            logging.debug("Lookup error : {0}".format(str(e)))
        except NoPeerAvailable as e:
            logging.debug(str(e))
        return certifiers

    @asyncio.coroutine
    def unique_valid_certifiers_of(self, identities_registry, community):
        certifier_list = yield from self.certifiers_of(identities_registry, community)
        unique_valid = []
        #  add certifiers of uid
        for certifier in tuple(certifier_list):
            # add only valid certification...
            try:
                cert_expired = yield from community.certification_expired(certifier['cert_time'])
            except NoPeerAvailable:
                logging.debug("No peer available")
                cert_expired = True

            if not cert_expired:
                # keep only the latest certification
                already_found = [c['identity'].pubkey for c in unique_valid]
                if certifier['identity'].pubkey in already_found:
                    index = already_found.index(certifier['identity'].pubkey)
                    if certifier['cert_time'] > unique_valid[index]['cert_time']:
                        unique_valid[index] = certifier
                else:
                    unique_valid.append(certifier)
        return unique_valid

    @asyncio.coroutine
    def certified_by(self, identities_registry, community):
        """
        Get the list of persons certified by this person
        :param cutecoin.core.registry.IdentitiesRegistry identities_registry: The registry
        :param cutecoin.core.Community community: The community

        :param cutecoin.core.community.Community community: The community target to request the join date
        :return: The list of the certified persons of this community in BMA json format
        :rtype: list
        """
        certified_list = list()
        try:
            data = yield from community.bma_access.future_request(bma.wot.CertifiedBy, {'search': self.pubkey})
            for certified_data in data['certifications']:
                certified = {}
                certified['identity'] = identities_registry.from_handled_data(certified_data['uid'],
                                                                              certified_data['pubkey'],
                                                                              BlockchainState.VALIDATED,
                                                                              community)
                certified['cert_time'] = certified_data['cert_time']['medianTime']
                if 'written' in certified_data and type(certified_data['written']) is dict:
                    certified['block_number'] = certified_data['written']['number']
                else:
                    certified['block_number'] = certified_data['cert_time']['block']
                certified_list.append(certified)
        except ValueError as e:
            if '404' in str(e):
                logging.debug('bma.wot.CertifiersOf request error')
        except NoPeerAvailable as e:
            logging.debug(str(e))

        try:
            data = yield from community.bma_access.future_request(bma.wot.Lookup, {'search': self.pubkey})
            for result in data['results']:
                if result["pubkey"] == self.pubkey:
                    self._refresh_uid(result['uids'])
                    for certified_data in result['signed']:
                        certified = {}
                        certified['identity'] = identities_registry.from_handled_data(certified_data['uid'],
                                                                          certified_data['pubkey'],
                                                                          BlockchainState.BUFFERED,
                                                                          community)
                        if certified['identity'] not in certified_list:
                            certified['cert_time'] = certified_data['meta']['timestamp']
                            certified['block_number'] = None
                            certified_list.append(certified)
        except ValueError as e:
            if '404' in str(e):
                logging.debug('bma.wot.Lookup request error')
        except NoPeerAvailable as e:
            logging.debug(str(e))
        return certified_list

    @asyncio.coroutine
    def unique_valid_certified_by(self, identities_registry, community):
        certified_list = yield from self.certified_by(identities_registry, community)
        unique_valid = []
        #  add certifiers of uid
        for certified in tuple(certified_list):
            # add only valid certification...
            try:
                cert_expired = yield from community.certification_expired(certified['cert_time'])
            except NoPeerAvailable:
                logging.debug("No peer available")
                cert_expired = True

            if not cert_expired:
                # keep only the latest certification
                already_found = [c['identity'].pubkey for c in unique_valid]
                if certified['identity'].pubkey in already_found:
                    index = already_found.index(certified['identity'].pubkey)
                    if certified['cert_time'] > unique_valid[index]['cert_time']:
                        unique_valid[index] = certified
                else:
                    unique_valid.append(certified)
        return unique_valid

    @asyncio.coroutine
    def membership_expiration_time(self, community):
        membership = yield from self.membership(community)
        join_block = membership['blockNumber']
        block = yield from community.get_block(join_block)
        join_date = block['medianTime']
        parameters = yield from community.parameters()
        expiration_date = join_date + parameters['sigValidity']
        current_time = time.time()
        return expiration_date - current_time

    def _refresh_uid(self, uids):
        """
        Refresh UID from uids list, got from a successful lookup request
        :param list uids: UIDs got from a lookup request
        """
        timestamp = 0
        if self.local_state == LocalState.NOT_FOUND:
            for uid_data in uids:
                if uid_data["meta"]["timestamp"] > timestamp:
                    timestamp = uid_data["meta"]["timestamp"]
                    identity_uid = uid_data["uid"]
                    self.uid = identity_uid
                    self.blockchain_state = BlockchainState.BUFFERED
                    self.local_state = LocalState.PARTIAL

    def jsonify(self):
        """
        Get the community as dict in json format.
        :return: The community as a dict in json format
        """
        data = {'uid': self.uid,
                'pubkey': self.pubkey,
                'local_state': self.local_state.name,
                'blockchain_state': self.blockchain_state.name}
        return data

    def __str__(self):
        return "{0} - {1} - {2} - {3}".format(self.uid,
                                        self.pubkey,
                                        self.local_state,
                                        self.blockchain_state)
<|endoftext|>


<commit_before>#!/usr/bin/env python

# Tested on v2.5
# written based on https://github.com/volatilityfoundation/volatility/blob/master/volatility/plugins/registry/shutdown.py

"""
Note: All of the information being queried may not be present
"""
import string
import volatility.addrspace as addrspace
import volatility.debug as debug
import volatility.obj as obj
import volatility.plugins.common as common
import volatility.plugins.registry.registryapi as registryapi
from volatility.renderers import TreeGrid
import volatility.timefmt as timefmt
import volatility.utils as utils

from datetime import datetime
import struct

class USBSTOR(common.AbstractWindowsCommand):
    "Parse USB Data from the Registry"

    def __init__(self, config, *args, **kwargs):
        common.AbstractWindowsCommand.__init__(self, config, *args, **kwargs)
        self.regapi = None

    def string_clean_hex(self, line):
        line = str(line)
        new_line = ''
        for c in line:
            if c in string.printable:
                new_line += c
            else:
                new_line += '\\x' + c.encode('hex')
        return new_line

    def calculate(self):
        addr_space = utils.load_as(self._config)
        self.regapi = registryapi.RegistryApi(self._config)
        self.regapi.set_current("SYSTEM")
        self.regapi.reset_current()
        currentcs = self.regapi.reg_get_currentcontrolset()

        if currentcs == None:
            currentcs = "ControlSet001"

        # Get list of devices form USBSTOR

        # RESET the API
        self.regapi.reset_current()
        # Store teh results in a dict
        results = {}
        results['subkeys'] = []
        results['USB_DEVICES'] = []

        USB_PATH = '{0}\\Enum\\USB'.format(currentcs)
        usb_key = self.regapi.reg_get_key('SYSTEM', USB_PATH)
        USB_STOR_PATH = '{0}\\Enum\\USBSTOR'.format(currentcs)
        usb_stor_key = self.regapi.reg_get_key('SYSTEM', USB_STOR_PATH)

        if usb_stor_key == None:
            results['exists'] = False
        else:
            results['exists'] = True

        sub_keys = self.regapi.reg_get_all_subkeys('SYSTEM', USB_STOR_PATH, given_root=usb_stor_key)
        for k in sub_keys:
            # Theses are grouped by vender
            #debug.info("Vendor / Brand / Rev: {0}".format(str(k.Name)))

            disk, vendor, product, rev = str(k.Name).split('&')
            vendor = vendor.split('_', 1)[-1]
            product = product.split('_', 1)[-1]
            rev = rev.split('_', 1)[-1]

            results['subkeys'].append(str(k.Name))
            usb_devs = self.regapi.reg_get_all_subkeys('SYSTEM', k, given_root=k)
            for dev in usb_devs:
                # These are individual devices
                # This is what we use to map in to the USB_DEVICES

                usb_info_dict = {}

                #Serial Number
                usb_info_dict['Serial Number'] = str(dev.Name)
                usb_info_dict['Vendor'] = vendor
                usb_info_dict['Product'] = product
                usb_info_dict['Revision'] = rev

                # Get all the sub values
                values = self.regapi.reg_yield_values('SYSTEM', dev, given_root=dev)
                for val in values:
                    try:
                        key_name = val[0].replace('\x00', '')
                        key_data = val[1].replace('\x00', '')
                        usb_info_dict[str(key_name)] = key_data
                    except AttributeError:
                        key_name = val[0].replace('\x00', '')
                        key_data = val[1]
                        usb_info_dict[str(key_name)] = key_data

                # Get the last written key for each device

                serial_number = usb_info_dict['Serial Number']
                usb_subkeys = self.regapi.reg_get_all_subkeys('SYSTEM', USB_PATH, given_root=usb_key)
                for a in usb_subkeys:
                    subs = self.regapi.reg_get_all_subkeys('SYSTEM', a, given_root=a)
                    for s in subs:
                        if serial_number.split('&')[0] == s.Name:
                            usb_info_dict['Device Last Plugged In'] = s.LastWriteTime

                # Now get the Drive letters if we can
                MOUNTED_DEVICES = 'MountedDevices'
                mounted_devices_key = self.regapi.reg_get_key('SYSTEM', MOUNTED_DEVICES)
                debug.info(usb_info_dict)
                ParentID = usb_info_dict['ParentIdPrefix']

                values = self.regapi.reg_yield_values('SYSTEM', mounted_devices_key, given_root=mounted_devices_key)
                for val in values:
                    key_name = val[0]
                    key_data = val[1]
                    key_data = key_data.replace('\x00', '')
                    key_data = self.string_clean_hex(key_data)
                    #debug.info(key_data)
                    #debug.info(key_data.encode('hex'))
                    if ParentID in key_data:
                        if 'Device' in str(key_name):
                            usb_info_dict['Drive Letter'] = key_name
                        else:
                            usb_info_dict['Drive Letter'] = "Unknown"
                        if 'Volume' in str(key_name):
                            usb_info_dict['Mounted Volume'] = key_name
                        else:
                            usb_info_dict['Mounted Volume'] = "Unknown"

                    #usb_info_dict[key_name] = key_data

                # Check if the current NTUSER.dat file contains the MountPoints2 entry
                # If yes user = this one else user = unknown

        results['USB_DEVICES'].append(usb_info_dict)

        # Return the results dict
        yield results

    '''
    def unified_output(self, data):
        return TreeGrid([("Date/Time (UTC)", str),
                            ("Type", str),
                            ("Summary", str),
                            ("Source", str),
                        ], self.generator(data)
                      )

    def generator(self, data):
        for result in data:
            yield (0, ['{0}'.format(result.get('timestamp') if result.get('timestamp') else result.get('key').LastWriteTime),
                        '{0}'.format(result.get('value') if not result.get('timestamp_type') else result.get('timestamp_type')),
                        ('' if result.get('timestamp') else '{0}'.format(result.get('value'))),
                        ('' if not result.get('hive') else '{0} | {1}\\{2}'.format(result.get('value_name'),
                                                                                result.get('hive'),
                                                                                ('' if not result.get('key') else self.regapi.reg_get_key_path(result.get('key')))
                                                                                )
                                            ),
                    ]
                )
    '''
    # Print to screen
    def render_text(self, outfd, data):
        outfd.write('Reading the USBSTOR Please Wait\n')
        for result in data:
            if not result['exists']:
                outfd.write('USBSTOR Not found in SYSTEM Hive\n')
            else:
                for usbdev in result['USB_DEVICES']:
                    outfd.write('Found USB Drive: \n')
                    for k, v in usbdev.iteritems():
                        outfd.write('{0}\t{1}\n'.format(k, v))

        outfd.write('\n')
<commit_msg>No USBSTOR Found<commit_after>#!/usr/bin/env python

# Tested on v2.5
# written based on https://github.com/volatilityfoundation/volatility/blob/master/volatility/plugins/registry/shutdown.py

"""
Note: All of the information being queried may not be present
"""
import string
import volatility.addrspace as addrspace
import volatility.debug as debug
import volatility.obj as obj
import volatility.plugins.common as common
import volatility.plugins.registry.registryapi as registryapi
from volatility.renderers import TreeGrid
import volatility.timefmt as timefmt
import volatility.utils as utils

from datetime import datetime
import struct

class USBSTOR(common.AbstractWindowsCommand):
    "Parse USB Data from the Registry"

    def __init__(self, config, *args, **kwargs):
        common.AbstractWindowsCommand.__init__(self, config, *args, **kwargs)
        self.regapi = None

    def string_clean_hex(self, line):
        line = str(line)
        new_line = ''
        for c in line:
            if c in string.printable:
                new_line += c
            else:
                new_line += '\\x' + c.encode('hex')
        return new_line

    def calculate(self):
        addr_space = utils.load_as(self._config)
        self.regapi = registryapi.RegistryApi(self._config)
        self.regapi.set_current("SYSTEM")
        self.regapi.reset_current()
        currentcs = self.regapi.reg_get_currentcontrolset()

        if currentcs == None:
            currentcs = "ControlSet001"

        # Get list of devices form USBSTOR

        # RESET the API
        self.regapi.reset_current()
        # Store teh results in a dict
        results = {}
        results['subkeys'] = []
        results['USB_DEVICES'] = []

        USB_PATH = '{0}\\Enum\\USB'.format(currentcs)
        usb_key = self.regapi.reg_get_key('SYSTEM', USB_PATH)
        USB_STOR_PATH = '{0}\\Enum\\USBSTOR'.format(currentcs)
        usb_stor_key = self.regapi.reg_get_key('SYSTEM', USB_STOR_PATH)

        if usb_stor_key == None:
            results['exists'] = False
            yield results
        else:
            results['exists'] = True

        # Only run if we have something to do
        if results['exists']:
            sub_keys = self.regapi.reg_get_all_subkeys('SYSTEM', USB_STOR_PATH, given_root=usb_stor_key)
            for k in sub_keys:
                # Theses are grouped by vender
                #debug.info("Vendor / Brand / Rev: {0}".format(str(k.Name)))

                disk, vendor, product, rev = str(k.Name).split('&')
                vendor = vendor.split('_', 1)[-1]
                product = product.split('_', 1)[-1]
                rev = rev.split('_', 1)[-1]

                results['subkeys'].append(str(k.Name))
                usb_devs = self.regapi.reg_get_all_subkeys('SYSTEM', k, given_root=k)
                for dev in usb_devs:
                    # These are individual devices
                    # This is what we use to map in to the USB_DEVICES

                    usb_info_dict = {}

                    #Serial Number
                    usb_info_dict['Serial Number'] = str(dev.Name)
                    usb_info_dict['Vendor'] = vendor
                    usb_info_dict['Product'] = product
                    usb_info_dict['Revision'] = rev

                    # Get all the sub values
                    values = self.regapi.reg_yield_values('SYSTEM', dev, given_root=dev)
                    for val in values:
                        try:
                            key_name = val[0].replace('\x00', '')
                            key_data = val[1].replace('\x00', '')
                            usb_info_dict[str(key_name)] = key_data
                        except AttributeError:
                            key_name = val[0].replace('\x00', '')
                            key_data = val[1]
                            usb_info_dict[str(key_name)] = key_data

                    # Get the last written key for each device

                    serial_number = usb_info_dict['Serial Number']
                    usb_subkeys = self.regapi.reg_get_all_subkeys('SYSTEM', USB_PATH, given_root=usb_key)
                    for a in usb_subkeys:
                        subs = self.regapi.reg_get_all_subkeys('SYSTEM', a, given_root=a)
                        for s in subs:
                            if serial_number.split('&')[0] == s.Name:
                                usb_info_dict['Device Last Plugged In'] = s.LastWriteTime

                    # Now get the Drive letters if we can
                    MOUNTED_DEVICES = 'MountedDevices'
                    mounted_devices_key = self.regapi.reg_get_key('SYSTEM', MOUNTED_DEVICES)
                    ParentID = usb_info_dict['ParentIdPrefix']

                    values = self.regapi.reg_yield_values('SYSTEM', mounted_devices_key, given_root=mounted_devices_key)
                    for val in values:
                        key_name = val[0]
                        key_data = val[1]
                        key_data = key_data.replace('\x00', '')
                        key_data = self.string_clean_hex(key_data)
                        #debug.info(key_data)
                        #debug.info(key_data.encode('hex'))
                        usb_info_dict['Drive Letter'] = "Unknown"
                        usb_info_dict['Mounted Volume'] = "Unknown"
                        if ParentID in key_data:
                            if 'Device' in str(key_name):
                                usb_info_dict['Drive Letter'] = key_name
                            elif 'Volume' in str(key_name):
                                usb_info_dict['Mounted Volume'] = key_name

                        #usb_info_dict[key_name] = key_data

                    # Check if the current NTUSER.dat file contains the MountPoints2 entry
                    # If yes user = this one else user = unknown

            results['USB_DEVICES'].append(usb_info_dict)

            # Return the results dict
            yield results

    '''
    def unified_output(self, data):
        return TreeGrid([("Date/Time (UTC)", str),
                            ("Type", str),
                            ("Summary", str),
                            ("Source", str),
                        ], self.generator(data)
                      )

    def generator(self, data):
        for result in data:
            yield (0, ['{0}'.format(result.get('timestamp') if result.get('timestamp') else result.get('key').LastWriteTime),
                        '{0}'.format(result.get('value') if not result.get('timestamp_type') else result.get('timestamp_type')),
                        ('' if result.get('timestamp') else '{0}'.format(result.get('value'))),
                        ('' if not result.get('hive') else '{0} | {1}\\{2}'.format(result.get('value_name'),
                                                                                result.get('hive'),
                                                                                ('' if not result.get('key') else self.regapi.reg_get_key_path(result.get('key')))
                                                                                )
                                            ),
                    ]
                )
    '''
    # Print to screen
    def render_text(self, outfd, data):
        outfd.write('Reading the USBSTOR Please Wait\n')
        for result in data:
            if not result['exists']:
                outfd.write('USBSTOR Not found in SYSTEM Hive\n')
            else:
                for usbdev in result['USB_DEVICES']:
                    outfd.write('Found USB Drive: \n')
                    for k, v in usbdev.iteritems():
                        outfd.write('\t{0}:\t{1}\n'.format(k, v))

        outfd.write('\n')
<|endoftext|>


<commit_before>import os
import pwd
import grp
import sys
import time
import signal
import daemon
import optparse
import datetime
import multiprocessing

from pandajedi.jediddm.DDMInterface import DDMInterface
from pandajedi.jedicore.JediTaskBufferInterface import JediTaskBufferInterface
from pandajedi.jedicore.ThreadUtils import ZombiCleaner
from pandajedi.jedicore.ProcessUtils import ProcessWrapper

from pandajedi.jediconfig import jedi_config

# the master class of JEDI which runs the main process
class JediMaster:

    # constrictor
    def __init__(self):
        self.stopEventList = []

    # spawn a knight to have own file descriptors
    def launcher(self, moduleName, *args, **kwargs):
        # import module
        mod = __import__(moduleName)
        for subModuleName in moduleName.split('.')[1:]:
            mod = getattr(mod, subModuleName)
        # launch
        timeNow = datetime.datetime.utcnow()
        print("{0} {1}: INFO    start {2} with pid={3}".format(str(timeNow),
                                                               moduleName,
                                                               'launcher',
                                                               os.getpid()))
        mod.launcher(*args, **kwargs)

    # convert config parameters
    def convParams(self, itemStr):
        items = itemStr.split(':')
        newItems = []
        for item in items:
            if item == '':
                newItems.append(None)
            elif ',' in item:
                newItems.append(item.split(','))
            else:
                try:
                    newItems.append(int(item))
                except Exception:
                    newItems.append(item)
        return newItems

    # main loop
    def start(self):
        # start zombi cleaner
        ZombiCleaner().start()
        # setup DDM I/F
        ddmIF = DDMInterface()
        ddmIF.setupInterface()
        # setup TaskBuffer I/F
        taskBufferIF = JediTaskBufferInterface()
        taskBufferIF.setupInterface()
        # setup intra-node message queue broker proxies
        if hasattr(jedi_config, 'mq') and hasattr(jedi_config.mq, 'configFile') and jedi_config.mq.configFile:
            from pandajedi.jediorder.JediMsgProcessor import MsgProcAgent
            mq_agent = MsgProcAgent(config_file=jedi_config.mq.configFile)
            mb_proxy_dict = mq_agent.start_passive_mode(prefetch_size=999)
        # the list of JEDI knights
        knightList = []
        # setup TaskRefiner
        for itemStr in jedi_config.taskrefine.procConfig.split(';'):
            items = self.convParams(itemStr)
            vo = items[0]
            plabel = items[1]
            nProc = items[2]
            for iproc in range(nProc):
                parent_conn, child_conn = multiprocessing.Pipe()
                proc = multiprocessing.Process(target=self.launcher,
                                               args=('pandajedi.jediorder.TaskRefiner',
                                                     child_conn, taskBufferIF, ddmIF,
                                                     vo, plabel))
                proc.start()
                knightList.append(proc)
        # setup TaskBrokerage
        for itemStr in jedi_config.taskbroker.procConfig.split(';'):
            items = self.convParams(itemStr)
            vo = items[0]
            plabel = items[1]
            nProc = items[2]
            for iproc in range(nProc):
                parent_conn, child_conn = multiprocessing.Pipe()
                proc = multiprocessing.Process(target=self.launcher,
                                               args=('pandajedi.jediorder.TaskBroker',
                                                     child_conn, taskBufferIF, ddmIF,
                                                     vo, plabel))
                proc.start()
                knightList.append(proc)
        # setup ContentsFeeder
        for itemStr in jedi_config.confeeder.procConfig.split(';'):
            items = self.convParams(itemStr)
            vo = items[0]
            plabel = items[1]
            nProc = items[2]
            for iproc in range(nProc):
                parent_conn, child_conn = multiprocessing.Pipe()
                proc = multiprocessing.Process(target=self.launcher,
                                               args=('pandajedi.jediorder.ContentsFeeder',
                                                     child_conn, taskBufferIF,
                                                     ddmIF, vo, plabel))
                proc.start()
                knightList.append(proc)
        # setup JobGenerator
        for itemStr in jedi_config.jobgen.procConfig.split(';'):
            items = self.convParams(itemStr)
            vo = items[0]
            plabel = items[1]
            nProc = items[2]
            cloud = items[3]
            try:
                loop_cycle = items[4]
            except IndexError:
                loop_cycle = None

            if not isinstance(cloud, list):
                cloud = [cloud]
            for iproc in range(nProc):
                parent_conn, child_conn = multiprocessing.Pipe()
                proc = ProcessWrapper(target=self.launcher,
                                      args=('pandajedi.jediorder.JobGenerator', child_conn, taskBufferIF, ddmIF, vo,
                                            plabel, cloud, True, True, loop_cycle))
                proc.start()
                knightList.append(proc)
        # setup PostProcessor
        for itemStr in jedi_config.postprocessor.procConfig.split(';'):
            items = self.convParams(itemStr)
            vo = items[0]
            plabel = items[1]
            nProc = items[2]
            for iproc in range(nProc):
                parent_conn, child_conn = multiprocessing.Pipe()
                proc = multiprocessing.Process(target=self.launcher,
                                               args=('pandajedi.jediorder.PostProcessor',
                                                     child_conn, taskBufferIF, ddmIF,
                                                     vo, plabel))
                proc.start()
                knightList.append(proc)
        # setup TaskCommando
        for itemStr in jedi_config.tcommando.procConfig.split(';'):
            items = self.convParams(itemStr)
            vo = items[0]
            plabel = items[1]
            nProc = items[2]
            for iproc in range(nProc):
                parent_conn, child_conn = multiprocessing.Pipe()
                proc = multiprocessing.Process(target=self.launcher,
                                               args=('pandajedi.jediorder.TaskCommando',
                                                     child_conn, taskBufferIF, ddmIF,
                                                     vo, plabel))
                proc.start()
                knightList.append(proc)
        # setup WatchDog
        for itemStr in jedi_config.watchdog.procConfig.split(';'):
            items = self.convParams(itemStr)
            vo = items[0]
            plabel = items[1]
            nProc = items[2]
            subStr = items[3] if len(items) > 3 else None
            period = items[4] if len(items) > 4 else None
            for iproc in range(nProc):
                parent_conn, child_conn = multiprocessing.Pipe()
                proc = multiprocessing.Process(target=self.launcher,
                                               args=('pandajedi.jediorder.WatchDog',
                                                     child_conn, taskBufferIF, ddmIF,
                                                     vo, plabel, subStr, period))
                proc.start()
                knightList.append(proc)
        # setup JediMsgProcessor agent (only one system process)
        if hasattr(jedi_config, 'msgprocessor') and hasattr(jedi_config.msgprocessor,
                                                            'configFile') and jedi_config.msgprocessor.configFile:
            stop_event = multiprocessing.Event()
            self.stopEventList.append(stop_event)
            parent_conn, child_conn = multiprocessing.Pipe()
            proc = multiprocessing.Process(target=self.launcher,
                                           args=('pandajedi.jediorder.JediMsgProcessor',
                                                 stop_event))
            proc.start()
            knightList.append(proc)
        # setup JediDaemon agent (only one system process)
        if hasattr(jedi_config, 'daemon') and hasattr(jedi_config.daemon, 'enable') and jedi_config.daemon.enable:
            parent_conn, child_conn = multiprocessing.Pipe()
            proc = multiprocessing.Process(target=self.launcher,
                                           args=('pandajedi.jediorder.JediDaemon',
                                                 taskBufferIF, ddmIF))
            proc.start()
            knightList.append(proc)
        # check initial failures
        time.sleep(5)
        for knight in knightList:
            if not knight.is_alive():
                timeNow = datetime.datetime.utcnow()
                print("{0} {1}: ERROR    pid={2} died in initialization".format(str(timeNow),
                                                                                self.__class__.__name__,
                                                                                knight.pid))
                os.killpg(os.getpgrp(), signal.SIGKILL)
        # join
        for knight in knightList:
            knight.join()

    # graceful stop
    def stop(self):
        for stop_event in self.stopEventList:
            stop_event.set()

# kill whole process
def kill_whole(sig, frame):
    # kill
    os.killpg(os.getpgrp(), signal.SIGKILL)

# main
if __name__ == "__main__":
    # parse option
    parser = optparse.OptionParser()
    parser.add_option('--pid', action='store', dest='pid', default=None,
                      help='pid filename')
    options, args = parser.parse_args()
    uid = None
    gid = None
    if 'PANDA_NO_ROOT' not in os.environ:
        if jedi_config.master.uname:
            uid = pwd.getpwnam(jedi_config.master.uname).pw_uid
        if jedi_config.master.gname:
            gid = grp.getgrnam(jedi_config.master.gname).gr_gid
    timeNow = datetime.datetime.utcnow()
    print("{0} JediMaster: INFO    start".format(str(timeNow)))
    # make daemon context
    dc = daemon.DaemonContext(stdout=sys.stdout,
                              stderr=sys.stderr,
                              uid=uid,
                              gid=gid)
    with dc:
        # record PID
        go_ahead = True
        try:
            pidFile = open(options.pid, 'x')
        except FileExistsError:
            print("{} JediMaster: ERROR    terminated since pid file {} already exists".format(str(timeNow),
                                                                                options.pid))
            go_ahead = False
        if go_ahead:
            pidFile.write('{0}'.format(os.getpid()))
            pidFile.close()
            # master
            master = JediMaster()

            # set handler
            def catch_sig(sig, frame):
                master.stop()
                time.sleep(3)
                kill_whole(sig, frame)

            signal.signal(signal.SIGINT, catch_sig)
            signal.signal(signal.SIGHUP, catch_sig)
            signal.signal(signal.SIGTERM, catch_sig)
            # start master
            master.start()
<commit_msg>removed MsgProcAgent stuff from the main process to avoid interference with Interaction<commit_after>import os
import pwd
import grp
import sys
import time
import signal
import daemon
import optparse
import datetime
import multiprocessing

from pandajedi.jediddm.DDMInterface import DDMInterface
from pandajedi.jedicore.JediTaskBufferInterface import JediTaskBufferInterface
from pandajedi.jedicore.ThreadUtils import ZombiCleaner
from pandajedi.jedicore.ProcessUtils import ProcessWrapper

from pandajedi.jediconfig import jedi_config

# the master class of JEDI which runs the main process
class JediMaster:

    # constrictor
    def __init__(self):
        self.stopEventList = []

    # spawn a knight to have own file descriptors
    def launcher(self, moduleName, *args, **kwargs):
        # import module
        mod = __import__(moduleName)
        for subModuleName in moduleName.split('.')[1:]:
            mod = getattr(mod, subModuleName)
        # launch
        timeNow = datetime.datetime.utcnow()
        print("{0} {1}: INFO    start {2} with pid={3}".format(str(timeNow),
                                                               moduleName,
                                                               'launcher',
                                                               os.getpid()))
        mod.launcher(*args, **kwargs)

    # convert config parameters
    def convParams(self, itemStr):
        items = itemStr.split(':')
        newItems = []
        for item in items:
            if item == '':
                newItems.append(None)
            elif ',' in item:
                newItems.append(item.split(','))
            else:
                try:
                    newItems.append(int(item))
                except Exception:
                    newItems.append(item)
        return newItems

    # main loop
    def start(self):
        # start zombi cleaner
        ZombiCleaner().start()
        # setup DDM I/F
        ddmIF = DDMInterface()
        ddmIF.setupInterface()
        # setup TaskBuffer I/F
        taskBufferIF = JediTaskBufferInterface()
        taskBufferIF.setupInterface()
        # the list of JEDI knights
        knightList = []
        # setup TaskRefiner
        for itemStr in jedi_config.taskrefine.procConfig.split(';'):
            items = self.convParams(itemStr)
            vo = items[0]
            plabel = items[1]
            nProc = items[2]
            for iproc in range(nProc):
                parent_conn, child_conn = multiprocessing.Pipe()
                proc = multiprocessing.Process(target=self.launcher,
                                               args=('pandajedi.jediorder.TaskRefiner',
                                                     child_conn, taskBufferIF, ddmIF,
                                                     vo, plabel))
                proc.start()
                knightList.append(proc)
        # setup TaskBrokerage
        for itemStr in jedi_config.taskbroker.procConfig.split(';'):
            items = self.convParams(itemStr)
            vo = items[0]
            plabel = items[1]
            nProc = items[2]
            for iproc in range(nProc):
                parent_conn, child_conn = multiprocessing.Pipe()
                proc = multiprocessing.Process(target=self.launcher,
                                               args=('pandajedi.jediorder.TaskBroker',
                                                     child_conn, taskBufferIF, ddmIF,
                                                     vo, plabel))
                proc.start()
                knightList.append(proc)
        # setup ContentsFeeder
        for itemStr in jedi_config.confeeder.procConfig.split(';'):
            items = self.convParams(itemStr)
            vo = items[0]
            plabel = items[1]
            nProc = items[2]
            for iproc in range(nProc):
                parent_conn, child_conn = multiprocessing.Pipe()
                proc = multiprocessing.Process(target=self.launcher,
                                               args=('pandajedi.jediorder.ContentsFeeder',
                                                     child_conn, taskBufferIF,
                                                     ddmIF, vo, plabel))
                proc.start()
                knightList.append(proc)
        # setup JobGenerator
        for itemStr in jedi_config.jobgen.procConfig.split(';'):
            items = self.convParams(itemStr)
            vo = items[0]
            plabel = items[1]
            nProc = items[2]
            cloud = items[3]
            try:
                loop_cycle = items[4]
            except IndexError:
                loop_cycle = None

            if not isinstance(cloud, list):
                cloud = [cloud]
            for iproc in range(nProc):
                parent_conn, child_conn = multiprocessing.Pipe()
                proc = ProcessWrapper(target=self.launcher,
                                      args=('pandajedi.jediorder.JobGenerator', child_conn, taskBufferIF, ddmIF, vo,
                                            plabel, cloud, True, True, loop_cycle))
                proc.start()
                knightList.append(proc)
        # setup PostProcessor
        for itemStr in jedi_config.postprocessor.procConfig.split(';'):
            items = self.convParams(itemStr)
            vo = items[0]
            plabel = items[1]
            nProc = items[2]
            for iproc in range(nProc):
                parent_conn, child_conn = multiprocessing.Pipe()
                proc = multiprocessing.Process(target=self.launcher,
                                               args=('pandajedi.jediorder.PostProcessor',
                                                     child_conn, taskBufferIF, ddmIF,
                                                     vo, plabel))
                proc.start()
                knightList.append(proc)
        # setup TaskCommando
        for itemStr in jedi_config.tcommando.procConfig.split(';'):
            items = self.convParams(itemStr)
            vo = items[0]
            plabel = items[1]
            nProc = items[2]
            for iproc in range(nProc):
                parent_conn, child_conn = multiprocessing.Pipe()
                proc = multiprocessing.Process(target=self.launcher,
                                               args=('pandajedi.jediorder.TaskCommando',
                                                     child_conn, taskBufferIF, ddmIF,
                                                     vo, plabel))
                proc.start()
                knightList.append(proc)
        # setup WatchDog
        for itemStr in jedi_config.watchdog.procConfig.split(';'):
            items = self.convParams(itemStr)
            vo = items[0]
            plabel = items[1]
            nProc = items[2]
            subStr = items[3] if len(items) > 3 else None
            period = items[4] if len(items) > 4 else None
            for iproc in range(nProc):
                parent_conn, child_conn = multiprocessing.Pipe()
                proc = multiprocessing.Process(target=self.launcher,
                                               args=('pandajedi.jediorder.WatchDog',
                                                     child_conn, taskBufferIF, ddmIF,
                                                     vo, plabel, subStr, period))
                proc.start()
                knightList.append(proc)
        # setup JediMsgProcessor agent (only one system process)
        if hasattr(jedi_config, 'msgprocessor') and hasattr(jedi_config.msgprocessor,
                                                            'configFile') and jedi_config.msgprocessor.configFile:
            stop_event = multiprocessing.Event()
            self.stopEventList.append(stop_event)
            parent_conn, child_conn = multiprocessing.Pipe()
            proc = multiprocessing.Process(target=self.launcher,
                                           args=('pandajedi.jediorder.JediMsgProcessor',
                                                 stop_event))
            proc.start()
            knightList.append(proc)
        # setup JediDaemon agent (only one system process)
        if hasattr(jedi_config, 'daemon') and hasattr(jedi_config.daemon, 'enable') and jedi_config.daemon.enable:
            parent_conn, child_conn = multiprocessing.Pipe()
            proc = multiprocessing.Process(target=self.launcher,
                                           args=('pandajedi.jediorder.JediDaemon',
                                                 taskBufferIF, ddmIF))
            proc.start()
            knightList.append(proc)
        # check initial failures
        time.sleep(5)
        for knight in knightList:
            if not knight.is_alive():
                timeNow = datetime.datetime.utcnow()
                print("{0} {1}: ERROR    pid={2} died in initialization".format(str(timeNow),
                                                                                self.__class__.__name__,
                                                                                knight.pid))
                os.killpg(os.getpgrp(), signal.SIGKILL)
        # join
        for knight in knightList:
            knight.join()

    # graceful stop
    def stop(self):
        for stop_event in self.stopEventList:
            stop_event.set()

# kill whole process
def kill_whole(sig, frame):
    # kill
    os.killpg(os.getpgrp(), signal.SIGKILL)

# main
if __name__ == "__main__":
    # parse option
    parser = optparse.OptionParser()
    parser.add_option('--pid', action='store', dest='pid', default=None,
                      help='pid filename')
    options, args = parser.parse_args()
    uid = None
    gid = None
    if 'PANDA_NO_ROOT' not in os.environ:
        if jedi_config.master.uname:
            uid = pwd.getpwnam(jedi_config.master.uname).pw_uid
        if jedi_config.master.gname:
            gid = grp.getgrnam(jedi_config.master.gname).gr_gid
    timeNow = datetime.datetime.utcnow()
    print("{0} JediMaster: INFO    start".format(str(timeNow)))
    # make daemon context
    dc = daemon.DaemonContext(stdout=sys.stdout,
                              stderr=sys.stderr,
                              uid=uid,
                              gid=gid)
    with dc:
        # record PID
        go_ahead = True
        try:
            pidFile = open(options.pid, 'x')
        except FileExistsError:
            print("{} JediMaster: ERROR    terminated since pid file {} already exists".format(str(timeNow),
                                                                                options.pid))
            go_ahead = False
        if go_ahead:
            pidFile.write('{0}'.format(os.getpid()))
            pidFile.close()
            # master
            master = JediMaster()

            # set handler
            def catch_sig(sig, frame):
                master.stop()
                time.sleep(3)
                kill_whole(sig, frame)

            signal.signal(signal.SIGINT, catch_sig)
            signal.signal(signal.SIGHUP, catch_sig)
            signal.signal(signal.SIGTERM, catch_sig)
            # start master
            master.start()
<|endoftext|>